Introducción
Decompilado
Abrimos la víctima con nuestro decompilador favorito y nos fijamos en su contenido.
Abrimos la víctima con nuestro decompilador favorito y nos fijamos en su contenido.
Recién rescatados del inframundo que es mi disco duro, os traigo un paquete de seis crackmes facilones para vuestro uso y disfrute. Desgraciadamente ya no está en activo la web de retos de donde los saqué así que os los dejo en descargas.
Los cuatro primero están realizados en Dev-C++ 4.9.9.2 siendo de estilo consola de comandos. Los dos restantes compilados con MingWin32 GCC 3.x carecen de GUI y vamos, que no se han esmerado mucho en darles forma.
No cuesta mucho dar con el código interesante mediante las referencias de texto. En Ollydbg clic derecho sobre el código y Search for > All referenced text strings.
004012E1 |. 8845 E8 MOV BYTE PTR SS:[EBP-18],AL ; |||| 004012E4 |. C70424 11304000 MOV DWORD PTR SS:[ESP],level1.00403011 ; ||||ASCII "Input Serial: " 004012EB |. E8 C0050000 CALL <JMP.&msvcrt.printf> ; |||\printf 004012F0 |. 8D45 C8 LEA EAX,[LOCAL.14] ; ||| 004012F3 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; ||| 004012F7 |. C70424 20304000 MOV DWORD PTR SS:[ESP],level1.00403020 ; |||ASCII "%s" 004012FE |. E8 9D050000 CALL <JMP.&msvcrt.scanf> ; ||\scanf 00401303 |. 8D45 D8 LEA EAX,[LOCAL.10] ; || 00401306 |. 8D55 C8 LEA EDX,[LOCAL.14] ; || 00401309 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; || 0040130D |. 891424 MOV DWORD PTR SS:[ESP],EDX ; ||level1.00403022 00401310 |. E8 7B050000 CALL <JMP.&msvcrt.strcmp> ; |\strcmp 00401315 |. 8945 C4 MOV [LOCAL.15],EAX ; | 00401318 |. 837D C4 00 CMP [LOCAL.15],0 ; | 0040131C |. 75 0E JNZ SHORT level1.0040132C ; | 0040131E |. C70424 23304000 MOV DWORD PTR SS:[ESP],level1.00403023 ; |ASCII "Well done. \n" 00401325 |. E8 86050000 CALL <JMP.&msvcrt.printf> ; \printf 0040132A |. EB 0C JMP SHORT level1.00401338 0040132C |> C70424 30304000 MOV DWORD PTR SS:[ESP],level1.00403030 ; |ASCII "Wrong. \n" 00401333 |. E8 78050000 CALL <JMP.&msvcrt.printf> ; \printf 00401338 |> C70424 39304000 MOV DWORD PTR SS:[ESP],level1.00403039 ; |ASCII "PAUSE" 0040133F |. E8 3C050000 CALL <JMP.&msvcrt.system> ; \system 00401344 |. B8 00000000 MOV EAX,0 00401349 |. C9 LEAVE 0040134A \. C3 RETN
La madre del cordero está en la dirección 401310 que es donde se lleva a cabo la función de comparación strcmp.
756296A0 msvcrt.strcmp 8B5424 04 MOV EDX,DWORD PTR SS:[ESP+4] 756296A4 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8] 756296A8 F7C2 03000000 TEST EDX,3 ; 0-3 = 4 bucles. Divide la comprobación en 4 bloques 756296AE 75 3C JNZ SHORT msvcrt.756296EC ; salta si hemos terminado los 4 bucles 756296B0 > 8B02 MOV EAX,DWORD PTR DS:[EDX] ; coge 4 caracteres del serial (INICIO BUCLE) 756296B2 3A01 CMP AL,BYTE PTR DS:[ECX] ; compara el 1º/5º/9º/13º dígito en función del bucle 756296B4 75 2E JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296B6 0AC0 OR AL,AL 756296B8 74 26 JE SHORT msvcrt.756296E0 756296BA 3A61 01 CMP AH,BYTE PTR DS:[ECX+1] ; compara el 2º/6º/10º/14º dígito en función del bucle 756296BD 75 25 JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296BF 0AE4 OR AH,AH 756296C1 74 1D JE SHORT msvcrt.756296E0 756296C3 C1E8 10 SHR EAX,10 756296C6 3A41 02 CMP AL,BYTE PTR DS:[ECX+2] ; compara el 3º/7º/11º/15º dígito en función del bucle 756296C9 75 19 JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296CB 0AC0 OR AL,AL 756296CD 74 11 JE SHORT msvcrt.756296E0 756296CF 3A61 03 CMP AH,BYTE PTR DS:[ECX+3] ; compara el 4º/8º/12º/16º dígito en función del bucle 756296D2 75 10 JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296D4 83C1 04 ADD ECX,4 756296D7 83C2 04 ADD EDX,4 756296DA 0AE4 OR AH,AH 756296DC ^ 75 D2 JNZ SHORT msvcrt.756296B0 ; Si no hemos terminado... 756296DE 8BFF MOV EDI,EDI 756296E0 33C0 XOR EAX,EAX ; EAX = 0 que es lo deseado 756296E2 C3 RETN ; salimos de la función superando la comprobación 756296E3 90 NOP 756296E4 1BC0 SBB EAX,EAX ; Zona mala 756296E6 D1E0 SHL EAX,1 756296E8 83C0 01 ADD EAX,1 ; EAX = 1 implica bad boy 756296EB C3 RETN ; salimos de la función
Si atendemos al volcado vemos el serial bueno Kcgcv8LsmV3nizfJ.
0060FEF0 31 32 33 34 35 36 37 38 39 30 00 75 40 19 18 00 1234567890.u@. 0060FF00 4B 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A Kcgcv8LsmV3nizfJ
Curiosamente, si introducimos el serial bueno el crackme no lo acepta. Fijándome en la comprobación veo que al introducir un serial de 16 caracteres inserta un carácter nulo (0x00) alterando el serial correcto y falseando la comprobación.
0060FEF0 4B 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A Kcgcv8LsmV3nizfJ 0060FF00 00 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A .cgcv8LsmV3nizfJ
Ahora ya no podemos comprobarlo pero recuerdo que la web consideraba válido el serial Kcgcv8LsmV3nizfJ, por lo que considero lo anteriormente citado un bug o un intento de despiste del autor.
Es exactamente igual que el anterior cambiando el serial por 6LPw3vDYja9KrT2V.
La comprobación del serial es igual a las dos anteriores pero añade una función intermedia que suma 0xD a cada carácter de nuestro serial
00401355 |. A1 03304000 MOV EAX,DWORD PTR DS:[403003] ; || 0040135A |. 8945 E8 MOV [LOCAL.6],EAX ; || 0040135D |. A1 07304000 MOV EAX,DWORD PTR DS:[403007] ; || 00401362 |. 8945 EC MOV [LOCAL.5],EAX ; || 00401365 |. A1 0B304000 MOV EAX,DWORD PTR DS:[40300B] ; || 0040136A |. 8945 F0 MOV [LOCAL.4],EAX ; || 0040136D |. A1 0F304000 MOV EAX,DWORD PTR DS:[40300F] ; || 00401372 |. 8945 F4 MOV [LOCAL.3],EAX ; || 00401375 |. C70424 13304000 MOV DWORD PTR SS:[ESP],level3.00403013 ; ||ASCII "Input Serial: " 0040137C |. E8 CF050000 CALL <JMP.&msvcrt.printf> ; |\printf 00401381 |. 8D45 D8 LEA EAX,[LOCAL.10] ; | 00401384 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; | 00401388 |. C70424 00304000 MOV DWORD PTR SS:[ESP],level3.00403000 ; |ASCII "%s" 0040138F |. E8 AC050000 CALL <JMP.&msvcrt.scanf> ; \scanf 00401394 |. 8D5D E8 LEA EBX,[LOCAL.6] 00401397 |. 8D45 D8 LEA EAX,[LOCAL.10] 0040139A |. 890424 MOV DWORD PTR SS:[ESP],EAX 0040139D |. E8 EEFEFFFF CALL level3.00401290 ; NUEVA FUNCIÓN SUMA 004013A2 |. 895C24 04 MOV DWORD PTR SS:[ESP+4],EBX ; || 004013A6 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; || 004013A9 |. E8 82050000 CALL <JMP.&msvcrt.strcmp> ; |\strcmp 004013AE |. 8945 D4 MOV [LOCAL.11],EAX ; | 004013B1 |. 837D D4 00 CMP [LOCAL.11],0 ; | 004013B5 |. 75 0E JNZ SHORT level3.004013C5 ; | 004013B7 |. C70424 22304000 MOV DWORD PTR SS:[ESP],level3.00403022 ; |ASCII "Well done." 004013BE |. E8 8D050000 CALL <JMP.&msvcrt.printf> ; \printf 004013C3 |. EB 0C JMP SHORT level3.004013D1 004013C5 |> C70424 2D304000 MOV DWORD PTR SS:[ESP],level3.0040302D ; |ASCII "Wrong. \n" 004013CC |. E8 7F050000 CALL <JMP.&msvcrt.printf> ; \printf 004013D1 |> C70424 36304000 MOV DWORD PTR SS:[ESP],level3.00403036 ; |ASCII "PAUSE" 004013D8 |. E8 43050000 CALL <JMP.&msvcrt.system> ; \system 004013DD |. B8 00000000 MOV EAX,0 004013E2 |. 8B5D FC MOV EBX,[LOCAL.1] 004013E5 |. C9 LEAVE 004013E6 \. C3 RETN -------- 004012A4 |> /8B45 08 /MOV EAX,[ARG.1] ; | 004012A7 |. |890424 |MOV DWORD PTR SS:[ESP],EAX ; | 004012AA |. |E8 B1060000 |CALL <JMP.&msvcrt.strlen> ; \strlen 004012AF |. |3945 FC |CMP [LOCAL.1],EAX 004012B2 |. |73 1C |JNB SHORT level3.004012D0 004012B4 |. |8B45 08 |MOV EAX,[ARG.1] 004012B7 |. |8B55 FC |MOV EDX,[LOCAL.1] 004012BA |. |01C2 |ADD EDX,EAX 004012BC |. |8B45 08 |MOV EAX,[ARG.1] 004012BF |. |0345 FC |ADD EAX,[LOCAL.1] 004012C2 |. |0FB600 |MOVZX EAX,BYTE PTR DS:[EAX] 004012C5 |. |04 0D |ADD AL,0D ; char + 0xD 004012C7 |. |8802 |MOV BYTE PTR DS:[EDX],AL 004012C9 |. |8D45 FC |LEA EAX,[LOCAL.1] 004012CC |. |FF00 |INC DWORD PTR DS:[EAX] 004012CE |.^\EB D4 \JMP SHORT level3.004012A4 -------- 756296A0 msvcrt.strcmp 8B5424 04 MOV EDX,DWORD PTR SS:[ESP+4] 756296A4 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8] 756296A8 F7C2 03000000 TEST EDX,3 756296AE 75 3C JNZ SHORT msvcrt.756296EC 756296B0 8B02 MOV EAX,DWORD PTR DS:[EDX] 756296B2 3A01 CMP AL,BYTE PTR DS:[ECX] 756296B4 75 2E JNZ SHORT msvcrt.756296E4 756296B6 0AC0 OR AL,AL 756296B8 74 26 JE SHORT msvcrt.756296E0 756296BA 3A61 01 CMP AH,BYTE PTR DS:[ECX+1] 756296BD 75 25 JNZ SHORT msvcrt.756296E4 756296BF 0AE4 OR AH,AH 756296C1 74 1D JE SHORT msvcrt.756296E0 756296C3 C1E8 10 SHR EAX,10 756296C6 3A41 02 CMP AL,BYTE PTR DS:[ECX+2] 756296C9 75 19 JNZ SHORT msvcrt.756296E4 756296CB 0AC0 OR AL,AL 756296CD 74 11 JE SHORT msvcrt.756296E0 756296CF 3A61 03 CMP AH,BYTE PTR DS:[ECX+3] 756296D2 75 10 JNZ SHORT msvcrt.756296E4 756296D4 83C1 04 ADD ECX,4 756296D7 83C2 04 ADD EDX,4 756296DA 0AE4 OR AH,AH 756296DC ^ 75 D2 JNZ SHORT msvcrt.756296B0 756296DE 8BFF MOV EDI,EDI 756296E0 33C0 XOR EAX,EAX 756296E2 C3 RETN 756296E3 90 NOP 756296E4 1BC0 SBB EAX,EAX 756296E6 D1E0 SHL EAX,1 756296E8 83C0 01 ADD EAX,1 756296EB C3 RETN
En la comparación vemos que el serial bueno es AvrQQsXjDk25Jrh por lo que si restamos 0xD (13 en decimal) a cada carácter obtendremos el serial bueno.
0060FF10 41 76 72 51 51 73 58 6A 44 6B 32 35 4A 72 68 00 AvrQQsXjDk25Jrh. 41 76 72 51 51 73 58 6A 44 6B 32 35 4A 72 68 - D 34 69 65 44 44 66 4B 5D 37 5E 25 28 3D 65 5B 4 i e D D f K ] 7 ^ % ( = e [ Serial bueno: 4ieDDfK]7^%(=e[
La comprobación del serial es igual que la anterior pero sustituyendo la función que sumaba un valor a cada dígito del serial por una que genera un hash con nuestro serial y después lo compara con otro hash almacenado en memoria. Si no nos viene a la mente el tipo de hash que puede ser PEiD ya nos avisaba de que efectivamente el crackme incorpora la función MD5.
La función MD5 hace tiempo que no se considera segura debido a la existencia de numerosos «diccionarios» de hashes que hacen que encontremos la solución en segundos. Yo he utilizado la web MD5 online pero existen muchas más.
0060FE5C 004013BF RETURN to level4.004013BF from <JMP.&msvcrt.strcmp> 0060FE60 0060FEA0 ASCII "e807f1fcf82d132f9bb018ca6738a19f" 0060FE64 0060FEE0 ASCII "fe01d67a002dfa0f3ac084298142eccd" e807f1fcf82d132f9bb018ca6738a19f == 1234567890 fe01d67a002dfa0f3ac084298142eccd == orange
La carta de presentación de este crackme es la imagen que veis arriba. Al explorarlo unos minutos enseguida nos damos cuenta de que no realiza ninguna comprobación y que nos está haciendo perder el tiempo. Ahí es cuando empezamos a revisar el ejecutable más a fondo y enseguida encontramos la solución con nuestro amigo el editor hexadecimal.
Misma carta de presentación que el anterior y misma ausencia de comprobación del serial. En esta ocasión echando un vistazo a los recursos encontramos la solución rápidamente.
Hace unos años cuando empecé a trastear con Android y animado por mi afición a la Ingeniería Inversa, decidí realizar una serie de crackmes. Los dos primeros pasaron algo desapercibidos, pero el Crackme nº3 tuvo una gran repercusión en el mundillo y, aunque no fue el primer crackme para Android ni mucho menos, si que fue uno de los más estudiados. Todos ellos fueron publicados a través de crackmes.de y el nº3 en cuestión el 6 de Noviembre de 2010. Os dejo una lista de unas cuantas webs donde aparece analizado para que veáis la repercusión que a mi parecer tuvo.
Los retos de criptografía pueden ser muy variados como he dicho anteriormente. El secreto suele estar en saber a que te enfrentas y posteriormente construir una herramienta para descifrarlo o usar una ya existente (la mayoría de los casos).
Una web con la que suelo resolver la mayoría de retos es dcode.fr. Si os fijáis en el enlace, la lista de categorías asciende a 48 y disponéis de unos 800 algoritmos para rebanaros los sesos.
A continuación veamos unos cuantos retos que podéis encontrar por la red. Cabe destacar que normalmente el título del reto dice mucho del algoritmo.
Con John The Ripper tenemos que preparar un archivo de texto del estilo: deurus.info:1011:4C240DDAB17D1796AAD3B435B51404EE:4C240DDAB17D1796AAD3B435B51404EE:::
y ejecutar el comando: john –format=lm LM.txt
Conversiones, cifra clásica, hash, simétricos, asimétricos, combinaciones de varios algoritmos y un largo etcetera. Como veis los hay para todos los gustos, ten en cuenta que aquí os muestro una pequeñísima parte de lo que os encontrareis en las webs de retos, pero para despertar la curiosidad es suficiente.
¡Hala, a decodificar!
AVISO: Debido a que este reto está en activo no publicaré a donde pertenece.
En este pequeño CrackMe se nos pide investigar como se genera la clave que resuelve el reto. No tiene formulario donde introducir usuario y clave, cuando lo ejecutamos simplemente aparece una NAG dándonos a entender que no lo conseguimos.
Lo primero que vemos es esto:
004010B8 | 53 | push ebx | 004010B9 | 56 | push esi | 004010BA | 57 | push edi | 004010BB | 83 C4 F4 | add esp,FFFFFFF4 | 004010BE | C6 05 84 20 40 00 00 | mov byte ptr ds:[402084],0 | Dirección 402084 = 0 004010C5 | C7 44 24 08 28 00 00 00 | mov dword ptr ds:[esp+8],28 | 004010CD | 54 | push esp | 004010CE | 6A 01 | push 1 | 004010D0 | 6A 00 | push 0 | 004010D2 | 68 0C 20 40 00 | push exepuzz1.40200C | ;0040200C:"Software\\Caesum\\rev1" 004010D7 | 68 02 00 00 80 | push 80000002 | 004010DC | E8 F4 00 00 00 | call <exepuzz1.RegOpenKeyExA> | Distracción 004010E1 | 85 C0 | test eax,eax | 004010E3 | 0F 85 C6 00 00 00 | jne exepuzz1.4011AF | Parchear este salto 004010E9 | 8D 44 24 08 | lea eax,dword ptr ds:[esp+8] | 004010ED | 50 | push eax | 004010EE | 68 84 20 40 00 | push exepuzz1.402084 | Coge lo que haya en la dirección 402084 ........
Lo primero que nos llama la atención es que en 4010BE pone el DUMP 402084 a cero. Lo corroboramos:
00402000: 04 20 40 00 63 6D 62 69 70 6F 66 00 53 6F 66 74 ; . @.cmbipof.Soft
00402010: 77 61 72 65 5C 43 61 65 73 75 6D 5C 72 65 76 31 ; ware\Caesum\rev1
00402020: 00 6B 65 79 00 74 65 6C 6C 20 6D 65 20 74 68 65 ; .key.tell me the
00402030: 20 61 6E 73 77 65 72 00 59 6F 75 72 20 70 61 73 ; answer.Your pas
00402040: 73 20 69 73 20 00 42 6C 61 68 00 54 68 69 73 20 ; s is .Blah.This
00402050: 6C 69 74 74 6C 65 20 62 75 6E 6E 79 20 77 65 6E ; little bunny wen
00402060: 74 20 68 6F 70 00 42 6C 61 68 00 42 6C 61 68 2C ; t hop.Blah.Blah,
00402070: 20 73 65 65 20 69 66 20 49 20 63 61 72 65 00 42 ; see if I care.B
00402080: 6C 61 68 00 00 00 00 00 00 00 00 00 00 00 00 00 ; lah.............
^
|
----402084 (Ahora no hay nada)
Además para poder continuar la ejecución debemos parchear el salto JNE de la dirección 4010E3. Seguimos:
........ 004010F3 | 8D 54 24 0C | lea edx,dword ptr ds:[esp+C] | 004010F7 | 52 | push edx | 004010F8 | 6A 00 | push 0 | 004010FA | 68 21 20 40 00 | push exepuzz1.402021 | ;00402021:"key" 004010FF | 8B 4C 24 14 | mov ecx,dword ptr ds:[esp+14] | 00401103 | 51 | push ecx | 00401104 | E8 C6 00 00 00 | call <exepuzz1.RegQueryValueExA> | Distracción 00401109 | 8B 04 24 | mov eax,dword ptr ds:[esp] | 0040110C | 50 | push eax | 0040110D | E8 B7 00 00 00 | call <exepuzz1.RegCloseKey> | 00401112 | 68 25 20 40 00 | push exepuzz1.402025 | ;00402025:"tell me the answer" 00401117 | 68 84 20 40 00 | push exepuzz1.402084 | Coge lo que haya en la dirección 402084 0040111C | E8 17 FF FF FF | call exepuzz1.401038 | 00401121 | 83 C4 08 | add esp,8 | 00401124 | 85 C0 | test eax,eax | 00401126 | 74 72 | je exepuzz1.40119A | 00401128 | 68 84 20 40 00 | push exepuzz1.402084 | 0040112D | E8 CE FE FF FF | call exepuzz1.401000 | 00401132 | 59 | pop ecx | 00401133 | 8B F0 | mov esi,eax | 00401135 | 33 DB | xor ebx,ebx | 00401137 | B9 84 20 40 00 | mov ecx,exepuzz1.402084 | 0040113C | 3B F3 | cmp esi,ebx | 0040113E | 7E 21 | jle exepuzz1.401161 | 00401140 | 0F BE 01 | movsx eax,byte ptr ds:[ecx] |>----BUCLE------ 00401143 | 8B D0 | mov edx,eax | EAX y EDX contienen el valor HEX del dígito que toque 00401145 | BF 1A 00 00 00 | mov edi,1A | EDI = 1A 0040114A | 43 | inc ebx | incremento el contador 0040114B | 8D 04 C2 | lea eax,dword ptr ds:[edx+eax*8] | EAX = Dígito+Dígito*8 0040114E | 8D 04 C2 | lea eax,dword ptr ds:[edx+eax*8] | EAX = Dígito+EAX*8 00401151 | 83 C0 3B | add eax,3B | EAX = EAX+3B 00401154 | 99 | cdq | 00401155 | F7 FF | idiv edi | EAX / EDI 00401157 | 80 C2 61 | add dl,61 | DL + 61 0040115A | 88 11 | mov byte ptr ds:[ecx],dl | 0040115C | 41 | inc ecx | 0040115D | 3B F3 | cmp esi,ebx | ¿He terminado de recorrer la string? 0040115F | 7F DF | jg exepuzz1.401140 |^-----BUCLE------ ........
En 401117 vemos que intenta leer del DUMP en la dirección 402084 y a partir de ahí según lo que haya en el DUMP realiza una serie de operaciones con los datos y nos devuelve el resultado en forma de NAG.
Probamos varias cosas y nuestra teoría funciona pero, ¿cúal es la cadena de texto que debemos introducir?. A partir de aquí ya es un poco la intuición de cada uno, aunque la más lógica es «tell me the answer» que aparece justo antes del bucle.
En resumen: t 74 74*8+74 = 414*8+74 = 2114+3B = 214F MOD 1A = 19 + 61 = 72 (z) e 65 65*8+65 = 38D*8+65 = 1CCD+3B = 1D08 MOD 1A = 16 + 61 = 77 (w) l 6C 6C*8+6C = 3CC*8+6C = 1ECC+3B = 1F07 MOD 1A = D + 61 = 6E (n) l 6C 6C*8+6C = 3CC*8+6C = 1ECC+3B = 1F07 MOD 1A = D + 61 = 6E (n) 20 20*8+20 = 120*8+20 = 0920+3B = 095B MOD 1A = 3 + 61 = 64 (d) m 6D 6D*8+6D = 3D5*8+6D = 1F15+3B = 1F50 MOD 1A = 8 + 61 = 69 (i) e 65 65*8+65 = 38D*8+65 = 1CCD+3B = 1D08 MOD 1A = 16 + 61 = 77 (w) 20 20*8+20 = 120*8+20 = 0920+3B = 095B MOD 1A = 3 + 61 = 64 (d) t 74 74*8+74 = 414*8+74 = 2114+3B = 214F MOD 1A = 19 + 61 = 72 (z) h 68 68*8+68 = 3A8*8+68 = 1DA8+3B = 1DE3 MOD 1A = 7 + 61 = 68 (h) e 65 65*8+65 = 38D*8+65 = 1CCD+3B = 1D08 MOD 1A = 16 + 61 = 77 (w) 20 20*8+20 = 120*8+20 = 0920+3B = 095B MOD 1A = 3 + 61 = 64 (d) a 61 61*8+61 = 369*8+61 = 1BA9+3B = 1BE4 MOD 1A = 10 + 61 = 71 (q) n 6E 6E*8+6E = 3DE*8+6E = 1F5E+3B = 1F9C MOD 1A = 6 + 61 = 67 (g) s 73 73*8+73 = 40B*8+73 = 20CB+3B = 2106 MOD 1A = 4 + 61 = 65 (e) w 77 77*8+77 = 42F*8+77 = 21EF+3B = 222A MOD 1A = A + 61 = 6B (k) e 65 65*8+65 = 38D*8+65 = 1CCD+3B = 1D08 MOD 1A = 16 + 61 = 77 (w) r 72 72*8+72 = 402*8+72 = 2082+3B = 20BD MOD 1A = 9 + 61 = 6A (j) zwnndiwdzhwdqdekwj
La cadena de texto resultante ¿sera la correcta?
Este crackme pertenece a la página de Karpoff Spanish Tutor. Data del año 2000 y está realizado en «Borland Delphi 6.0 – 7.0», además, para resolverlo deberemos activar un botón y conseguir la clave de registro. La principal dificultad proviene a la hora de activar el botón ya que el serial es en realidad un serial hardcodeado muy sencillo.
Existen numerosas herramientas para facilitarnos esta tarea, una de las más conocidas en el entorno del Cracking es «Veoveo» realizado por Crack el Destripador & Marmota hace ya unos añitos. Con el crackme ejecutado, ejecutamos VeoVeo y nos aparece el icono en la barra de tareas, hacemos click derecho y elegimos Activar Botones (manual) y ya tenemos el botón activado. Claro está que en cada ejecución del Crackme debemos de Re-activarlo.
Lo que siempre nos interesa es que el botón esté activado de forma permanente y eso nos exige un poco más de atención. En este caso nos enfrentamos a Delphi y no nos sirve ni Resource Hacker ni Dede. Cuando nos encontramos en un punto muerto el último recurso siempre es realizar un programa en Delphi con un botón activado y otro desactivado y compararlos con un editor hexadecimal para saber que cambia. Si hacemos esto llegaremos a la conclusión de que en Delphi el bit que equivale a desactivado es 8 y ha activado es 9. Con este simple cambio ya tenemos el crackme parcheado. Comentar que en este caso el crackme no tiene ningún timer ni ninguna rutina que desactive el botón de forma periódica, este es el caso más simple.
Abrimos Ollydbg y en las «String references» encontramos los mensajes de versión registrada, pinchamos sobre ellos y vemos a simple vista la zona de comprobación del serial. Como podéis observar, el serial se vé a simple vista.
0045811A |. B8 10824500 MOV EAX,CrackMe3.00458210 ; ASCII "ESCRIBE ALGO JOER" 0045811F |. E8 D889FDFF CALL CrackMe3.00430AFC 00458124 |. EB 5C JMP SHORT CrackMe3.00458182 00458126 |> 807D FF 4F CMP BYTE PTR SS:[EBP-1],4F - O 0045812A |. 75 56 JNZ SHORT CrackMe3.00458182 0045812C |. 807D FE 41 CMP BYTE PTR SS:[EBP-2],41 - A 00458130 |. 75 50 JNZ SHORT CrackMe3.00458182 00458132 |. 807D FD 45 CMP BYTE PTR SS:[EBP-3],45 - E 00458136 |. 75 4A JNZ SHORT CrackMe3.00458182 00458138 |. 807D FC 4B CMP BYTE PTR SS:[EBP-4],4B - K 0045813C |. 75 44 JNZ SHORT CrackMe3.00458182 0045813E |. 807D FB 43 CMP BYTE PTR SS:[EBP-5],43 - C 00458142 |. 75 3E JNZ SHORT CrackMe3.00458182 00458144 |. 807D FA 41 CMP BYTE PTR SS:[EBP-6],41 - A 00458148 |. 75 38 JNZ SHORT CrackMe3.00458182 0045814A |. 807D F9 52 CMP BYTE PTR SS:[EBP-7],52 - R 0045814E |. 75 32 JNZ SHORT CrackMe3.00458182 00458150 |. 807D F8 4B CMP BYTE PTR SS:[EBP-8],4B - K 00458154 |. 75 2C JNZ SHORT CrackMe3.00458182 00458156 |. 807D F7 20 CMP BYTE PTR SS:[EBP-9],20 - 0045815A |. 75 26 JNZ SHORT CrackMe3.00458182 0045815C |. 807D F6 49 CMP BYTE PTR SS:[EBP-A],49 - I 00458160 |. 75 20 JNZ SHORT CrackMe3.00458182 00458162 |. 807D F5 4F CMP BYTE PTR SS:[EBP-B],4F - O 00458166 |. 75 1A JNZ SHORT CrackMe3.00458182 00458168 |. 807D F4 54 CMP BYTE PTR SS:[EBP-C],54 - T 0045816C |. 75 14 JNZ SHORT CrackMe3.00458182 0045816E |. 807D F3 20 CMP BYTE PTR SS:[EBP-D],20 - 00458172 |. 75 0E JNZ SHORT CrackMe3.00458182 00458174 |. 807D F2 41 CMP BYTE PTR SS:[EBP-E],41 - A 00458178 |. 75 08 JNZ SHORT CrackMe3.00458182 0045817A |. 807D F1 59 CMP BYTE PTR SS:[EBP-F],59 - Y 0045817E |. 75 02 JNZ SHORT CrackMe3.00458182 00458180 |. B3 01 MOV BL,1 00458182 |> 80FB 01 CMP BL,1 00458185 |. 75 4C JNZ SHORT CrackMe3.004581D3 00458187 |. BA 2C824500 MOV EDX,CrackMe3.0045822C 0045818C |. 8B86 F4020000 MOV EAX,DWORD PTR DS:[ESI+2F4] 00458192 |. E8 B5EBFDFF CALL CrackMe3.00436D4C 00458197 |. BA 48824500 MOV EDX,CrackMe3.00458248 ; ASCII "VERSION REGISTRADA :)" Serial = YA TOI KRACKEAO
Warning: This challenge is still active and therefore should not be resolved using this information.
Aviso: Este reto sigue en activo y por lo tanto no se debería resolver utilizando esta información.
Este es el típico reto de Javascript, no tiene mucha complicación pero he decidido dedicarle una entrada por que me llamó la atención lo que utiliza de usuario y clave.
function getStyle(el,styleProp)
{
var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
if (y.substr(0, 1) == "#"){ return y; } else {
var value = y.split(',');
var R = value[0].substr(4);
var G = value[1];
var B = value[2].substr(0, value[2].length-1);
var RGB = "#" + toHex(R)+ toHex(G)+toHex(B);
return RGB;
}
}
function toHex(N) {
if (N==null) return "00";
N=parseInt(N); if (N==0 || isNaN(N)) return "00";
N=Math.max(0,N); N=Math.min(N,255); N=Math.round(N);
return "0123456789ABCDEF".charAt((N-N%16)/16)
+ "0123456789ABCDEF".charAt(N%16);
}
function pw (form)
{
var d1, d2, d3;
if (navigator.appName == "Netscape"){
d1= getStyle('content', 'background-color');
} else {
d1= getStyle('content', 'backgroundColor');
}
d2=form.Name.value;
d3=form.Password.value;
if (d2==d1.length) {
if (d3==d1) {
window.open ("../" + d1.substr(1, 10), "_self")
} else {
alert("Muhaha! Wrong!")
}
} else {
alert("Muhaha! Wrong!")
}
}
<div class="chal_box" style="padding:10px;">
<form name="form" action="" method="post">
Username<br />
<input id="inputd2" type="text" name="Name" value="" size="30" maxlength="30"><br />
Password<br />
<input id="inputd1" type="text" name="Password" value="" size="30" maxlength="30"><br /><br />
<input type="button" name="Only a button" value="Enter Site" id="Only a button" class="btn" onclick="pw(this.form)">
</form>
</div>
En el formulario vemos que llama a la función «pw» y ésta a su vez llama a la función «getStyle«, bueno, pués es tan simple como poner un «alert();» dentro de la función «pw» para cazar la clave. Con éste método podemos cazar la clave del 90% de este tipo de pruebas.
Con esto ya tenemos la clave. El usuario responde a la siguiente sentencia «d2==d1.length«, es decir, es el número de dígitos de la clave.
¿Fácil no?
Recién rescatados del inframundo que es mi disco duro, os traigo un paquete de seis crackmes facilones para vuestro uso y disfrute. Desgraciadamente ya no está en activo la web de retos de donde los saqué así que os los dejo en descargas.
Los cuatro primero están realizados en Dev-C++ 4.9.9.2 siendo de estilo consola de comandos. Los dos restantes compilados con MingWin32 GCC 3.x carecen de GUI y vamos, que no se han esmerado mucho en darles forma.
No cuesta mucho dar con el código interesante mediante las referencias de texto. En Ollydbg clic derecho sobre el código y Search for > All referenced text strings.
004012E1 |. 8845 E8 MOV BYTE PTR SS:[EBP-18],AL ; |||| 004012E4 |. C70424 11304000 MOV DWORD PTR SS:[ESP],level1.00403011 ; ||||ASCII "Input Serial: " 004012EB |. E8 C0050000 CALL <JMP.&msvcrt.printf> ; |||\printf 004012F0 |. 8D45 C8 LEA EAX,[LOCAL.14] ; ||| 004012F3 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; ||| 004012F7 |. C70424 20304000 MOV DWORD PTR SS:[ESP],level1.00403020 ; |||ASCII "%s" 004012FE |. E8 9D050000 CALL <JMP.&msvcrt.scanf> ; ||\scanf 00401303 |. 8D45 D8 LEA EAX,[LOCAL.10] ; || 00401306 |. 8D55 C8 LEA EDX,[LOCAL.14] ; || 00401309 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; || 0040130D |. 891424 MOV DWORD PTR SS:[ESP],EDX ; ||level1.00403022 00401310 |. E8 7B050000 CALL <JMP.&msvcrt.strcmp> ; |\strcmp 00401315 |. 8945 C4 MOV [LOCAL.15],EAX ; | 00401318 |. 837D C4 00 CMP [LOCAL.15],0 ; | 0040131C |. 75 0E JNZ SHORT level1.0040132C ; | 0040131E |. C70424 23304000 MOV DWORD PTR SS:[ESP],level1.00403023 ; |ASCII "Well done. \n" 00401325 |. E8 86050000 CALL <JMP.&msvcrt.printf> ; \printf 0040132A |. EB 0C JMP SHORT level1.00401338 0040132C |> C70424 30304000 MOV DWORD PTR SS:[ESP],level1.00403030 ; |ASCII "Wrong. \n" 00401333 |. E8 78050000 CALL <JMP.&msvcrt.printf> ; \printf 00401338 |> C70424 39304000 MOV DWORD PTR SS:[ESP],level1.00403039 ; |ASCII "PAUSE" 0040133F |. E8 3C050000 CALL <JMP.&msvcrt.system> ; \system 00401344 |. B8 00000000 MOV EAX,0 00401349 |. C9 LEAVE 0040134A \. C3 RETN
La madre del cordero está en la dirección 401310 que es donde se lleva a cabo la función de comparación strcmp.
756296A0 msvcrt.strcmp 8B5424 04 MOV EDX,DWORD PTR SS:[ESP+4] 756296A4 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8] 756296A8 F7C2 03000000 TEST EDX,3 ; 0-3 = 4 bucles. Divide la comprobación en 4 bloques 756296AE 75 3C JNZ SHORT msvcrt.756296EC ; salta si hemos terminado los 4 bucles 756296B0 > 8B02 MOV EAX,DWORD PTR DS:[EDX] ; coge 4 caracteres del serial (INICIO BUCLE) 756296B2 3A01 CMP AL,BYTE PTR DS:[ECX] ; compara el 1º/5º/9º/13º dígito en función del bucle 756296B4 75 2E JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296B6 0AC0 OR AL,AL 756296B8 74 26 JE SHORT msvcrt.756296E0 756296BA 3A61 01 CMP AH,BYTE PTR DS:[ECX+1] ; compara el 2º/6º/10º/14º dígito en función del bucle 756296BD 75 25 JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296BF 0AE4 OR AH,AH 756296C1 74 1D JE SHORT msvcrt.756296E0 756296C3 C1E8 10 SHR EAX,10 756296C6 3A41 02 CMP AL,BYTE PTR DS:[ECX+2] ; compara el 3º/7º/11º/15º dígito en función del bucle 756296C9 75 19 JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296CB 0AC0 OR AL,AL 756296CD 74 11 JE SHORT msvcrt.756296E0 756296CF 3A61 03 CMP AH,BYTE PTR DS:[ECX+3] ; compara el 4º/8º/12º/16º dígito en función del bucle 756296D2 75 10 JNZ SHORT msvcrt.756296E4 ; salto a zona mala 756296D4 83C1 04 ADD ECX,4 756296D7 83C2 04 ADD EDX,4 756296DA 0AE4 OR AH,AH 756296DC ^ 75 D2 JNZ SHORT msvcrt.756296B0 ; Si no hemos terminado... 756296DE 8BFF MOV EDI,EDI 756296E0 33C0 XOR EAX,EAX ; EAX = 0 que es lo deseado 756296E2 C3 RETN ; salimos de la función superando la comprobación 756296E3 90 NOP 756296E4 1BC0 SBB EAX,EAX ; Zona mala 756296E6 D1E0 SHL EAX,1 756296E8 83C0 01 ADD EAX,1 ; EAX = 1 implica bad boy 756296EB C3 RETN ; salimos de la función
Si atendemos al volcado vemos el serial bueno Kcgcv8LsmV3nizfJ.
0060FEF0 31 32 33 34 35 36 37 38 39 30 00 75 40 19 18 00 1234567890.u@. 0060FF00 4B 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A Kcgcv8LsmV3nizfJ
Curiosamente, si introducimos el serial bueno el crackme no lo acepta. Fijándome en la comprobación veo que al introducir un serial de 16 caracteres inserta un carácter nulo (0x00) alterando el serial correcto y falseando la comprobación.
0060FEF0 4B 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A Kcgcv8LsmV3nizfJ 0060FF00 00 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A .cgcv8LsmV3nizfJ
Ahora ya no podemos comprobarlo pero recuerdo que la web consideraba válido el serial Kcgcv8LsmV3nizfJ, por lo que considero lo anteriormente citado un bug o un intento de despiste del autor.
Es exactamente igual que el anterior cambiando el serial por 6LPw3vDYja9KrT2V.
La comprobación del serial es igual a las dos anteriores pero añade una función intermedia que suma 0xD a cada carácter de nuestro serial
00401355 |. A1 03304000 MOV EAX,DWORD PTR DS:[403003] ; || 0040135A |. 8945 E8 MOV [LOCAL.6],EAX ; || 0040135D |. A1 07304000 MOV EAX,DWORD PTR DS:[403007] ; || 00401362 |. 8945 EC MOV [LOCAL.5],EAX ; || 00401365 |. A1 0B304000 MOV EAX,DWORD PTR DS:[40300B] ; || 0040136A |. 8945 F0 MOV [LOCAL.4],EAX ; || 0040136D |. A1 0F304000 MOV EAX,DWORD PTR DS:[40300F] ; || 00401372 |. 8945 F4 MOV [LOCAL.3],EAX ; || 00401375 |. C70424 13304000 MOV DWORD PTR SS:[ESP],level3.00403013 ; ||ASCII "Input Serial: " 0040137C |. E8 CF050000 CALL <JMP.&msvcrt.printf> ; |\printf 00401381 |. 8D45 D8 LEA EAX,[LOCAL.10] ; | 00401384 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; | 00401388 |. C70424 00304000 MOV DWORD PTR SS:[ESP],level3.00403000 ; |ASCII "%s" 0040138F |. E8 AC050000 CALL <JMP.&msvcrt.scanf> ; \scanf 00401394 |. 8D5D E8 LEA EBX,[LOCAL.6] 00401397 |. 8D45 D8 LEA EAX,[LOCAL.10] 0040139A |. 890424 MOV DWORD PTR SS:[ESP],EAX 0040139D |. E8 EEFEFFFF CALL level3.00401290 ; NUEVA FUNCIÓN SUMA 004013A2 |. 895C24 04 MOV DWORD PTR SS:[ESP+4],EBX ; || 004013A6 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; || 004013A9 |. E8 82050000 CALL <JMP.&msvcrt.strcmp> ; |\strcmp 004013AE |. 8945 D4 MOV [LOCAL.11],EAX ; | 004013B1 |. 837D D4 00 CMP [LOCAL.11],0 ; | 004013B5 |. 75 0E JNZ SHORT level3.004013C5 ; | 004013B7 |. C70424 22304000 MOV DWORD PTR SS:[ESP],level3.00403022 ; |ASCII "Well done." 004013BE |. E8 8D050000 CALL <JMP.&msvcrt.printf> ; \printf 004013C3 |. EB 0C JMP SHORT level3.004013D1 004013C5 |> C70424 2D304000 MOV DWORD PTR SS:[ESP],level3.0040302D ; |ASCII "Wrong. \n" 004013CC |. E8 7F050000 CALL <JMP.&msvcrt.printf> ; \printf 004013D1 |> C70424 36304000 MOV DWORD PTR SS:[ESP],level3.00403036 ; |ASCII "PAUSE" 004013D8 |. E8 43050000 CALL <JMP.&msvcrt.system> ; \system 004013DD |. B8 00000000 MOV EAX,0 004013E2 |. 8B5D FC MOV EBX,[LOCAL.1] 004013E5 |. C9 LEAVE 004013E6 \. C3 RETN -------- 004012A4 |> /8B45 08 /MOV EAX,[ARG.1] ; | 004012A7 |. |890424 |MOV DWORD PTR SS:[ESP],EAX ; | 004012AA |. |E8 B1060000 |CALL <JMP.&msvcrt.strlen> ; \strlen 004012AF |. |3945 FC |CMP [LOCAL.1],EAX 004012B2 |. |73 1C |JNB SHORT level3.004012D0 004012B4 |. |8B45 08 |MOV EAX,[ARG.1] 004012B7 |. |8B55 FC |MOV EDX,[LOCAL.1] 004012BA |. |01C2 |ADD EDX,EAX 004012BC |. |8B45 08 |MOV EAX,[ARG.1] 004012BF |. |0345 FC |ADD EAX,[LOCAL.1] 004012C2 |. |0FB600 |MOVZX EAX,BYTE PTR DS:[EAX] 004012C5 |. |04 0D |ADD AL,0D ; char + 0xD 004012C7 |. |8802 |MOV BYTE PTR DS:[EDX],AL 004012C9 |. |8D45 FC |LEA EAX,[LOCAL.1] 004012CC |. |FF00 |INC DWORD PTR DS:[EAX] 004012CE |.^\EB D4 \JMP SHORT level3.004012A4 -------- 756296A0 msvcrt.strcmp 8B5424 04 MOV EDX,DWORD PTR SS:[ESP+4] 756296A4 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8] 756296A8 F7C2 03000000 TEST EDX,3 756296AE 75 3C JNZ SHORT msvcrt.756296EC 756296B0 8B02 MOV EAX,DWORD PTR DS:[EDX] 756296B2 3A01 CMP AL,BYTE PTR DS:[ECX] 756296B4 75 2E JNZ SHORT msvcrt.756296E4 756296B6 0AC0 OR AL,AL 756296B8 74 26 JE SHORT msvcrt.756296E0 756296BA 3A61 01 CMP AH,BYTE PTR DS:[ECX+1] 756296BD 75 25 JNZ SHORT msvcrt.756296E4 756296BF 0AE4 OR AH,AH 756296C1 74 1D JE SHORT msvcrt.756296E0 756296C3 C1E8 10 SHR EAX,10 756296C6 3A41 02 CMP AL,BYTE PTR DS:[ECX+2] 756296C9 75 19 JNZ SHORT msvcrt.756296E4 756296CB 0AC0 OR AL,AL 756296CD 74 11 JE SHORT msvcrt.756296E0 756296CF 3A61 03 CMP AH,BYTE PTR DS:[ECX+3] 756296D2 75 10 JNZ SHORT msvcrt.756296E4 756296D4 83C1 04 ADD ECX,4 756296D7 83C2 04 ADD EDX,4 756296DA 0AE4 OR AH,AH 756296DC ^ 75 D2 JNZ SHORT msvcrt.756296B0 756296DE 8BFF MOV EDI,EDI 756296E0 33C0 XOR EAX,EAX 756296E2 C3 RETN 756296E3 90 NOP 756296E4 1BC0 SBB EAX,EAX 756296E6 D1E0 SHL EAX,1 756296E8 83C0 01 ADD EAX,1 756296EB C3 RETN
En la comparación vemos que el serial bueno es AvrQQsXjDk25Jrh por lo que si restamos 0xD (13 en decimal) a cada carácter obtendremos el serial bueno.
0060FF10 41 76 72 51 51 73 58 6A 44 6B 32 35 4A 72 68 00 AvrQQsXjDk25Jrh. 41 76 72 51 51 73 58 6A 44 6B 32 35 4A 72 68 - D 34 69 65 44 44 66 4B 5D 37 5E 25 28 3D 65 5B 4 i e D D f K ] 7 ^ % ( = e [ Serial bueno: 4ieDDfK]7^%(=e[
La comprobación del serial es igual que la anterior pero sustituyendo la función que sumaba un valor a cada dígito del serial por una que genera un hash con nuestro serial y después lo compara con otro hash almacenado en memoria. Si no nos viene a la mente el tipo de hash que puede ser PEiD ya nos avisaba de que efectivamente el crackme incorpora la función MD5.
La función MD5 hace tiempo que no se considera segura debido a la existencia de numerosos «diccionarios» de hashes que hacen que encontremos la solución en segundos. Yo he utilizado la web MD5 online pero existen muchas más.
0060FE5C 004013BF RETURN to level4.004013BF from <JMP.&msvcrt.strcmp> 0060FE60 0060FEA0 ASCII "e807f1fcf82d132f9bb018ca6738a19f" 0060FE64 0060FEE0 ASCII "fe01d67a002dfa0f3ac084298142eccd" e807f1fcf82d132f9bb018ca6738a19f == 1234567890 fe01d67a002dfa0f3ac084298142eccd == orange
La carta de presentación de este crackme es la imagen que veis arriba. Al explorarlo unos minutos enseguida nos damos cuenta de que no realiza ninguna comprobación y que nos está haciendo perder el tiempo. Ahí es cuando empezamos a revisar el ejecutable más a fondo y enseguida encontramos la solución con nuestro amigo el editor hexadecimal.
Misma carta de presentación que el anterior y misma ausencia de comprobación del serial. En esta ocasión echando un vistazo a los recursos encontramos la solución rápidamente.
Hoy tenemos aquí un crackme del 2009 originario de crackmes.de. El Crackme está hecho en VB6, sin empacar y consta de 4 tareas a superar. Un anti-debugger, un parcheo, una sorpresa y finalmente un algoritmo sencillo.
Nuestro primer incordio es el anti-debbuger. Este lo podemos afrontar de diferentes maneras, con un plugin desde Olly o de forma permanente parcheando. Si elegimos parchear debemos hacerlo en el offset 408328, cambiando el salto je por jmp.
00408328 /0F84 69030000 je T0RNAD0'.00408697
Si iniciamos el crackme nos encontramos con la siguiente nag que nos impide el arranque.
Las referencias de texto parecen encriptadas así que, ponemos un breakpoint a MSVBVM60.rtcMsgBox y vemos que la llamada se hace desde el offset 406897. Un poco más arriba encontramos un salto condicional muy interesante, concretamente en el offset 40677B. Lo cambiamos por un jmp y arrancamos el programa.
A continuación arranca el crackme y vemos lo siguiente.
La sorpresa es que el formulario no se mueve y no hay rastro de las cajas de texto del keygenme. Por suerte para nosotros este crackme está hecho en vb6 y como tal podemos abrirlo con VB Reformer para ver que se nos ofrece.
Abrimos VB Reformer y cambiamos la propiedad «Moveable» del formulario a true.
Ahora ya podemos mover el formulario y por suerte para nosotros, si lo movemos hacia la esquina superior izquierda aparecen las cajas de texto por arte de magia.
Como hemos dicho antes, las referencias de texto son inútiles, de modo que ponemos un breakpoint a MSVBVM60.__vbaStrCmp y enseguida obtenemos nuestro primer serial válido. También nos percatamos de que hasta que no metemos en el nombre 8 dígitos, no nos muestra un mensaje de error. De este mismo modo obtenemos que el nombre más grande puede tener 30 dígitos.
Username: deurusab (lenght 8)
0012F3F0 0040533A RETURN to T0RNAD0'.0040533A from MSVBVM60.__vbaStrCmp
0012F3F4 0015C954 UNICODE "L-8-deurus-0199F9CA"
Username: abcdefghijklmnopqrstuvwxyz1234 (lenght 30)
0012F3F0 0040533A RETURN to T0RNAD0'.0040533A from MSVBVM60.__vbaStrCmp
0012F3F4 0015F40C UNICODE "L-30-lmnopq-DD19F9CA"
Finalmente llegamos a la rutina de comprobación del serial. Usaremos como nombre: abcdefghijklmnopqrstuvwxyz1234.
00404E82 . 52 push edx 00404E83 . 56 push esi 00404E84 . C746 34 0DF0D1BA mov dword ptr ds:[esi+34],BAD1F00D |Variables cachondas 00404E8B . C746 38 01ADDE10 mov dword ptr ds:[esi+38],10DEAD01 |Variables cachondas 00404E92 . C746 3C EFBE1010 mov dword ptr ds:[esi+3C],1010BEEF |Variables cachondas 00404E99 . C746 40 D0BA0110 mov dword ptr ds:[esi+40],1001BAD0 |Variables cachondas 00404EA0 . FF91 2C070000 call ds:[ecx+72C] 00404EA6 . 3BC7 cmp eax,edi 00404EA8 . DBE2 fclex 00404EAA . 7D 12 jge short T0RNAD0'.00404EBE 00404EAC . 68 2C070000 push 72C 00404EB1 . 68 14404000 push T0RNAD0'.00404014 00404EB6 . 56 push esi 00404EB7 . 50 push eax 00404EB8 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404EBE > 8B45 B4 mov eax,ss:[ebp-4C] 00404EC1 . 8D55 E0 lea edx,ss:[ebp-20] 00404EC4 . 52 push edx 00404EC5 . 50 push eax 00404EC6 . 8B08 mov ecx,ds:[eax] 00404EC8 . 8985 48FFFFFF mov ss:[ebp-B8],eax 00404ECE . FF91 A0000000 call ds:[ecx+A0] 00404ED4 . 3BC7 cmp eax,edi 00404ED6 . DBE2 fclex 00404ED8 . 7D 18 jge short T0RNAD0'.00404EF2 00404EDA . 8B8D 48FFFFFF mov ecx,ss:[ebp-B8] 00404EE0 . 68 A0000000 push 0A0 00404EE5 . 68 7C414000 push T0RNAD0'.0040417C 00404EEA . 51 push ecx 00404EEB . 50 push eax 00404EEC . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404EF2 > 8B45 E0 mov eax,ss:[ebp-20] |Mueve el nombre a eax 00404EF5 . 8D55 A0 lea edx,ss:[ebp-60] 00404EF8 . 8945 A8 mov ss:[ebp-58],eax 00404EFB . 6A 01 push 1 00404EFD . 8D45 90 lea eax,ss:[ebp-70] 00404F00 . 52 push edx 00404F01 . 50 push eax 00404F02 . 897D E0 mov ss:[ebp-20],edi 00404F05 . C745 A0 08000000 mov dword ptr ss:[ebp-60],8 00404F0C . FF15 40114000 call ds:[<&MSVBVM60.#619>] ; MSVBVM60.rtcRightCharVar 00404F12 . 8B3D D0104000 mov edi,ds:[<&MSVBVM60.__vbaStrVarVal>] ; MSVBVM60.__vbaStrVarVal 00404F18 . 8D4D 90 lea ecx,ss:[ebp-70] 00404F1B . 8D55 DC lea edx,ss:[ebp-24] 00404F1E . 51 push ecx 00404F1F . 52 push edx 00404F20 . FFD7 call edi ; <&MSVBVM60.__vbaStrVarVal> 00404F22 . 50 push eax 00404F23 . FF15 30104000 call ds:[<&MSVBVM60.#516>] ; MSVBVM60.rtcAnsiValueBstr |Toma el último dígito en ascii (4 asc = 34) 00404F29 . 66:6BC0 7B imul ax,ax,7B |34 * 7B = 18FC 00404F2D . 8B4E 34 mov ecx,ds:[esi+34] |Mueve BAD1F00D a ecx 00404F30 . 0F80 05070000 jo T0RNAD0'.0040563B 00404F36 . 0FBFC0 movsx eax,ax 00404F39 . 33C8 xor ecx,eax |18FC xor BAD1F00D = BAD1E8F1 00404F3B . 894E 34 mov ds:[esi+34],ecx 00404F3E . 8D4D DC lea ecx,ss:[ebp-24] 00404F41 . FF15 5C114000 call ds:[<&MSVBVM60.__vbaFreeStr>] ; MSVBVM60.__vbaFreeStr 00404F47 . 8D4D B4 lea ecx,ss:[ebp-4C] 00404F4A . FF15 60114000 call ds:[<&MSVBVM60.__vbaFreeObj>] ; MSVBVM60.__vbaFreeObj 00404F50 . 8D4D 90 lea ecx,ss:[ebp-70] 00404F53 . 8D55 A0 lea edx,ss:[ebp-60] 00404F56 . 51 push ecx 00404F57 . 52 push edx 00404F58 . 6A 02 push 2 00404F5A . FF15 20104000 call ds:[<&MSVBVM60.__vbaFreeVarList>] ; MSVBVM60.__vbaFreeVarList 00404F60 . 8B06 mov eax,ds:[esi] 00404F62 . 83C4 0C add esp,0C 00404F65 . 8D4D B4 lea ecx,ss:[ebp-4C] 00404F68 . 51 push ecx 00404F69 . 56 push esi 00404F6A . FF90 2C070000 call ds:[eax+72C] 00404F70 . 85C0 test eax,eax 00404F72 . DBE2 fclex 00404F74 . 7D 12 jge short T0RNAD0'.00404F88 00404F76 . 68 2C070000 push 72C 00404F7B . 68 14404000 push T0RNAD0'.00404014 00404F80 . 56 push esi 00404F81 . 50 push eax 00404F82 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404F88 > 8B45 B4 mov eax,ss:[ebp-4C] 00404F8B . 8D4D E0 lea ecx,ss:[ebp-20] 00404F8E . 51 push ecx 00404F8F . 50 push eax 00404F90 . 8B10 mov edx,ds:[eax] 00404F92 . 8985 48FFFFFF mov ss:[ebp-B8],eax 00404F98 . FF92 A0000000 call ds:[edx+A0] 00404F9E . 85C0 test eax,eax 00404FA0 . DBE2 fclex 00404FA2 . 7D 18 jge short T0RNAD0'.00404FBC 00404FA4 . 8B95 48FFFFFF mov edx,ss:[ebp-B8] 00404FAA . 68 A0000000 push 0A0 00404FAF . 68 7C414000 push T0RNAD0'.0040417C 00404FB4 . 52 push edx 00404FB5 . 50 push eax 00404FB6 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00404FBC > 8B45 E0 mov eax,ss:[ebp-20] 00404FBF . 6A 01 push 1 00404FC1 . 8945 A8 mov ss:[ebp-58],eax 00404FC4 . 8D45 A0 lea eax,ss:[ebp-60] 00404FC7 . 8D4D 90 lea ecx,ss:[ebp-70] 00404FCA . 50 push eax 00404FCB . 51 push ecx 00404FCC . C745 E0 00000000 mov dword ptr ss:[ebp-20],0 00404FD3 . C745 A0 08000000 mov dword ptr ss:[ebp-60],8 00404FDA . FF15 2C114000 call ds:[<&MSVBVM60.#617>] ; MSVBVM60.rtcLeftCharVar 00404FE0 . 8D55 90 lea edx,ss:[ebp-70] 00404FE3 . 8D45 DC lea eax,ss:[ebp-24] 00404FE6 . 52 push edx 00404FE7 . 50 push eax 00404FE8 . FFD7 call edi 00404FEA . 50 push eax 00404FEB . FF15 30104000 call ds:[<&MSVBVM60.#516>] ; MSVBVM60.rtcAnsiValueBstr |Toma el primer dígito en ascii (a asc = 61) 00404FF1 . 66:6BC0 7B imul ax,ax,7B |61 * 7B = 2E9B 00404FF5 . 8B56 3C mov edx,ds:[esi+3C] |Mueve 1010BEEF a edx 00404FF8 . 0F80 3D060000 jo T0RNAD0'.0040563B 00404FFE . 0FBFC8 movsx ecx,ax 00405001 . 33D1 xor edx,ecx | 2E9B xor 1010BEEF = 10109074 00405003 . 8D4D DC lea ecx,ss:[ebp-24] 00405006 . 8956 3C mov ds:[esi+3C],edx 00405009 . FF15 5C114000 call ds:[<&MSVBVM60.__vbaFreeStr>] ; MSVBVM60.__vbaFreeStr 0040500F . 8D4D B4 lea ecx,ss:[ebp-4C] 00405012 . FF15 60114000 call ds:[<&MSVBVM60.__vbaFreeObj>] ; MSVBVM60.__vbaFreeObj 00405018 . 8D55 90 lea edx,ss:[ebp-70] 0040501B . 8D45 A0 lea eax,ss:[ebp-60] 0040501E . 52 push edx 0040501F . 50 push eax 00405020 . 6A 02 push 2 00405022 . FF15 20104000 call ds:[<&MSVBVM60.__vbaFreeVarList>] ; MSVBVM60.__vbaFreeVarList 00405028 . 66:8BCB mov cx,bx |Mueve a CX el tamaño del nombre 0040502B . 83C4 0C add esp,0C 0040502E . 66:69C9 4101 imul cx,cx,141 |Tamaño nombre(1E) * 141 = 259E 00405033 . 8B46 3C mov eax,ds:[esi+3C] 00405036 . 0F80 FF050000 jo T0RNAD0'.0040563B 0040503C . 0FBFD1 movsx edx,cx 0040503F . 8B4E 38 mov ecx,ds:[esi+38] |Mueve a ECX 10DEAD01 00405042 . 33D0 xor edx,eax |10109074 xor 259E = 1010B5BA 00405044 . 33CA xor ecx,edx |1010B5BA xor 10DEAD01 = 00CE18EB 00405046 . 66:8BD3 mov dx,bx 00405049 . 66:69D2 4101 imul dx,dx,141 |Tamaño nombre(1E) * 141 = 259E 0040504E . 0F80 E7050000 jo T0RNAD0'.0040563B 00405054 . 894E 38 mov ds:[esi+38],ecx 00405057 . 81F1 01010101 xor ecx,1010101 |00CE18EB xor 1010101 = 01CF19EA (Temp1) 0040505D . 0FBFD2 movsx edx,dx 00405060 . 3356 34 xor edx,ds:[esi+34] |BAD1E8F1 xor 259E = BAD1CD6F 00405063 . 894E 38 mov ds:[esi+38],ecx 00405066 . 35 10101010 xor eax,10101010 |10109074 xor 10101010 = 8064 0040506B . 8D4D B4 lea ecx,ss:[ebp-4C] 0040506E . 3156 40 xor ds:[esi+40],edx |BAD1CD6F xor 1001BAD0 = AAD077BF (Temp2) 00405071 . 8946 3C mov ds:[esi+3C],eax 00405074 . 8B06 mov eax,ds:[esi] 00405076 . 51 push ecx 00405077 . 56 push esi 00405078 . FF90 2C070000 call ds:[eax+72C] 0040507E . 85C0 test eax,eax 00405080 . DBE2 fclex 00405082 . 7D 12 jge short T0RNAD0'.00405096 00405084 . 68 2C070000 push 72C 00405089 . 68 14404000 push T0RNAD0'.00404014 0040508E . 56 push esi 0040508F . 50 push eax 00405090 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00405096 > 8B45 B4 mov eax,ss:[ebp-4C] 00405099 . 8D4D DC lea ecx,ss:[ebp-24] 0040509C . 51 push ecx 0040509D . 50 push eax 0040509E . 8B10 mov edx,ds:[eax] 004050A0 . 8985 48FFFFFF mov ss:[ebp-B8],eax 004050A6 . FF92 A0000000 call ds:[edx+A0] 004050AC . 85C0 test eax,eax 004050AE . DBE2 fclex 004050B0 . 7D 18 jge short T0RNAD0'.004050CA 004050B2 . 8B95 48FFFFFF mov edx,ss:[ebp-B8] 004050B8 . 68 A0000000 push 0A0 004050BD . 68 7C414000 push T0RNAD0'.0040417C 004050C2 . 52 push edx 004050C3 . 50 push eax 004050C4 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 004050CA > 8B06 mov eax,ds:[esi] 004050CC . 8D4D B0 lea ecx,ss:[ebp-50] 004050CF . 51 push ecx 004050D0 . 56 push esi 004050D1 . FF90 2C070000 call ds:[eax+72C] 004050D7 . 85C0 test eax,eax 004050D9 . DBE2 fclex 004050DB . 7D 12 jge short T0RNAD0'.004050EF 004050DD . 68 2C070000 push 72C 004050E2 . 68 14404000 push T0RNAD0'.00404014 004050E7 . 56 push esi 004050E8 . 50 push eax 004050E9 . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 004050EF > 8B45 B0 mov eax,ss:[ebp-50] 004050F2 . 8D4D D0 lea ecx,ss:[ebp-30] 004050F5 . 51 push ecx 004050F6 . 50 push eax 004050F7 . 8B10 mov edx,ds:[eax] 004050F9 . 8985 3CFFFFFF mov ss:[ebp-C4],eax 004050FF . FF92 A0000000 call ds:[edx+A0] 00405105 . 85C0 test eax,eax 00405107 . DBE2 fclex 00405109 . 7D 18 jge short T0RNAD0'.00405123 0040510B . 8B95 3CFFFFFF mov edx,ss:[ebp-C4] 00405111 . 68 A0000000 push 0A0 00405116 . 68 7C414000 push T0RNAD0'.0040417C 0040511B . 52 push edx 0040511C . 50 push eax 0040511D . FF15 40104000 call ds:[<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 00405123 > 8B45 D0 mov eax,ss:[ebp-30] 00405126 . 6A 01 push 1 00405128 . 8945 98 mov ss:[ebp-68],eax 0040512B . 8D45 90 lea eax,ss:[ebp-70] 0040512E . 8D4D 80 lea ecx,ss:[ebp-80] 00405131 . 50 push eax 00405132 . 51 push ecx 00405133 . C745 A8 06000000 mov dword ptr ss:[ebp-58],6 0040513A . C745 A0 02000000 mov dword ptr ss:[ebp-60],2 00405141 . C745 D0 00000000 mov dword ptr ss:[ebp-30],0 00405148 . C745 90 08000000 mov dword ptr ss:[ebp-70],8 0040514F . FF15 40114000 call ds:[<&MSVBVM60.#619>] ; MSVBVM60.rtcRightCharVar 00405155 . 8D55 80 lea edx,ss:[ebp-80] 00405158 . 8D45 CC lea eax,ss:[ebp-34] 0040515B . 52 push edx 0040515C . 50 push eax 0040515D . FFD7 call edi 0040515F . 50 push eax 00405160 . FF15 30104000 call ds:[<&MSVBVM60.#516>] ; MSVBVM60.rtcAnsiValueBstr 00405166 . 8B56 40 mov edx,ds:[esi+40] |Mueve a EDX AAD077BF (Temp2) 00405169 . 68 90414000 push T0RNAD0'.00404190 ; UNICODE "L-" |Comienza el serial 0040516E . 0FBFC8 movsx ecx,ax |Mueve a ECX último dígito en ascii (34) 00405171 . 8B46 38 mov eax,ds:[esi+38] |Mueve a EAX 01CF19EA (Temp1) 00405174 . 53 push ebx 00405175 . 03D0 add edx,eax |AAD077BF + 01CF19EA = AC9F91A9 00405177 . C785 70FFFFFF 0300000>mov dword ptr ss:[ebp-90],3 00405181 . 0F80 B4040000 jo T0RNAD0'.0040563B 00405187 . 03CA add ecx,edx |AC9F91A9 + 34 = AC9F91DD (Nuestro serial) 00405189 . 0F80 AC040000 jo T0RNAD0'.0040563B 0040518F . 898D 78FFFFFF mov ss:[ebp-88],ecx 00405195 . FF15 04104000 call ds:[<&MSVBVM60.__vbaStrI2>] ; MSVBVM60.__vbaStrI2 0040519B . 8B3D 38114000 mov edi,ds:[<&MSVBVM60.__vbaStrMove>] ; MSVBVM60.__vbaStrMove 004051A1 . 8BD0 mov edx,eax 004051A3 . 8D4D E0 lea ecx,ss:[ebp-20] 004051A6 . FFD7 call edi ; <&MSVBVM60.__vbaStrMove> 004051A8 . 50 push eax |EAX = tamaño del nombre 004051A9 . FF15 38104000 call ds:[<&MSVBVM60.__vbaStrCat>] ; MSVBVM60.__vbaStrCat |Concatena con "L-" 004051AF . 8BD0 mov edx,eax 004051B1 . 8D4D BC lea ecx,ss:[ebp-44] 004051B4 . FFD7 call edi 004051B6 . 66:83EB 06 sub bx,6 |Tamaño nombre - 6 = 18 004051BA . 50 push eax 004051BB . 0F80 7A040000 jo T0RNAD0'.0040563B 004051C1 . 0FBFCB movsx ecx,bx 004051C4 . 898D 08FFFFFF mov ss:[ebp-F8],ecx 004051CA . 8D45 A0 lea eax,ss:[ebp-60] 004051CD . DB85 08FFFFFF fild dword ptr ss:[ebp-F8] 004051D3 . 68 9C414000 push T0RNAD0'.0040419C 004051D8 . 50 push eax 004051D9 . DD9D 00FFFFFF fstp qword ptr ss:[ebp-100] 004051DF . DD85 00FFFFFF fld qword ptr ss:[ebp-100] 004051E5 . 833D 00A04000 00 cmp dword ptr ds:[40A000],0 004051EC . 75 08 jnz short T0RNAD0'.004051F6 004051EE . DC35 78114000 fdiv qword ptr ds:[401178] |18 / 2 = C (C es la posición para cojer dígitos del nombre, coje 6) 004051F4 . EB 11 jmp short T0RNAD0'.00405207 004051F6 > FF35 7C114000 push dword ptr ds:[40117C] 004051FC . FF35 78114000 push dword ptr ds:[401178] 00405202 . E8 3DC0FFFF call <jmp.&MSVBVM60._adj_fdiv_m64> 00405207 > DFE0 fstsw ax 00405209 . A8 0D test al,0D 0040520B . 0F85 25040000 jnz T0RNAD0'.00405636 00405211 . FF15 44114000 call ds:[<&MSVBVM60.__vbaR8IntI4>] ; MSVBVM60.__vbaR8IntI4 00405217 . 8B55 DC mov edx,ss:[ebp-24] |EDX = nombre 0040521A . 50 push eax |Eax = C 0040521B . 52 push edx 0040521C . FF15 6C104000 call ds:[<&MSVBVM60.#631>] ; MSVBVM60.rtcMidCharBstr |Mid(nombre,C,6) = "lmnopq" 00405222 . 8BD0 mov edx,eax 00405224 . 8D4D D8 lea ecx,ss:[ebp-28] 00405227 . FFD7 call edi 00405229 . 8B1D 38104000 mov ebx,ds:[<&MSVBVM60.__vbaStrCat>] ; MSVBVM60.__vbaStrCat 0040522F . 50 push eax 00405230 . FFD3 call ebx ; <&MSVBVM60.__vbaStrCat> |Concatena "-lmnopq" 00405232 . 8BD0 mov edx,eax 00405234 . 8D4D D4 lea ecx,ss:[ebp-2C] 00405237 . FFD7 call edi 00405239 . 50 push eax 0040523A . 68 9C414000 push T0RNAD0'.0040419C 0040523F . FFD3 call ebx |Concatena "-lmnopq-" 00405241 . 8BD0 mov edx,eax 00405243 . 8D4D C4 lea ecx,ss:[ebp-3C] 00405246 . FFD7 call edi 00405248 . 50 push eax 00405249 . 8D85 70FFFFFF lea eax,ss:[ebp-90] 0040524F . 50 push eax 00405250 . FF15 F0104000 call ds:[<&MSVBVM60.#572>] ; MSVBVM60.rtcHexBstrFromVar |serial "AC9F91DD" 00405256 . 8BD0 mov edx,eax 00405258 . 8D4D C8 lea ecx,ss:[ebp-38] 0040525B . FFD7 call edi 0040525D . 50 push eax 0040525E . FF15 B4104000 call ds:[<&MSVBVM60.#713>] ; MSVBVM60.rtcStrReverse |Invierte el serial "DD19F9CA" 00405264 . 8BD0 mov edx,eax 00405266 . 8D4D C0 lea ecx,ss:[ebp-40] 00405269 . FFD7 call edi 0040526B . 50 push eax 0040526C . FFD3 call ebx |Concatena "-lmnopq-DD19F9CA" 0040526E . 8BD0 mov edx,eax 00405270 . 8D4D B8 lea ecx,ss:[ebp-48] 00405273 . FFD7 call edi 00405275 . 50 push eax 00405276 . FFD3 call ebx |Concatena "L-30-lmnopq-DD19F9CA" ... 00405334 . FF15 80104000 call ds:[<&MSVBVM60.__vbaStrCmp>] ; MSVBVM60.__vbaStrCmp |Comparación final
Ejemplos:
Nombre: abcdefghijklmnopqrstuvwxyz1234 Serial: L-30-lmnopq-DD19F9CA Nombre: deurus2014 Serial: L-10-eurus2-84D8F9CA
Al descargar la imagen de la web del reto vemos que tiene la extensión php y lo más probable es que no nos abra correctamente.
... <br/> <img src="steg1img.php"/> <br/> ...
Abrimos la imagen con nuestro editor hexadecimal favorito y nos fijamos en la cabecera.
00000000h: 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 ; ‰PNG........IHDR
Renombramos entonces la extensión a png y continuamos.
Esta parte la afrontaremos con Steganabara, una herramienta muy útil que siempre uso cuando me enfrento a un reto «stego». En esta ocasión utilizaremos el análisis de color. Para ello pulsamos sobre «Analyse > Color table«.
En la tabla de colores tenemos la descomposición de colores RGBA y su frecuencia de aparición. Ordenamos por frecuencia descendiente y hacemos doble clic sobre la fila para abrir la imagen resultante.
A continuación un resumen de las imágenes obtenidas.
Como podéis observar, la imagen oculta es un código QR. Lo escaneamos con nuestra app preferida y obtenemos un texto encriptado.
dtsfwqutisvqtesymkuvabbujwhfecuvlshwopcyeghguywjvlaibflcacyahckyqvypjntfhihgtvyxeqakjwouldltuiuhbhjumgkxuugqahvwhotduqtahcknheypjetxpvlhxtlrpjagyjzcgijgfjmcupsslkzpuxegaillytlfbygeptzjtuzlvlwkzdznxqwpabbe
A partir de aquí el reto pasa a ser de encriptación. Con el tiempo diferenciareis fácilmente el tipo de cifrado con sólo ver el texto. En este caso lo primero que se nos ocurre es comprobar dos cifrados clásicos como son el cifrado César y el Vigenere.
Tras desestimar el cifrado César realizamos un ataque de «fuerza bruta» al cifrado Vigenere mediante análisis estadístico. En la imagen que muestro a continuación se puede ver que la clave está cerca de ser «HPHQTC» pero todavía no se lee correctamente.
Ya que la fuerza bruta de por sí no termina de darnos la respuesta correcta, pasamos a probar algo muy útil, esto es, descifrar por fuerza bruta pero dándole una palabra para comparar. En este caso en concreto vemos que una posible palabra que pudiera estar en el texto encriptado es «PASSWORD», probamos y reto terminado.
Hace poco me puse a leer El oscuro pasajero de Jeff Lindsay, novela que inspiró la serie Dexter. La nostalgia me invadió y al final decidí volver a ver la primera temporada que tanto me gustó hace unos años. Para mi sorpresa, muchos de los detalles que recordaba de la serie eran incorrectos o incompletos. Bueno, el caso es que en esta ocasión me he fijado más en los detalles y he descubierto una pequeña perla en el capítulo 8 de la primera temporada.
ALERTA DE SPOILER: Aunque la serie tiene unos añitos no quisiera fastidiarsela a nadie. Si continuas leyendo puede que te enteres de algo que no quieras.
En un momento dado, a Dexter se le ocurre la feliz idea de contactar con el asesino en serie que le está dejando regalitos y no se le ocurre mejor idea que hacerlo en una web de contactos cualquiera. La web en cuestión es www.miamilist12.com/miami/main y Dexter decide escribir un mensaje en el hilo missed connections. A continuación la secuencia de imágenes.
La simple idea de escribir en un tablón, foro, lista, etc y esperar que el asesino en serie lo lea ya es una locura. Pero señor@s, esto es ficción, y por supuesto el asesino no solo ve el mensaje si no que responde a Dexter creando un pequeño error con las direcciones de email. Y es que cuando el asesino ve el mensaje se puede apreciar que la dirección de email de Dexter es frozenbarbie@hotmail.web y cuando el asesino le responde, se ve claramente que lo hace a la dirección frozenbarbie@hotmail.com. A continuación las imágenes.
Además me ha llamado la atención que aunque es evidente que el asesino usa Windows XP, se puede apreciar que han retocado en post-producción el botón de inicio para que quede oculto.
Nos vemos en el siguiente BTM.
Se nos entrega el siguiente ELF:
/* This file was generated by the Hex-Rays decompiler version 8.4.0.240320.
Copyright (c) 2007-2021 Hex-Rays <info@hex-rays.com>
Detected compiler: GNU C++
*/
#include <defs.h>
//-------------------------------------------------------------------------
// Function declarations
__int64 (**init_proc())(void);
void sub_1020();
// int printf(const char *format, ...);
// int getchar(void);
// int fflush(FILE *stream);
// __int64 __isoc99_scanf(const char *, ...); weak
// void __noreturn exit(int status);
// int __fastcall _cxa_finalize(void *);
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void));
FILE **deregister_tm_clones();
__int64 register_tm_clones(); // weak
FILE **_do_global_dtors_aux();
__int64 __fastcall frame_dummy(_QWORD, _QWORD, _QWORD); // weak
int __fastcall main(int argc, const char **argv, const char **envp);
_BOOL8 __fastcall comprobacion(char a1, char a2, int a3);
void _libc_csu_fini(void); // idb
void term_proc();
// int __fastcall _libc_start_main(int (__fastcall *main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void *stack_end);
// int __fastcall __cxa_finalize(void *);
// __int64 _gmon_start__(void); weak
//-------------------------------------------------------------------------
// Data declarations
_UNKNOWN _libc_csu_init;
__int64 (__fastcall *_frame_dummy_init_array_entry)() = &frame_dummy; // weak
__int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)() = &_do_global_dtors_aux; // weak
void *_dso_handle = &_dso_handle; // idb
char *a = "MdfnJk"; // weak
char *b = "jYx}"; // weak
char *c = "gWmfk"; // weak
char *d = "mlvpc"; // weak
char *f = "neU++w"; // weak
FILE *_bss_start; // idb
char completed_0; // weak
//----- (0000000000001000) ----------------------------------------------------
__int64 (**init_proc())(void)
{
__int64 (**result)(void); // rax
result = &_gmon_start__;
if ( &_gmon_start__ )
return (__int64 (**)(void))_gmon_start__();
return result;
}
// 40D0: using guessed type __int64 _gmon_start__(void);
//----- (0000000000001020) ----------------------------------------------------
void sub_1020()
{
JUMPOUT(0LL);
}
// 1026: control flows out of bounds to 0
//----- (0000000000001090) ----------------------------------------------------
// positive sp value has been detected, the output may be wrong!
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void))
{
__int64 v3; // rax
int v4; // esi
__int64 v5; // [rsp-8h] [rbp-8h] BYREF
char *retaddr; // [rsp+0h] [rbp+0h] BYREF
v4 = v5;
v5 = v3;
_libc_start_main(
(int (__fastcall *)(int, char **, char **))main,
v4,
&retaddr,
(void (*)(void))_libc_csu_init,
_libc_csu_fini,
a3,
&v5);
__halt();
}
// 1096: positive sp value 8 has been found
// 109D: variable 'v3' is possibly undefined
//----- (00000000000010C0) ----------------------------------------------------
FILE **deregister_tm_clones()
{
return &_bss_start;
}
//----- (00000000000010F0) ----------------------------------------------------
__int64 register_tm_clones()
{
return 0LL;
}
// 10F0: using guessed type __int64 register_tm_clones();
//----- (0000000000001130) ----------------------------------------------------
FILE **_do_global_dtors_aux()
{
FILE **result; // rax
if ( !completed_0 )
{
if ( &__cxa_finalize )
_cxa_finalize(_dso_handle);
result = deregister_tm_clones();
completed_0 = 1;
}
return result;
}
// 4080: using guessed type char completed_0;
//----- (0000000000001175) ----------------------------------------------------
int __fastcall main(int argc, const char **argv, const char **envp)
{
char v4; // [rsp+7h] [rbp-9h] BYREF
int v5; // [rsp+8h] [rbp-8h]
bool v6; // [rsp+Fh] [rbp-1h]
v6 = 1;
v5 = 0;
while ( v6 )
{
fflush(_bss_start);
printf("\nIntroduce la letra correcta:\t");
__isoc99_scanf("%c", &v4);
getchar();
if ( v5 > 5 )
{
if ( v5 > 9 )
{
if ( v5 > 14 )
{
if ( v5 > 19 )
v6 = comprobacion(v4, f[v5 - 20], 10);
else
v6 = comprobacion(v4, d[v5 - 15], 2);
}
else
{
v6 = comprobacion(v4, c[v5 - 10], 8);
}
}
else
{
v6 = comprobacion(v4, b[v5 - 6], 17);
}
}
else
{
v6 = comprobacion(v4, a[v5], 5);
}
if ( !v6 )
{
printf("Incorrecta");
exit(1);
}
printf("\n%c\n", (unsigned int)v4);
if ( v5 == 25 )
{
printf("Ya tienes la flag!!");
exit(1);
}
++v5;
}
return 0;
}
// 1060: using guessed type __int64 __isoc99_scanf(const char *, ...);
// 4050: using guessed type char *a;
// 4058: using guessed type char *b;
// 4060: using guessed type char *c;
// 4068: using guessed type char *d;
// 4070: using guessed type char *f;
//----- (0000000000001352) ----------------------------------------------------
_BOOL8 __fastcall comprobacion(char a1, char a2, int a3)
{
return a1 == (a3 ^ a2);
}
//----- (0000000000001390) ----------------------------------------------------
void __fastcall _libc_csu_init(unsigned int a1, __int64 a2, __int64 a3)
{
signed __int64 v4; // rbp
__int64 i; // rbx
init_proc();
v4 = &_do_global_dtors_aux_fini_array_entry - &_frame_dummy_init_array_entry;
if ( v4 )
{
for ( i = 0LL; i != v4; ++i )
((void (__fastcall *)(_QWORD, __int64, __int64))*(&_frame_dummy_init_array_entry + i))(a1, a2, a3);
}
}
// 1170: using guessed type __int64 __fastcall frame_dummy(_QWORD, _QWORD, _QWORD);
// 3DE8: using guessed type __int64 (__fastcall *_frame_dummy_init_array_entry)();
// 3DF0: using guessed type __int64 (__fastcall *_do_global_dtors_aux_fini_array_entry)();
//----- (00000000000013F4) ----------------------------------------------------
void term_proc()
{
;
}
Si nos fijamos en las líneas 41 a la 45 vemos las siguientes cadenas:
a = «MdfnJk»
b = «jYx}»
c = «gWmfk»
d = «mlvpc»
f = «neU++w»
Usaremos las cadenas y los valores XOR especificados para cada rango de v5 en el main (líneas 123 a 182) para determinar los caracteres correctos.
Para v5 de 0 a 5: v6 = comprobacion(v4, a[v5], 5);
Significa que: v4 debe ser igual a a[v5] ^ 5
Para v5 de 6 a 9: v6 = comprobacion(v4, b[v5 – 6], 17);
Significa que: v4 debe ser igual a b[v5 – 6] ^ 17
Para v5 de 10 a 14: v6 = comprobacion(v4, c[v5 – 10], 8);
Significa que: v4 debe ser igual a c[v5 – 10] ^ 8
Para v5 de 15 a 19: v6 = comprobacion(v4, d[v5 – 15], 2);
Significa que: v4 debe ser igual a d[v5 – 15] ^ 2
Para v5 de 20 a 25: v6 = comprobacion(v4, f[v5 – 20], 10);
Significa que: v4 debe ser igual a f[v5 – 20] ^ 10
Cálculo de los caracteres correctos:
Para v5 de 0 a 5:
a[0] = ‘M’, M ^ 5 = 0x4D ^ 0x05 = 0x48 -> ‘H’
a[1] = ‘d’, d ^ 5 = 0x64 ^ 0x05 = 0x61 -> ‘a’
a[2] = ‘f’, f ^ 5 = 0x66 ^ 0x05 = 0x63 -> ‘c’
a[3] = ‘n’, n ^ 5 = 0x6E ^ 0x05 = 0x6B -> ‘k’
a[4] = ‘J’, J ^ 5 = 0x4A ^ 0x05 = 0x4F -> ‘O’
a[5] = ‘k’, k ^ 5 = 0x6B ^ 0x05 = 0x6E -> ‘n’
Resulta en la cadena: HackOn
Para v5 de 6 a 9:
b[0] = ‘j’, j ^ 17 = 0x6A ^ 0x11 = 0x7B -> ‘{‘
b[1] = ‘Y’, Y ^ 17 = 0x59 ^ 0x11 = 0x48 -> ‘H’
b[2] = ‘x’, x ^ 17 = 0x78 ^ 0x11 = 0x69 -> ‘i’
b[3] = ‘}’, } ^ 17 = 0x7D ^ 0x11 = 0x6C -> ‘l’
Resulta en la cadena: {Hil
Para v5 de 10 a 14:
c[0] = ‘g’, g ^ 8 = 0x67 ^ 0x08 = 0x6F -> ‘o’
c[1] = ‘W’, W ^ 8 = 0x57 ^ 0x08 = 0x5F -> ‘_’
c[2] = ‘m’, m ^ 8 = 0x6D ^ 0x08 = 0x65 -> ‘e’
c[3] = ‘f’, f ^ 8 = 0x66 ^ 0x08 = 0x6E -> ‘n’
c[4] = ‘k’, k ^ 8 = 0x6B ^ 0x08 = 0x63 -> ‘c’
Resulta en la cadena: o_enc
Para v5 de 15 a 19:
d[0] = ‘m’, m ^ 2 = 0x6D ^ 0x02 = 0x6F -> ‘o’
d[1] = ‘l’, l ^ 2 = 0x6C ^ 0x02 = 0x6E -> ‘n’
d[2] = ‘v’, v ^ 2 = 0x76 ^ 0x02 = 0x74 -> ‘t’
d[3] = ‘p’, p ^ 2 = 0x70 ^ 0x02 = 0x72 -> ‘r’
d[4] = ‘c’, c ^ 2 = 0x63 ^ 0x02 = 0x61 -> ‘a’
Resulta en la cadena: ontra
Para v5 de 20 a 25:
f[0] = ‘n’, n ^ 10 = 0x6E ^ 0x0A = 0x64 -> ‘d’
f[1] = ‘e’, e ^ 10 = 0x65 ^ 0x0A = 0x6F -> ‘o’
f[2] = ‘U’, U ^ 10 = 0x55 ^ 0x0A = 0x5F -> ‘_‘
f[3] = ‘+’, + ^ 10 = 0x2B ^ 0x0A = 0x21 -> ‘!’
f[4] = ‘+’, + ^ 10 = 0x2B ^ 0x0A = 0x21 -> ‘!’
f[5] = ‘w’, w ^ 10 = 0x77 ^ 0x0A = 0x7D -> ‘}’
Resulta en la cadena: do_!!}
Uniendo todas las partes, obtenemos la flag completa: HackOn{Hilo_enc_ontrado_!!}
Warning: This challenge is still active and therefore should not be resolved using this information.
Aviso: Este reto sigue en activo y por lo tanto no se debería resolver utilizando esta información.
Echamos un vistazo a la web y lo único interesante que vemos es un buscador.
Miramos el código fuente y vemos una ruta interesante.
Ahora fijémonos en el menú productos. Pinchamos sobre cualquier producto y a continuación en la imagen para ampliarla, veremos el siguiente enlace.
Vamos a ver si podemos explotar «i.php«. Probamos a obtener información sensible del servidor.
Probamos «http://www.thisislegal.com/nc/i.php?img=adm/login.pwd» y nos da error, seguramente por que está anexionando la extensión de la imagen, es decir, el script está interpretando esto:
Vamos a anularlo con un caracter nulo. Probamos y ahora si.
El password está en base64. Lo decodificamos online, nos logueamos y reto superado.