Entrada

Bandit: nivel 16 → 17

Cómo resolver el nivel 16 → 17 de OverTheWire Bandit encontrando, entre mil puertos, el único servicio SSL/TLS que devuelve las credenciales, con un bucle en bash y con nmap.

Bandit: nivel 16 → 17

En el nivel anterior sabíamos exactamente a qué puerto hablar. Ahora no: el servicio está en algún puerto entre el 31000 y el 32000, habla SSL/TLS y además hay señuelos. Este nivel es una pequeña introducción a algo que harás en cualquier pentest: descubrir qué puertos están abiertos y qué servicio corre en cada uno.

Las contraseñas y claves 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 bandit16@bandit.labs.overthewire.org -p 2220
bandit16@bandit:~$ export TERM=xterm

El enunciado

El enunciado del nivel dice que la contraseña del siguiente nivel se obtiene enviando la contraseña del nivel actual a un puerto de localhost entre el 31000 y el 32000. Primero hay que averiguar qué puertos tienen un servidor escuchando y, de esos, cuáles hablan SSL/TLS. Solo uno da las credenciales del siguiente nivel; los demás simplemente te devuelven lo que les mandas.

1
2
bandit16@bandit:~$ ls
bandit16@bandit:~$

Home vacío otra vez. Todo pasa en la red.

La solución: un bucle que prueba los 1001 puertos

Ya sabemos del nivel anterior cómo mandar la contraseña a un servicio TLS con ncat --ssl. La diferencia es que ahora no sabemos el puerto, así que lo pruebo en todos con un bucle for de bash:

1
bandit16@bandit:~$ for port in {31000..32000}; do ncat --ssl localhost ${port} < /etc/bandit_pass/bandit16 2>/dev/null; done

Por pantalla aparece, entre otras cosas, una clave privada SSH:

1
[REDACTED: clave privada SSH]

Desmontando el comando pieza a pieza:

  • {31000..32000} es una expansión de llaves de bash: genera todos los números del 31000 al 32000 (1001 valores). El bucle los recorre uno a uno guardando cada número en la variable port.
  • ncat --ssl localhost ${port} intenta abrir una conexión TLS contra ese puerto, igual que en el nivel anterior.
  • < /etc/bandit_pass/bandit16 le pasa la contraseña por la entrada estándar, sin copiar y pegar.
  • 2>/dev/null tira a la basura los errores. Y aquí va a haber muchísimos.

¿Por qué tantos errores? En cada puerto puede pasar una de estas cosas:

Situación del puertoQué hace ncat --ssl
Cerrado (nada escuchando)Falla al conectar (conexión rechazada)
Abierto, sin SSL/TLSConecta por TCP pero el handshake TLS falla
Abierto, con SSL/TLS, señueloTe devuelve lo mismo que le mandas (tu propia contraseña)
Abierto, con SSL/TLS, el buenoTe devuelve las credenciales del nivel 17

Los dos primeros casos generan errores en la salida de errores (stderr), y como la gran mayoría de los 1001 puertos están cerrados, sin 2>/dev/null la pantalla sería un muro de mensajes. Al silenciarlos, solo queda lo que responden los servicios TLS de verdad.

Este bucle funciona, pero tiene dos pegas: tarda (son 1001 intentos de conexión) y no te dice qué puerto ha respondido qué. Verás tu propia contraseña repetida (los señuelos) y la clave, sin saber de dónde viene cada cosa. En la siguiente sección lo mejoramos.

Usar la clave para entrar en bandit17

Lo que devuelve el servicio no es una contraseña, sino una clave privada SSH, como la que ya usamos en el nivel 13 → 14. Me la llevo a mi máquina: copio el bloque completo de la clave (incluidas las líneas -----BEGIN ...----- y -----END ...-----) en un fichero local, por ejemplo bandit17.key.

Antes de usarla, le cambio los permisos:

1
2
$ chmod 600 bandit17.key
$ ssh -i bandit17.key bandit17@bandit.labs.overthewire.org -p 2220

¿Por qué chmod 600? SSH es muy estricto con las claves privadas: si el fichero lo puede leer alguien más que tú, se niega a usarla y te avisa de que la clave está desprotegida. 600 significa lectura y escritura solo para el propietario (rw-------), que es justo lo que pide.

Una vez dentro como bandit17, haz cat /etc/bandit_pass/bandit17 y guárdate la contraseña. Así la próxima vez puedes entrar con sshpass como siempre, sin depender del fichero de la clave.

Otras formas de hacerlo

1. Un bucle que te dice qué puerto responde

Podemos mejorar el bucle para que solo muestre los puertos que devuelven algo distinto de lo que les hemos mandado, es decir, que ignore los señuelos:

1
2
bandit16@bandit:~$ pass=$(cat /etc/bandit_pass/bandit16)
bandit16@bandit:~$ for port in {31000..32000}; do out=$(timeout 3 ncat --ssl localhost $port <<< "$pass" 2>/dev/null); if [ -n "$out" ] && [ "$out" != "$pass" ]; then echo "[+] Puerto $port"; echo "$out"; fi; done

Lo nuevo aquí:

  • pass=$(cat ...) guarda la contraseña en una variable (sustitución de comandos).
  • out=$(...) captura lo que responde cada puerto en otra variable, en vez de soltarlo directamente por pantalla.
  • <<< "$pass" es un here-string: le pasa el contenido de la variable por la entrada estándar.
  • timeout 3 mata el ncat si un puerto se queda colgado más de 3 segundos, para que el bucle no se atasque.
  • [ -n "$out" ] comprueba que la respuesta no está vacía, y [ "$out" != "$pass" ] que no es nuestra propia contraseña de vuelta.

El resultado es una sola línea [+] Puerto ... seguida de la clave. Mucho más limpio.

2. La forma “de pentester”: nmap

En la vida real no probarías puertos uno a uno con un bucle: usarías un escáner de puertos. nmap está instalado en el servidor de Bandit.

Primero, descubrir qué puertos del rango están abiertos:

1
bandit16@bandit:~$ nmap -p 31000-32000 localhost

Esto te devuelve una lista corta de puertos abiertos. Después, le pido a nmap que identifique qué servicio corre en cada uno con -sV (detección de versiones), solo sobre esos puertos:

1
bandit16@bandit:~$ nmap -sV -p <puertos_abiertos> localhost

Separando los puertos por comas (por ejemplo -p 31xxx,31yyy). En la columna SERVICE verás cuáles llevan delante ssl/: esos son los que hablan TLS. Entre ellos, los que nmap identifica como echo son los señuelos (devuelven lo que reciben), y el que queda es tu objetivo. Entonces solo tienes que mandarle la contraseña a ese puerto:

1
bandit16@bandit:~$ ncat --ssl localhost <puerto> < /etc/bandit_pass/bandit16

-sV es más lento porque nmap habla con cada servicio para identificarlo. Por eso primero se hace un escaneo rápido de puertos y luego -sV solo sobre los abiertos. Es exactamente el flujo que usarás en máquinas de HTB o en un pentest real.

3. openssl s_client contra el puerto bueno

Una vez sabes el puerto, también vale la herramienta del nivel anterior. Recuerda el -quiet para evitar el problema de los comandos interactivos (Q, R, k, K) y para que no cierre antes de recibir la respuesta:

1
bandit16@bandit:~$ openssl s_client -connect localhost:<puerto> -quiet < /etc/bandit_pass/bandit16

Pasar al nivel siguiente

Desde bandit16 salgo y entro como bandit17 con la clave desde mi máquina:

1
2
3
bandit16@bandit:~$ exit
$ chmod 600 bandit17.key
$ ssh -i bandit17.key bandit17@bandit.labs.overthewire.org -p 2220

Resumen

Comando / conceptoPara qué sirve
for port in {31000..32000}; do ...; doneRecorrer un rango de puertos con un bucle de bash
{inicio..fin}Expansión de llaves: genera una secuencia de números
2>/dev/nullDescartar los errores (puertos cerrados o sin TLS)
$(comando) / <<< "$var"Capturar la salida en una variable / pasar una variable por stdin
timeout N comandoCortar un comando que tarda más de N segundos
nmap -p 31000-32000 localhostDescubrir qué puertos están abiertos en un rango
nmap -sV -p ...Identificar el servicio de cada puerto (y si usa SSL/TLS)
chmod 600 clavePermisos que SSH exige para una clave privada
ssh -i clave usuario@host -p 2220Entrar con una clave privada en vez de contraseña
Esta entrada está licenciada bajo CC BY 4.0 por el autor.