Contenido principal

Defcon 18 CTF PreQuals WriteUps (Spanish)

Junio 10, 2010

A continuación algunas de las resoluciones de esta preclasificatoria al evento Defcon 18.
Las resoluciones que podrán encontrar acá son:
Pursuits Trivial: 100, 200, 400
Crypto Badness: 100, 300
Binary L33tness: 100

La lista más completa la pueden encontrar en la colección de resoluciones de vnsecurity

Pursuits Trivial 100
Pregunta
What common linux command was quoted in the popular movie spiderman?

Resolución
Ingresamos a las citas memorables en la base de datos de películas en internet: http://www.imdb.com/title/tt0145487/quotes
Allí podemos encontrar esta cita: "Peter Parker: [voiceover] Whatever life holds in store for me, I will never forget these words: 'With great power comes great responsibility.' This is my gift, my curse. Who am I? I'm Spider-man."

Respuesta
sudo

Pursuits Trivial 200 por Fernando Muñoz
Pregunta
sheep@pwn21.ddtek.biz:6000
sheep go baaAaaA

Resolución
Primero nos conectamos al host pwn21.ddtek.biz en el puerto 6000 con ssh.

Accedemos:
[fernando@abbey ~]$ ssh sheep@pwn21.ddtek.biz con password baaAaaA

Usando gnome-terminal se podia ver un cuadro negro encima de la pantalla que tapaba todo lo que aparecia.
Abrimos entonces una consola que ignore los colores:

[fernando@abbey ~]$ xterm -cm

Nos volvemos a conectar y apenas entramos podemos ver que se abre vim.

Con la opcion de comandos de vim, escribimos el comando para abrir un archivo y presionando TAB vim autocompleta, el primer archivo que aparece es uno llamado key. El cual contiene la llave de este reto.
:e key

Respuesta
SHis4pansies

Pursuits Trivial 400
Pregunta
Rank these hackers

Archivos
t400_49d12929d2eeb6df.jar

Resolución
La idea es rankear a los hackers y hacer el proceso automático, para ver como funciona el programa debemos decompilarlo, al hacerlo, vemos que el algoritmo ejecuta las siguientes instrucciones:
1. Recibe como parámetro el nombre del servidor y se conecta al puerto número 8129.
2. El programa escribe en el socket la cadena de caracteres "illogical" y comienza el juego, el servidor envia unos datos.
3. Los datos enviados siguen el siguiente formato

+-------+---+
|4 bytes| N |
+-------+   |
|           |
|           |
+-------+---+
|4 bytes| M |
+-------+   |
|           |
|           |
+-----------+

4 bytes
N = 4 bytes xor 0xC932F768
Imagen cifrada de N bytes de longitud

4 bytes
M = 4 bytes xor 0xC932F768
Imagen cifrada de M bytes de longitud

Si N es negativo indica algún mensaje de estado listado a continuación:
-1: Better luck next time
-2: Better luck next time
-3: What sequence did you follow to get here? Enter as a string of L/R. (Cuando terminamos de rankear exitosamente, nos pide la secuencia con la que hemos seleccionado los personajes)
-5: Better luck next time
-6: Too slow. Better luck next time
-4: Answer: (Respuesta del servidor) Congratulations

4. Cuando hacemos clic en alguna de las dos imágenes se escribe en el socket 0x00 si elegimos la imagen de la izquierda y 0x01 si elegimos la de la derecha.
5. El servidor responde enviando los datos pertinentes siguiendo el formato anteriormente descrito.

Algoritmo de rankeo
Usando una base de datos podemos organizar el ranking, asignamos un ID para cada imagen, como no conocemos los nombres podemos ponerle de nombre a la imagen el MD5 de sus datos. Cuando tenemos todos las imágenes con un ranking específico, procedemos a enviar los datos al servidor según ese ranking, cuando fallamos, intercambiamos sus IDs.
Con el algoritmo se cumple transitividad y no tendriamos que calcular todas las combinaciones:
Si el personaje c1 le ganó al personaje 2, y si el personaje c2 le ganó al personaje 3, entonces el personaje 1 le gana al c3.
Tendríamos en este caso un ranking ordenado de la siguiente forma:

Puesto  Personaje
1       c1
2       c2
3       c3

Recursos
RankMe.phps - Script que implementa el algoritmo de rankeo.
RankMe.java - RankMe.class decompilado.
pursuit.db - Base de datos que contiene el ranking y su respectiva imagen
t400.gz - Código original del servidor e imágenes

Respuesta
None hold a candle to Bessie the sh33p!

Crypto Badness 100
Pregunta
Decrypt please

Ocmln. up.'g.bjf abanfoco odrgne er yd. ypcjt d.p. /,.nnw urp yd. mroy lapy=v
Ydco y.qy ,ao ,pcyy.b gocbi a ol.jcan t.fxrapew br bry .pirbrmcjw frg aoodayv
WdcbyV Yd. t.f frg ap. nrrtcbi urp co yd. bam.oat. ru ydco t.fxrapev WzdcbyV

Resolución
Se trata de un cifrado de sustitución simple (Cada letra es reemplazada por una única letra del alfabeto), en este caso la sustitución se convierte en un mensaje escrito en un teclado qwerty usando un layout dvorak.

El texto original es:
Simple frequency analysis should do the trick here [well, for the most part].
This text was written using a special keyboard, no not ergonomic, you asshat.
The key you are looking for is the namesake of this keyboard.

Recursos
http://wbic16.xedoloh.com/dvorak.html

Respueta
dvorak

Crypto Badness 300
Pregunta
Would you link to play a game

Archivos
c300_f75bec6f545034716.tgz

Resolución
Abrimos la hoja de excel y observamos que el libro está protegido con contraseña
CB300_1

Igualmente sus macros
CB300_2

Usando algún programa de análisis para la hoja de excel descubrimos que la contraseña para la hoja Asteroids es: 6b1b7b3b3b1b5
Podemos modificar fácilmente la contraseña para los macros, abrimos el archivo con un editor hexadecimal y ubicamos la cadena "DPB"
CB300_3

Luego reemplazamos esa línea (DPB="...") por

DPB="9A9836099E269E2661DA9F2671AB22488C08DD6637A65D15DD073663CE1BDFA091A4F09F0D"

y así cambiamos la contraseña del macro desconocida por la contraseña "1234".

Abrimos el libro, y luego abrimos el código que ejecuta ese macro (Macro.vb)

En el código vemos que se llama a la función "X" la cual se encarga de descifrar las cadenas que allí encontramos, tal función usa como clave una variable llamada CK

CK = Worksheets("Data").Range("AU2") & Worksheets("Data").Range("BE4866") & _
Worksheets("Data").Range("Z9550")

Esa misma variable es nuestra contraseña para validar el reto, ponemos un breakpoint allí, ejecutamos el macro y luego de tal instrucción en la ventana inmediato copiamos el código para obtener esa variable
CB300_4

Respuesta
a23sd21AeB349sdfWewrfw29552

Binary L33tness 100
Pregunta
Find the key

Archivos
b100_4c5cd364e89fd34.bin

Resolución
Obtenemos el pseudo código fuente con hex-rays y vemos el siguiente código

int __cdecl sub_80485B4(int a1, int a2)
{
unsigned int v3; // eax@4
char v4; // [sp+1Eh] [bp-102h]@4
//Si el número de argumentos pasados al programa son diferentes de 2 entonces nos muestra el mensaje y sale
if ( a1 != 2 )
{
fwrite("Please supply a key", 1u, 0x13u, stderr);
exit(1);
}
++dword_8049ECC;
fwrite("I hope you got it! Good luck\n", 1u, 0x1Du, stderr);
v3 = strlen(*(const char **)(a2 + 4));
//Llama a la función sub_8048698 pasándole como parámetro el valor que ingresamos por el argumento del programa y su longitud
sub_8048698(&v4, *(_DWORD *)(a2 + 4), v3);
//Llama a la función sub_804886A pasándole como parámetro un valor calculado de la anterior función, una cadena, y el número 34
sub_804886A((int)&v4, (int)"†šM.+QÀÚ", 34);
fprintf(stderr, "%s\n", "†šM.+QÀÚ");
return 0;
}


//----- (08048698) --------------------------------------------------------
void *__cdecl sub_8048698(void *s, int a2, unsigned int a3)
{
void *result; // eax@1
char v4; // ST1F_1@6
unsigned int i; // [sp+18h] [bp-10h]@2
unsigned int j; // [sp+18h] [bp-10h]@5
*((_BYTE *)s + 257) = 0;
*((_BYTE *)s + 256) = 0;
result = memset(s, 0, 0x100u);
if ( a3 )
{
for ( i = 0; i <= 0xFF; ++i )
*((_BYTE *)s + i) = i;
for ( j = 0; j <= 0xFF; ++j )
{
*((_BYTE *)s + 257) += *((_BYTE *)s + j) + *(_BYTE *)(a2 + j % a3);
v4 = *((_BYTE *)s + *((_BYTE *)s + 257));
*((_BYTE *)s + *((_BYTE *)s + 257)) = *((_BYTE *)s + j);
*((_BYTE *)s + j) = v4;
}
result = s;
*((_BYTE *)s + 257) = 0;
}
return result;
}
//----- (080487AA) --------------------------------------------------------
int __cdecl sub_80487AA(int a1)
{
char v2; // ST0F_1@1
++*(_BYTE *)(a1 + 256);
*(_BYTE *)(a1 + 257) += *(_BYTE *)(a1 + *(_BYTE *)(a1 + 256));
v2 = *(_BYTE *)(a1 + *(_BYTE *)(a1 + 257));
*(_BYTE *)(a1 + *(_BYTE *)(a1 + 257)) = *(_BYTE *)(a1 + *(_BYTE *)(a1 + 256));
*(_BYTE *)(a1 + *(_BYTE *)(a1 + 256)) = v2;
return *(_BYTE *)(a1 + (unsigned __int8)(*(_BYTE *)(a1 + *(_BYTE *)(a1 + 257)) + v2));
}

Las dos funciones anteriores son las usadas por el programa, y coinciden con el algoritmo del cifrado de flujos RC4

for i from 0 to 255
S[i] := i
endfor
j := 0
for i from 0 to 255
j := (j + S[i] + key[i mod keylength]) mod 256
swap(&S[i],&S[j])
endfor
i := 0
j := 0
while GeneratingOutput:
i := (i + 1) mod 256
j := (j + S[i]) mod 256
swap(&S[i],&S[j])
byte_cipher := S[(S[i] + S[j]) mod 256]
// (byte_cipher is referred to as "K" in the above figure)
result_ciphered := byte_cipher XOR byte_message
endwhile

Lo que hice en un principio fue obtener la cadena que quería descifrar y hacer un script que realizara fuerza bruta con el algoritmo para encontrar la supuesta contraseña.
El algoritmo sigue este proceso:
1. Abre el diccionario descargado de packetstormsecurity, que contiene 815 palabras comunes para el uso de contraseñas.
2. Por cada palabra se aplica el algoritmo de RC4.
3. Se analiza la salida usando el algoritmo de entropia para encontrar cadenas de caracteres que posiblemente sean texto.

El resultado con el script fue el siguiente

bailey _ òpe>32E !ˆ8E@Qt`!u'ÛH#ùϬLòÌ9Ý
disc _ \º·sÍfPûåBŠ,å"ÏN(5ö~VDZ.-8§A8ÜF
ingress _ h4­¥)˜pç&E1Å#0j5Æj¯j‹ÝQ!²3…B`Lüñs
ness _ ,Ý´r!3Õ,;HuàAU(‹kåirl8dP_1Ht7q
oxford _ DFB{sÛÔ—‰Ó–-ôLÃ<¸^*C:-ì57Y~uãhF/
password _ you gotta know where the code goes
trombone _ ]5Qsn8¤¬Ò¾4æbê”j]©k1ÄTþm-D¯ðed´_3t

Intentamos varias veces colocar por contraseña "password" y "you gotta know where the code goes", pero no funcionó. Cuando nos reunimos en el chat me mostraron una parte del código por la cual había pasado desapercibido.

result = dword_8049ECC;
if ( dword_8049ECC )
{
if ( v9 )
{
v3 = 1969448307;
v4 = 114;
v5 = 101;
v6 = 107;
v7 = 101;
v8 = 121;
sub_8048698(&s, (int)&v3, 9u);
sub_804886A((int)&s, (int)&unk_8049E84, 30);
result = fprintf(stderr, "%s\n", &unk_8049E84);
}
}

Ese mismo código llama a las dos funciones, pero en este caso usando una contraseña específica y no ingresada por el argumento del programa.
v4, v5, v6, v7, y v8 son de tipo char, forman entonces la cadena rekey
Mientras que v3 por ser de tipo int no muestra una cadena "normal", el tipo int es de 4 bytes, así que podemos sacar la cadena de esta forma:
1. Convertimos el entero a hexadecimal = 1969448307 en decimal es 75636573 en hexadecimal.
2. Separamos esa cadena hexadecimal con espacios cada dos carácteres = 75636573 a 75 63 65 73
3. Convertimos cada par a decimal = 75 63 65 73 a 117 99 101 115
4. El resultado obtenido en la anterior operación es ASCII, queda: "uces"
5. No olvidemos el little endian = "secu"
Al final la clave que usaron para descifrar el texto que aún no conocemos es "securekey".

El texto a descifrar se encuentra inmediatamente después del primero (\x5E\xA7\x71\x54).

Recursos
http://packetstormsecurity.org/Crackers/wordlists/
Script que realizó fuerza bruta sobre el algoritmo (Necesita el wordlist llamado common-2 que se encuentra en el anterior recurso).

Respuesta
bob's yer mom

Archivado en: Criptografía, Ingeniería Inversa, Programación, Retos informáticos |

13 comentarios

  1. hecky Junio 10, 2010 @ 10:57 pm

    WoW, que buena info maestro!!! Como siempre, me deja con el ojo cuadrado :D

  2. kagure Junio 11, 2010 @ 12:21 pm

    Si la verdad muy buenos habia visto algunas soluciones en securytybydefault y en pentester.es siempre es bueno poder leer articulos como estos.

  3. Checho Junio 15, 2010 @ 4:03 pm

    mmm interesante definitivamente cada vez q veo algo bueno me doy cuenta q no se ni mierda xD jajaj =P

  4. Saurom Junio 16, 2010 @ 1:55 pm

    Muy buena entrada!!

    El nivel de dificultad en las pruebas creo que sube año a año.

    Gran explicacion de la solucion del Binary L33tness 100. Supongo que ya verias lo que se liaron otras personas para pasar este (http://maybe-successful.blogspot.com/2010/05/defcon18-ctf-quals-binary-l33tness-100.html) xD xD Lo que hace tener una idea feliz!!

  5. Sysroot Junio 16, 2010 @ 3:20 pm

    Este año se incrementó la dificulta, es cierto, pero lo raro fue que duplicamos el puntaje, teniamos otras dos respuestas sin ingresar y otras dos pruebas hechas a medias, teóricamente triplicamos el puntaje, el resultado fue mejor de lo esperado, ya sabes que el próximo año te esperamos Saurom para que nos des una mano, y si alguién mas se quiere unir pues bienvenido!

  6. p3ll3 Junio 18, 2010 @ 3:53 pm

    Excelente informacion!!!
    Saludos a todos 8)

  7. kagure Julio 1, 2010 @ 8:02 pm

    YO me le pego al team jajaja de una como es que se llama el team?? cuantos son ? muy bueno

  8. Sysroot Julio 14, 2010 @ 2:17 am

    Que pena contigo Kagure, el team se llama *NULL Labs, y somos hasta el momento cinco. Péguese para que aprenda!

  9. Segundo aniversario Sinfocol | Seguridad Informática Colombiana Agosto 8, 2010 @ 8:55 pm

    [...] #Comentarios: 7 Sitio web dedicado a la ingeniería informática y de sistemas #Comentarios: 0 Defcon 18 CTF PreQuals WriteUps (En español) #Comentarios: 8 smpChallenge1 - smpCTF 2010 (Español) #Comentarios: 1 smpChallenge2 - smpCTF [...]

  10. maybe-failed Diciembre 5, 2010 @ 1:48 am

    uhmm... yo el binary-l33tness-100 lo complete pasandole una clave nula:

    ./b100_4c5cd364e89fd34.bin ''

    y de una :)

  11. Sysroot Diciembre 13, 2010 @ 6:10 pm

    Excelente solución, yo me complique mucho más para el reto sabiendo que podía ser algo sencillo.

  12. Danilo Diciembre 20, 2010 @ 7:51 pm

    Que tal hermano... para el post de Crypto Badness 300...que programa usas para analizar el archivo de excel??? me pase por el Dios Google pero no pude encontrar nada o no supe realizar la busqueda...te lo agradezco.. saludos.

  13. Sysroot Diciembre 21, 2010 @ 1:16 am

    En ese caso fue un programa de Elcomsoft llamado Advanced Office Password Recovery: http://www.elcomsoft.com/aopr.html.
    Buscando con "Excel password recovery" puedes encontrar otros programas y que aparte son gratuitos.

Deja un comentario