Entrada

Bandit: nivel 22 → 23

Cómo resolver el nivel 22 → 23 de OverTheWire Bandit leyendo un script de cron que calcula el nombre del fichero con md5sum, y reproduciendo ese cálculo a mano.

Bandit: nivel 22 → 23

Seguimos con cron, pero esta vez el fichero donde cae la contraseña no está a la vista: su nombre lo calcula el propio script. Para resolverlo hay que leer el script, entender cómo genera ese nombre y reproducir el mismo cálculo nosotros a mano. Es un salto importante: pasamos de “leer lo que hay” a “razonar qué va a hacer un programa”.

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 bandit22@bandit.labs.overthewire.org -p 2220
bandit22@bandit:~$ export TERM=xterm

El enunciado

El enunciado del nivel nos avisa de que es parecido al anterior y nos vuelve a mandar a /etc/cron.d/. La configuración repite el patrón:

1
2
3
bandit22@bandit:~$ cat /etc/cron.d/cronjob_bandit23
@reboot bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null
* * * * * bandit23 /usr/bin/cronjob_bandit23.sh  &> /dev/null

Igual que en el nivel 21 → 22: una tarea que corre como bandit23 cada minuto, ejecuta un script y manda toda la salida a /dev/null. La diferencia está en el script.

Leer el script

1
2
3
4
5
6
7
8
9
bandit22@bandit:~$ cat /usr/bin/cronjob_bandit23.sh
#!/bin/bash

myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)

echo "Copying passwordfile /etc/bandit_pass/$myname to /tmp/$mytarget"

cat /etc/bandit_pass/$myname > /tmp/$mytarget

Vamos línea a línea, porque toda la gracia está aquí:

  • myname=$(whoami): guarda en la variable myname el nombre del usuario que ejecuta el script. Como el cron lo lanza como bandit23, aquí myname vale bandit23 (¡no bandit22!).
  • mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1): esta es la clave. Calcula el nombre del fichero destino así:
    • echo I am user $myname produce el texto I am user bandit23.
    • | md5sum calcula el hash MD5 de ese texto. md5sum devuelve el hash seguido de un guion (hash -).
    • | cut -d ' ' -f 1 corta esa salida usando el espacio como separador (-d ' ') y se queda con el primer campo (-f 1), es decir, solo el hash, sin el ` -` del final.
  • cat /etc/bandit_pass/$myname > /tmp/$mytarget: vuelca la contraseña de bandit23 en /tmp/<hash>.

En resumen: la contraseña de bandit23 está en un fichero de /tmp cuyo nombre es el MD5 del texto I am user bandit23. El detalle que engaña: el nombre se calcula con whoami, que es bandit23 cuando lo ejecuta el cron, no el usuario que somos ahora.

Un MD5 es una función de hash: convierte cualquier texto en una cadena de longitud fija, y para la misma entrada da siempre la misma salida. Por eso podemos reproducir el cálculo: si usamos exactamente el mismo texto, obtenemos exactamente el mismo nombre de fichero que generó el script.

La solución: reproducir el cálculo

Calculo yo mismo el hash, usando el nombre del usuario objetivo (bandit23):

1
2
bandit22@bandit:~$ echo I am user bandit23 | md5sum | cut -d ' ' -f 1
8ca319486bfbbc3663ea0fbe81326349

Y ahora leo el fichero de /tmp con ese nombre:

1
2
bandit22@bandit:~$ cat /tmp/8ca319486bfbbc3663ea0fbe81326349
[REDACTED]

Ahí está la contraseña de bandit23.

Cuidado con las comillas y los espacios: el texto tiene que ser exactamente I am user bandit23. Un espacio de más, o poner bandit22 por costumbre, da un hash distinto y, por tanto, un fichero que no existe. El hash es determinista, así que o lo clavas o no sale.

Otra forma: ejecutar el propio script… pero no

La tentación es ejecutar el script directamente para que haga el trabajo. No funciona como esperas: si tú (bandit22) lo ejecutas, whoami devuelve bandit22, intentará leer /etc/bandit_pass/bandit22 (que sí puedes leer, es el tuyo) y lo escribirá en el /tmp correspondiente a bandit22. No te da la contraseña de bandit23. La contraseña de bandit23 solo la puede escribir alguien que sea bandit23, y eso es justo lo que hace el cron por nosotros. Por eso la vía correcta es dejar que el cron haga su trabajo y nosotros recalcular el nombre para leer su resultado.

Pasar al nivel siguiente

1
2
bandit22@bandit:~$ exit
$ sshpass -p '[REDACTED]' ssh bandit23@bandit.labs.overthewire.org -p 2220

El siguiente nivel es el que anticipábamos: un cron que ejecuta un script en un directorio donde tú puedes escribir. Ahí ya no lees, sino que colocas tu propio script para que lo ejecute bandit24.

Resumen

Comando / conceptoPara qué sirve
$(comando)Sustitución de comandos: guardar la salida en una variable
whoamiMostrar el usuario actual (aquí, el que ejecuta el cron)
md5sumCalcular el hash MD5 de una entrada
cut -d ' ' -f 1Quedarse con el primer campo, separando por espacios
Hash deterministaLa misma entrada da siempre el mismo hash: se puede reproducir
cat /etc/bandit_pass/$myname > /tmp/$mytargetVolcar la contraseña en un fichero de nombre calculado
Esta entrada está licenciada bajo CC BY 4.0 por el autor.