WriteUp I'm feeling lucky - PlaidCTF 2011
Abril 25, 2011
Este fin de semana Plaid Parliament of Pwning fueron los anfitriones del plaid CTF, un concurso donde 440 equipos participaron de una serie de retos dirigidos a entusiastas y profesionales de la seguridad informática.
En total eran 38 retos que se debian resolver en 48 horas, las categorías del concurso fueron: Reversing, Web, Crypto, Trivia, Pwnables y QR Code.
Y pues bueno, un torneo grandioso donde los ganadores demostraron sus habilidades, felicitaciones a ellos y a PPP por tan genial y organizado evento!
Ahora sí, la resolución para el problema número 7: I'm feeling lucky.
WriteUp I'm Feeling lucky
Descripción
We found that one of the executives of AED keeps using 'Fortune Cookie' program everyday before he logs in to his *very* important machine.
We extracted the program, and we are certain that there's a key hidden somewhere in the binary.
Reverse engineer and get the key!
Download
http://www.plaidctf.com/chals/43e842e63a795e8f28739a018de547822382e7d3.exe
Resolución
Bueno, este es un breve resumen de lo que hice para obtener la respuesta del reto.
Lo primero que hice fue localizar el código que se ejecutaba al dar clic al botón con Ollydbg, llegando a la instrucción 00412530.
00412530 /$ 68 90000000 PUSH 90 00412535 |. B8 23DA5000 MOV EAX,43e842e6.0050DA23 0041253A |. E8 16550E00 CALL 43e842e6.004F7A55 0041253F |. 8BF9 MOV EDI,ECX 00412541 |. 33C0 XOR EAX,EAX 00412543 |. 8945 F0 MOV [LOCAL.4],EAX 00412546 |. C745 EC FFFFFF7F MOV [LOCAL.5],7FFFFFFF 0041254D |. 8B5D 08 MOV EBX,[ARG.1] 00412550 |. 8945 FC MOV [LOCAL.1],EAX 00412553 |. 81FB 11010000 CMP EBX,111 00412559 |. 75 22 JNZ SHORT 43e842e6.0041257D 0041255B |. FF75 10 PUSH [ARG.3] 0041255E |. 8B07 MOV EAX,DWORD PTR DS:[EDI] 00412560 |. FF75 0C PUSH [ARG.2] 00412563 |. FF90 F4000000 CALL DWORD PTR DS:[EAX+F4]
En la instrucción 00412559 es donde se compara el mensaje enviado con 111 que pertenece a WM_COMMAND (Cuando se presiona el botón).
Luego de numerosas instrucciones el programa llama la función CryptDecrypt pasándole como parámetro general una llave y un texto el cual es luego mostrado como una galleta de la fortuna
Identifiqué todos los llamados (En orden de ejecución) a la biblioteca criptográfica de Microsoft teniendo como resultado el siguiente resumen.
4025F0: CryptAcquireContext |Arg1 = 0012FE40 phProv |Arg2 = 00000000 pszContainer |Arg3 = 00000000 pszProvider |Arg4 = 00000001 dwProvType \Arg5 = F0000000 dwFlags CryptCreateHash |Arg1 = 00188DD0 hProv |Arg2 = 00008003 Algid (CALG_MD5) |Arg3 = 00000000 hKey |Arg4 = 00000000 dwFlags \Arg5 = 0012FE48 phHash 401140: CryptDestroyHash \Arg1 = 00186F70 hHash CryptCreateHash |Arg1 = 00188DD0 hProv |Arg2 = 00008003 Algid (CALG_MD5) |Arg3 = 00000000 hKey |Arg4 = 00000000 dwFlags \Arg5 = 0012FE48 phHash CryptHashData |Arg1 = 00186F70 hHash |Arg2 = 00B7ADD0 pbData (This is the key, but this is not the key you are looking for :p) |Arg3 = 0000003F dwDataLen (63) \Arg4 = 00000000 dwFlags CryptDeriveKey |Arg1 = 00188DD0 hProv |Arg2 = 00006602 Algid (CALG_RC2) |Arg3 = 00186F70 hBaseData |Arg4 = 00000001 dwFlags \Arg5 = 0012FE44 phKey 00412530: CryptDecrypt |Arg1 = 00189368 hKey |Arg2 = 00000000 hHash |Arg3 = 00000001 Final |Arg4 = 00000000 dwFlags |Arg5 = 00B7F570 pbData \Arg6 = 0012F664 pdwDataLen
Luego simulé el funcionamiento y extraje la cadenas cifradas que se localizaban en el offset 140D18 del archivo ejecutable.
Creé un programa en C++ y un script en PHP que leyera archivos binarios e hiciera split (Disculpa a los lectores si la solución es un poco ortodoxa).
#include <stdio.h>
#include <stdlib.h>
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
int main(int argc, char* argv[]) {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;
CryptAcquireContext(&hCryptProv, 0, 0, 1, 0xF0000000);
CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash);
BYTE *pbBuffer = (BYTE *)"This is the key, but this is not the key you are looking for :p";
DWORD dwBufferLen = strlen((char *)pbBuffer);
CryptHashData(hHash, pbBuffer, dwBufferLen, 0);
CryptDeriveKey(hCryptProv, CALG_RC2, hHash, 1, &hKey);
FILE *fp = fopen("filetmp.hex", "rb");
fseek(fp, 0, SEEK_END);
ULONG size = ftell(fp);
unsigned char *buffer = (unsigned char*) calloc(size, sizeof(char));
rewind(fp);
fread(buffer, size, 1, fp);
fclose(fp);
CryptDecrypt(hKey, 0, 1, 0, buffer, &size);
printf("%s\n", buffer);
return 0;
}
Y el script de PHP que ejecutaba el anterior código
$file = file_get_contents('strings.hex'); // Obtain all ciphered strings
$file = str_replace("\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00", $file);
$file = explode("\x00\x00\x00\x00", $file); // Split based on null chars
foreach ($file as $line) { // Loop through all strings
file_put_contents("filetmp.hex", $line); // Save the string in temporal file
system("mission7.exe"); // Call mission7 executable
}
La respuesta se encontraba en una de las últimas galletas de la fortuna
Your character can be described as natural and unrestrained. Your difficulties will strengthen you. Oh YEAH, this is THE k3y U r L0ok1ng FOr Your dreams are worth your best efforts to achieve them. Your energy returns and you get things done.
Respuesta
Oh YEAH, this is THE k3y U r L0ok1ng FOr
Archivado en: Criptografía, Ingeniería Inversa, Programación |
muy pasado!!! genial la resolución. gracias por compartir tanto. (seria bueno seguir con las conferencias de wargames).
Gracias por el solucionario y pulgar arriba para el comentario de Zarek
Thanks man
Como siempre exelente que compartas las soluciones de este tipo de eventos que dificiles si son.
Gracias. y apoyo lo de las conferencias se le extraña en publico.
[...] publico la solucion para el reto I'm feeling lucky. Y por mi parte les publicare la solucion para Division is hard, esto para ayudarle a cierto equipo [...]