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.
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 variableport.ncat --ssl localhost ${port}intenta abrir una conexión TLS contra ese puerto, igual que en el nivel anterior.< /etc/bandit_pass/bandit16le pasa la contraseña por la entrada estándar, sin copiar y pegar.2>/dev/nulltira 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 puerto | Qué hace ncat --ssl |
|---|---|
| Cerrado (nada escuchando) | Falla al conectar (conexión rechazada) |
| Abierto, sin SSL/TLS | Conecta por TCP pero el handshake TLS falla |
| Abierto, con SSL/TLS, señuelo | Te devuelve lo mismo que le mandas (tu propia contraseña) |
| Abierto, con SSL/TLS, el bueno | Te 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, hazcat /etc/bandit_pass/bandit17y guárdate la contraseña. Así la próxima vez puedes entrar consshpasscomo 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 3mata elncatsi 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
-sVes más lento porquenmaphabla con cada servicio para identificarlo. Por eso primero se hace un escaneo rápido de puertos y luego-sVsolo 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 / concepto | Para qué sirve |
|---|---|
for port in {31000..32000}; do ...; done | Recorrer un rango de puertos con un bucle de bash |
{inicio..fin} | Expansión de llaves: genera una secuencia de números |
2>/dev/null | Descartar los errores (puertos cerrados o sin TLS) |
$(comando) / <<< "$var" | Capturar la salida en una variable / pasar una variable por stdin |
timeout N comando | Cortar un comando que tarda más de N segundos |
nmap -p 31000-32000 localhost | Descubrir qué puertos están abiertos en un rango |
nmap -sV -p ... | Identificar el servicio de cada puerto (y si usa SSL/TLS) |
chmod 600 clave | Permisos que SSH exige para una clave privada |
ssh -i clave usuario@host -p 2220 | Entrar con una clave privada en vez de contraseña |