miércoles, 26 de mayo de 2010

Writeup PKT100 DefCon CTF 2010 Quals

Este es el reto 100 de paquetes de red, en esta categoría generalmente se entrega un archivo .pcap que hay que analizar. En este caso el paquete de muestra tenia paquetes ping entre dos maquinas y como ayuda teniamos la pista: sumthing is not like other...

Este reto fué de nivel 100, pero creo que hizo llorar a mas de uno. Como siempre una vez visto el resultado todo parece tan fácil ;)

Lo primero que observamos es que el archivo viene comprimido con lzma:

>$file pkt100_6b233464726cfa8fa.pcap.lzma
pkt100_6b233464726cfa8fa.pcap.lzma: data
>$

lo descomprimimos entonces:

>$lzma -d pkt100_6b233464726cfa8fa.pcap.lzma
>$file pkt100_6b233464726cfa8fa.pcap
pkt100_6b233464726cfa8fa.pcap: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)
>$

Lo cargamos en el wireshark y tratamos de entender de que se trata el asunto.


La pista nos daba a entender que algo en el paquete no era como los otros y al mezclar la palabra something con la palabra sum (de summary quizas), entendiamos que se trataba de algo en suma o resumen que no era como los demas ...

En este punto y para no hacer muy larga la historia (y el sufrimiento XD) podemos decir que se intentaron cosas como:
  • Verificar cada checksum de los paquetes tratando de encontrar incongruencias
  • Verificar posibles datos que identificaramos dentro del campo data de los paquetes icmp
  • Uno de los paquetes era diferente en bytes al resto, tenia 129 bytes, mientras el resto tenia 256, probamos todas las posibles claves relacionadas con ese paquete, se trata del primero, asi que probamos con uno, first, first packet, 1 frame, frame 1, frame 1 packet, etc.
  • También probamos con los nombres de cada campo del header IP e ICMP, pero tampoco dió resultado.
Algo que nunca vimos y que por ahí estaba el truco era que cada DATA del paquete ICMP era diferente, generalmente los PINGS son homogeneos tanto en la pregunta (ICMP tipo 8), como en la respuesta (ICMP tipo 0).

Como se soluciona el ejercicio?

Podemos hacer un pequeño script usando la libreria scapy:

>$cat sacadata.py
#!/usr/bin/env python
#Extrae la data de los paquetes ICMP que encuentre en
#el archivo .pcap, sys.argv[1] == paquete.pcap de entrada
import sys
from scapy.all import *
a=rdpcap(sys.argv[1])
for data in a:
print data.load
>$

Este script extraerá todos los campos DATA de los paquetes ICMP que se encuentre en el archivo .pcap. La salida de este script la podemos redireccionar a un archivo.

>$python sacadata.py pkt100_6b233464726cfa8fa.pcap > salida
>$tail -2 salida
��ighRSYgV�SXU��Rhf�XXRWf��dfVX�OdXTWdWWgPg�TgYP��iYXPhP���XgTXS4ffhSh�VS�ghj�4RO�TR�iTPWTdfUYShji�h�fVUXXg�Xd�XP�X�VYYfXUf�fdRh�X�gTfX�S�PTgd�4�YRghg�S�TdhS�iWRggTg�h�dOPOf���Ud�dR���jTOSUj�����jf�SO�Ud
UW�PVjOV�U�4�h��d�SUUUVYY�jV�YRSfRjPg�hi��S�ff�fPP�PS�fd�PgiVj��WVYgRY�Y�XRTUS�ijTRYW�jUdT4SRVfVRg�TgYV�WfgU�j��SP�OdT���W����Vf�i�RRXidUUYhWhVW�Uigj�iRPX�4��VUTgOSd�VS�SdRdgR�gSSURV�hj��PTi���S�OX��Sf�S
...

Al leer el archivo resultante nos damos cuenta que hay caracteres no imprimibles, y el comando file nos reporta lo siguiente:

>$file salida
salida: Non-ISO extended-ASCII text, with CRLF, CR, NEL line terminators
>$

Que hacemos entonces?, podemos pensar que el texto esta codificado y que seguramente existirá algo que lo decodifique. En este punto un pájaro cruza la ventana del HackLab y se posa en mi hombro y me twittea al oido lo siguiente:

yydecode, yydecode, yydecode ...


En un principio pense que eran cosas sin sentido, cosas de pajaros, pues que mas le puede decir a uno un pajaro a travez de su pico?

Pero despues me di cuenta que existe otra cosa diferente a base64 para hacer este tipo de codificación y que efectivamente yydecode y yencode son cosas que existen en este mundo.

Con esta pista clara, procedemos a decodificar el texto:

>$yydecode salida
yydecode: salida: No `=ybegin' or `begin' line found
>$

Supongo que yydecode requiere algo estandar para funcionar, así que descargo el yencode y lo uso a modo de prueba:

>$cat prueba.txt
esto es una prueba.
>$yencode prueba.txt
prueba.txt: prueba.txt.ync (1/1): file OK: (470.0%)
>$

El resultado queda en el archivo prueba.txt.ync

>$cat prueba.txt.ync
=ybegin line=128 size=20 name=prueba.txt
�J���J���X4
=yend size=20 crc32=087F0ABC
>$

De esta forma me doy cuenta como espera el yydecode que le pasemos el archivo, lo que hago es usar el archivo de salida del .pcap y agregarle las cabezeras del archivo de prueba. Al intentar decodificar el archivo, me dice que el original existe, entonces lo borro.

>$yydecode salida
yydecode: salida: prueba.txt: File exists
>$

Intento de nuevo.

>$yydecode salida
yydecode: salida: prueba.txt:1: Part longer than expected
yydecode: prueba.txt:1: Part broken (of 1 parts)
yydecode: prueba.txt: wrote 0 bytes; should have been 0
yydecode: prueba.txt: renamed to prueba.txt.broken
>$

Lo que me suponia, se requiere una longitud correcta y un CRC32 válido para el archivo para que el yydecode haga su trabajo.

=ybegin line=128 size=5000 name=prueba.txt

Edito el tamaño (variable size) a 5000 y pruebo nuevamente.

No funciona, que hago?, abro el editor nano y le doy CTRL + C para que me informe cuantos caracteres tiene el archivo:

[ line 66/67 (98%), col 128/128 (100%), char 8449/8450 (99%) ]

Pruebo cambiando el dato de los caracteres a 8450.

Ahora que el tamaño es correcto o por lo menos parece, yydecode arroja un error diferente:

>$yydecode salida
yydecode: salida: prueba.txt:1: Part CRC32 error -- got 0x6796de83, should be 0x087f0abc
yydecode: prueba.txt:1: Part broken (of 1 parts)
yydecode: prueba.txt: wrote 0 bytes; should have been
yydecode: prueba.txt: renamed to prueba.txt.broken
>$

Esto me indica que el CRC32 esta malo (obviamente) pero me hace el favor de recalcular uno correcto. Así que tomo el valor 0x6796de83 y edito el archivo.

=yend size=8450 crc32=0x6796de83

Pruebo nuevamente ...

>$yydecode salida
yydecode: salida: prueba.txt:1: warning: Wrong part size -- decoded 8384 bytes, expected 8450
yydecode: prueba.txt: wrote 8384 bytes; should have been 0
yydecode: prueba.txt: renamed to prueba.txt.broken
>$

Sigue generando errores pero me informa que gran parte del archivo fue decodificado (decoded 8384 bytes).

La salida la obtenemos en: prueba.txt.broken

>$tail prueba.txt.broken
+&?)^=>][+,+,]}.(}]?-?]--.@(%<|>*|%){^|=]}],&&|(-,*^<[/:+[{:{:/, @]@<{[{:-{:<)~,@=%-=~&>{,&(~.~&=|}&?(,&)=@&/^?<&-|{.)-(,:%[]<~<& :{.-,-[]:*>|*)/.=}>*~>%~)*]]-|//~|.^[},&]]<))%/=+..>?+&]<(%]|)-, *|&}@./*.&<<@-|%[[.%::{*{+~)&][.<{(]&::[,*&,)|>]),?}=*.^/+:?^)&[
]).%/(,>}=(>.@[~&{-+>}][=]}{-%=]/(^.+/(+(-<{:<,<+(+?>&&=,&-[-]|%
)>>)|/^-/,>+<*|>&|>@@^/?%^,*]={~~%>~&^},&)|>(<%&[=*|:%%?)~[(]@({ ~*+/&**=}:([*-{({+/=,|,:=?~&^,{^(~}))(/:(/{{@)&-}%,]@)>%))[^*=,]
~@,{|=]/+)>]=^&~%&%@[>=](}.?(=.}%~,](--.[.%~*-|)]->.]=-:??^&[<{[ ^)(]^&-*[//=+}]%{.)->%[?@(%>=^})|-^*{~|->&/*,?[[-&-=}-]:,%]&*(~[
...

Efectivamente el archivo esta decodificado y entonces?, cual es la clave?
Lo que hacemos es examinar todo el archivo y en algun lugar perdido encontramos un md5.


Para romper el md5 visitamos los sitios de siempre (google, bing, md5crack, passcracking). Recuerden siempre intentar encontrar bases de datos donde ya esten crackeados los MD5 que buscan antes de sacar sus propias tablas arcoiris, para los interesados les puedo enviar las del grupo por correo, solo pesan 150GB ;)

Finalmente usamos esta respuesta en la scoreboard del juego y ... nos damos cuenta que el juego ya se acabó y que estos 100 puntos se perdieron ;)

Como ven, era solo cuestión de entender un poco mas a fondo la estructura ICMP y pensar en que la DATA va encodeada, fácil, muy fácil XD.

Entradas populares