Mes: agosto 2014
Reto forense de HackThis!!
Intro
We require your services once again. An employee from our company had recently been identified as a known criminal named Brett Thwaits. He is considered to have stolen missile launch codes from the US navy which unfortunately were handed to us for a brief period of time. As of now, we are accussed of the theft and unless we do something about it, we’re gonna end in some serious trouble. Before Brett left, he formatted the thumbdrive which used to store the launch codes. Fortunately, our system had made a backup image of the drive. See if you can recover the fourth launch code. Good luck!
Requerimos una vez más sus servicios. Un empleado de nuestra empresa había sido identificado recientemente como el conocido criminal Brett Thwaites. Se considera que ha robado los códigos de lanzamiento de misiles de la Armada de Estados Unidos, que por desgracia fueron entregados a nosotros por un breve período de tiempo. A partir de ahora, se nos acusa del robo y a menos que hagamos algo al respecto, vamos a tener serios problemas. Antes de que Brett se fuera formateó el dispositivo que se usa para almacenar los códigos de lanzamiento. Afortunadamente, nuestro sistema había hecho una copia de seguridad de la unidad. Mira a ver si puedes recuperar los cuatro códigos de lanzamiento. ¡Buena suerte!
Análisis del archivo
- Fichero: forensics1
- Extensión: img
- Tamaño: 25 MB (26.214.400 bytes)
- Hash MD5: 56e4cd5b8f076ba8b7c020c7339caa2b
Echamos un vistazo al archivo con un editor hexadecimal y vemos encabezados de tipos de archivos conocidos, por lo que la unidad no está encriptada. Al no estar encriptada la imagen, usaremos una herramienta de creación propia, Ancillary. En esta ocasión usaremos la versión 2 alpha, que actualmente está en desarrollo, pero podéis usar tranquilamente la versión 1.x.
Ancillary nos muestra lo que ha encontrado en el archivo por lo que pasamos a analizarlo.
Como siempre os digo en este tipo de retos, es difícil discriminar unos ficheros en favor de otros, ya que no sabemos si lo que buscamos va a estar en una imagen, documento u otro tipo de fichero codificado o no.
Tras analizar todos los ficheros, rápidamente suscitan nuestro interés los ficheros RAR, y más cuando el fichero que contienen es un fichero de audio y su nombre es tan sugerente como «conversation_dtmf.wav«. Como podéis apreciar en la imagen, el fichero RAR está protegido con clave por lo que necesitamos esquivar ese obstaculo.
Recuperando una clave de un archivo RAR
En este caso el software que voy a utilizar es cRARk, pero podéis utilizar cualquier otro. Como se muestra en la imagen de abajo, mi procesador es más bien modesto pero la clave no tiene más que tres dígitos por lo que no supone ninguna dificultad recuperarla.
DTMF (Dual-Tone Multi-Frequency)
Una vez recuperado el archivo WAV, al reproducirlo escuchamos 16 tonos telefónicos que inmediatamente me recuerdan las aventuras del mítico «Capitán Crunch«. Os animo a leer la historia de John Draper y su famosa «Blue Box» ya que no tiene desperdicio y forma parte de la historia del Phreaking.
Por si no conocías la historia, el propio nombre del fichero wav nos da la pista clave de qué buscar al contener las siglas «DTMF«.
Al ser pulsada en el teléfono la tecla correspondiente al dígito que quiere marcar, se envían dos tonos, de distinta frecuencia: uno por columna y otro por fila en la que esté la tecla, que la central decodifica a través de filtros especiales, detectando qué dígito se marcó.
No tenemos más que buscar un decodificador de tonos para obtener los preciados códigos de lanzamiento.
Links
Cruehead’s Crackme 2.0 Serial [2/3]
Introducción
Continuamos con la segunda entrega de Cruehead. En este caso nos encontramos con un único campo de contraseña para introducir.
El algoritmo
Abrimos con Olly y vemos dos saltos. El primer Call realiza una serie de operaciones con el serial introducido y el segundo comprueba si el serial es correcto.
A continuación llegamos aquí:
00401365 /$ C605 18214000 00 MOV BYTE PTR DS:[402118],0 0040136C |. 8B7424 04 MOV ESI,DWORD PTR SS:[ESP+4] 00401370 |. 56 PUSH ESI 00401371 |> 8A06 /MOV AL,BYTE PTR DS:[ESI] ; <--- 00401373 |. 84C0 |TEST AL,AL 00401375 |. 74 19 |JE SHORT CRACKME2.00401390 00401377 |. FE05 18214000 |INC BYTE PTR DS:[402118] 0040137D |. 3C 41 |CMP AL,41 ; 41 = A 0040137F |. 72 04 |JB SHORT CRACKME2.00401385 ; ya es mayúscula 00401381 |. 3C 5A |CMP AL,5A ; 5A = Z 00401383 |. 73 03 |JNB SHORT CRACKME2.00401388 ; Convertir a mayúscula 00401385 |> 46 |INC ESI 00401386 |.^ EB E9 |JMP SHORT CRACKME2.00401371 ; Bucle --> 00401388 |> E8 25000000 |CALL CRACKME2.004013B2 0040138D |. 46 |INC ESI 0040138E |.^ EB E1 \JMP SHORT CRACKME2.00401371 00401390 |> 5E POP ESI 00401391 |. E8 03000000 CALL CRACKME2.00401399 ;Convertido a mayúsculas continuamos 00401396 |. EB 00 JMP SHORT CRACKME2.00401398 00401398 \> C3 RETN
Si nuestro serial contiene solo letras, las convierte a mayúsculas y seguimos aquí. En resumen hace XOR byte a byte entre nuestro serial y la frase «Messing_in_bytes»
00401399 /$ 33DB XOR EBX,EBX 0040139B |. 33FF XOR EDI,EDI 0040139D |> 8A8F A3214000 /MOV CL,BYTE PTR DS:[EDI+4021A3] ; Carga el primer byte de 4021A3 004013A3 |. 8A1E |MOV BL,BYTE PTR DS:[ESI] ; 004013A5 |. 84DB |TEST BL,BL 004013A7 |. 74 08 |JE SHORT CRACKME2.004013B1 004013A9 |. 32D9 |XOR BL,CL ; byteSerial XOR Byte"Messing_in..." 004013AB |. 881E |MOV BYTE PTR DS:[ESI],BL 004013AD |. 46 |INC ESI ;Siguiente byte de "Messing_in_bytes" 004013AE |. 47 |INC EDI ;Siguiente byte del serial 004013AF |.^ EB EC \JMP SHORT CRACKME2.0040139D 004013B1 \> C3 RETN ;XOR finalizado volvemos
Estado del DUMP (memoria) antes del XOR y con nuestro serial (12345678) cargado.
00402118 00 47 6F 6F 64 20 77 6F 72 6B 21 00 47 72 65 61 .Good work!.Grea 00402128 74 20 77 6F 72 6B 2C 20 6D 61 74 65 21 0D 4E 6F t work, mate!.No 00402138 77 20 74 72 79 20 74 68 65 20 6E 65 78 74 20 43 w try the next C 00402148 72 61 63 6B 4D 65 21 00 1F 2C 37 36 3B 3D 28 19 rackMe!.,76;=( 00402158 3D 26 1A 31 2D 3B 37 3E 4E 6F 20 6C 75 63 6B 21 =&1-;7>No luck! 00402168 00 4E 6F 20 6C 75 63 6B 20 74 68 65 72 65 2C 20 .No luck there, 00402178 6D 61 74 65 21 00 31 32 33 34 35 36 37 38 39 00 mate!.123456789. 00402188 00 00 00 00 00 00 00 00 00 00 54 72 79 20 74 6F ..........Try to 00402198 20 63 72 61 63 6B 20 6D 65 21 00 4D 65 73 73 69 crack me!.Messi 004021A8 6E 67 5F 69 6E 5F 62 79 74 65 73 00 00 00 00 00 ng_in_bytes.....
Estado del DUMP después del XOR.
00402118 0A 47 6F 6F 64 20 77 6F 72 6B 21 00 47 72 65 61 .Good work!.Grea 00402128 74 20 77 6F 72 6B 2C 20 6D 61 74 65 21 0D 4E 6F t work, mate!.No 00402138 77 20 74 72 79 20 74 68 65 20 6E 65 78 74 20 43 w try the next C 00402148 72 61 63 6B 4D 65 21 00 1F 2C 37 36 3B 3D 28 19 rackMe!.,76;=( 00402158 3D 26 1A 31 2D 3B 37 3E 4E 6F 20 6C 75 63 6B 21 =&1-;7>No luck! 00402168 00 4E 6F 20 6C 75 63 6B 20 74 68 65 72 65 2C 20 .No luck there, 00402178 6D 61 74 65 21 00 7C 57 40 47 5C 58 50 67 50 5E mate!.|W@G\XPgP^ 00402188 00 00 00 00 00 00 00 00 00 00 54 72 79 20 74 6F ..........Try to 00402198 20 63 72 61 63 6B 20 6D 65 21 00 4D 65 73 73 69 crack me!.Messi 004021A8 6E 67 5F 69 6E 5F 62 79 74 65 73 ng_in_bytes
A continuación comprueba nuestro serial XOReado con los bytes en memoria.
004013B8 /$ 33FF XOR EDI,EDI 004013BA |. 33C9 XOR ECX,ECX 004013BC |. 8A0D 18214000 MOV CL,BYTE PTR DS:[402118] 004013C2 |. 8B7424 04 MOV ESI,DWORD PTR SS:[ESP+4] ; APUNTA AL DUMP 40217E 004013C6 |. BF 50214000 MOV EDI,CRACKME2.00402150 ; APUNTA AL DUMP 402150 004013CB |. F3:A6 REPE CMPS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; VER NOTA** 004013CD \. C3 RETN
Nota**
Si buscamos el comando REPE encontramos que si el flag Z = 1 el bucle se corta y que trabaja con bytes. El problema es que en Olly la instrucción REPE nosotros la vemos con un solo paso y nos puede pasar desapercibida.
En resumen, está comprobando los bytes de las direcciones 402150 (1F 2C 37 36 3B 3D 28 19 3D 26 1A 31 2D 3B 37 3E) con nuestro serial XOReado, 40217E en adelante, por lo que si hacemos XOR entre los bytes de 402150 y la frase «Messing_in_bytes» obtendremos la clave correcta.
M e s s i n g _ i n _ b y t e s
4D 65 73 73 69 6E 67 5F 69 6E 5F 62 79 74 65 73
XOR
1F 2C 37 36 3B 3D 28 19 3D 26 1A 31 2D 3B 37 3E
-----------------------------------------------
52 49 44 45 52 53 4F 46 54 48 45 53 54 4F 52 4D
R I D E R S O F T H E S T O R M
Serial: RIDERSOFTHESTORM
Links
Protegido: Reto Crypt-art de Root-Me.org
Crudd’s Splish Splash KeyGen
Intro
Hoy tenemos un crackme hecho en ensamblador y que cuenta con tres niveles. En el primero de todos nos enfrentamos a una «Splash screen» o nag. El segundo en un serial Hardcodeado y el tercero un número de serie asociado a un nombre.
Nopeando la Splash Screen
Abrimos el crackme con Olly y vamos a las «Intermodular Calls«, enseguida vemos la función que crea las ventanas «CreateWindowExA«. Se puede ver lo que parece ser la creación de la pantalla del crackme y al final hay algo que salta a la vista y es la propiedad «WS_TOPMOST», es decir, que se mantenga delante del resto de ventanas.
Pinchamos sobre la función y vamos a parar aquí.
Vemos la llamada a CreateWindowExA que podríamos parchear pero vamos a pensar un poco. Vemos la función GetTickCount y que carga el valor 7D0. 7D0 es 2000 en decimal, que perfectamente pueden ser milisegundos, por lo tanto el parcheo más elegante sería poner la función GetTickCount a 0. En la imagen inferior se puede ver como queda parcheado el valor 7D0.
Probamos y funciona, pasamos a lo siguiente.
Serial Hardcodeado
El mensaje de error del serial hardcodeado dice «Sorry, please try again». Lo buscamos en las string references y vamos a parar aquí.
Vemos un bucle de comparación que carga unos bytes de la memoria, los bytes dicen «HardCoded«, probamos y prueba superada.
El nombre y número de serie
Con el mismo método de las string references localizamos el código que nos interesa. Metemos deurus como nombre y 12345 como serial y empezamos a tracear. Lo primero que hace es una serie de operaciones con nuestro nombre a las que podemos llamar aritmética modular. Aunque en la imagen viene bastante detallado se vé mejor con un ejemplo.
Ejemplo para Nombre: deurus
d e u r u s 64 65 75 72 75 73 -hex 100 101 117 114 117 115 -dec 1ºByte = ((Nombre[0] % 10)^0)+2 2ºByte = ((Nombre[1] % 10)^1)+2 3ºByte = ((Nombre[2] % 10)^2)+2 4ºByte = ((Nombre[3] % 10)^3)+2 5ºByte = ((Nombre[4] % 10)^4)+2 6ºByte = ((Nombre[5] % 10)^5)+2 1ºByte = ((100 Mod 10) Xor 0) + 2 2ºByte = ((101 Mod 10) Xor 1) + 2 3ºByte = ((117 Mod 10) Xor 2) + 2 4ºByte = ((114 Mod 10) Xor 3) + 2 5ºByte = ((117 Mod 10) Xor 4) + 2 6ºByte = ((115 Mod 10) Xor 5) + 2 Si el byte > 10 --> Byte = byte - 10 1ºByte = 2 2ºByte = 2 3ºByte = 7 4ºByte = 9 5ºByte = 5 6ºByte = 2
Lo que nos deja que los Bytes mágicos para deurus son: 227952.
Debido a la naturaleza de la operación IDIV y el bucle en general, llegamos a la conclusión de que para cada letra es un solo byte mágico y que este está comprendido entre 0 y 9.
A continuación realiza las siguientes operaciones con el serial introducido.
Ejemplo para serial: 12345
1 2 3 4 5 31 32 33 34 35 -hex 49 50 51 52 53 -dec 49 mod 10 = 9 50 mod 10 = 0 51 mod 10 = 1 52 mod 10 = 2 53 mod 10 = 3
Los bytes mágicos del serial son: 90123, que difieren bastante de los conseguidos con el nombre.
A continuación compara byte a byte 227952 con 90123.
En resumen, para cada nombre genera un código por cada letra y luego la comprobación del serial la realiza usando el módulo 10 del dígito ascii. Lo primero que se me ocurre es que necesitamos cotejar algún dígito del 0 al 9 para tener cubiertas todas las posibilidades. Realizamos manualmente mod 10 a los números del 0 al 9 y obtenemos sus valores.
(0) 48 mod 10 = 8 (1) 49 mod 10 = 9 (2) 50 mod 10 = 0 (3) 51 mod 10 = 1 (4) 52 mod 10 = 2 (5) 53 mod 10 = 3 (6) 54 mod 10 = 4 (7) 55 mod 10 = 5 (8) 56 mod 10 = 6 (9) 57 mod 10 = 7
Con esto ya podríamos generar un serial válido.
0123456789 - Nuestro alfabeto numérico 8901234567 - Su valor Mod 10
Por lo que para deurus un serial válido sería: 449174. Recordemos que los bytes mágicos para deurus eran «227952», solo hay que sustituir.
Para realizar un KeyGen más interesante, he sacado los valores de un alfabeto mayor y le he añadido una rutina aleatoria para que genere seriales diferentes para un mismo nombre.
'abcdefghijklmnñppqrstuvwxyz0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ - Alfabeto
'7890123456778901234567789018901234567567890123455678901234556880 - Valor
Dim suma As Integer = 0
'Para hacer el serial más divertido
Dim brute() As String = {"2", "3", "4", "5", "6", "7", "8", "9", "0", "1"}
Dim brute2() As String = {"d", "e", "f", "g", "h", "i", "j", "a", "b", "c"}
Dim brute3() As String = {"P", "Q", "R", "S", "T", "U", "j", "a", "D", "E"}
Dim alea As New Random()
txtserial.Text = ""
'Evito nombres mayores de 11 para evitar el BUG comentado en le manual
If Len(txtnombre.Text) > 0 And Len(txtnombre.Text) < 12 Then
For i = 1 To Len(txtnombre.Text)
Dim aleatorio As Integer = alea.Next(0, 9)
suma = (((Asc(Mid(txtnombre.Text, i, 1))) Mod 10) Xor i - 1) + 2
If suma > 9 Then
suma = suma - 10
End If
If (aleatorio) >= 0 And (aleatorio) <= 4 Then
txtserial.Text = txtserial.Text & brute(suma)
ElseIf (aleatorio) > 4 And (aleatorio) <= 7 Then
txtserial.Text = txtserial.Text & brute2(suma)
ElseIf (aleatorio) > 7 And (aleatorio) <= 10 Then
txtserial.Text = txtserial.Text & brute3(suma)
End If
suma = 0
Next
Else
txtserial.Text = "El Nombre..."
End If
Notas finales
Hay un pequeño bug en el almacenaje del nombre y serial y en el guardado de bytes mágicos del serial. Si nos fijamos en los bucles del nombre y el serial, vemos que los bytes mágicos del nombre los guarda a partir de la dirección de memoria 403258 y los bytes mágicos del serial a partir de 40324D. En la siguiente imagen podemos ver seleccionados los 11 primeros bytes donde se almacenan los bytes mágicos del serial. Vemos que hay seleccionados 11 bytes y que el siguiente sería ya 403258, precisamente donde están los bytes mágicos del nombre. Como puedes imaginar si escribes un serial >11 dígitos se solapan bytes y es una chapuza, de modo que el keygen lo he limitado a nombres de 11 dígitos.
Links
lost_in_bin
Estamos ante un ELF un poco más interesante que los vistos anteriormente. Básicamente porque es divertido y fácil encontrar la solución en el decompilado y quizá por evocar recuerdos de tiempos pretéritos.
ELF Decompilado
/* 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);
__int64 sub_400650(); // weak
// int printf(const char *format, ...);
// int puts(const char *s);
// void __noreturn exit(int status);
// size_t strlen(const char *s);
// __int64 __fastcall MD5(_QWORD, _QWORD, _QWORD); weak
// int sprintf(char *s, const char *format, ...);
// __int64 ptrace(enum __ptrace_request request, ...);
// __int64 strtol(const char *nptr, char **endptr, int base);
// __int64 __isoc99_scanf(const char *, ...); weak
// int memcmp(const void *s1, const void *s2, size_t n);
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void));
void *sub_400730();
__int64 sub_400760();
void *sub_4007A0();
__int64 sub_4007D0();
void 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);
// __int64 _gmon_start__(void); weak
//-------------------------------------------------------------------------
// Data declarations
_UNKNOWN main;
_UNKNOWN init;
__int64 (__fastcall *funcs_400E29)() = &sub_4007D0; // weak
__int64 (__fastcall *off_601DF8)() = &sub_4007A0; // weak
__int64 (*qword_602010)(void) = NULL; // weak
char *off_602080 = "FLAG-%s\n"; // idb
char a7yq2hryrn5yJga[16] = "7Yq2hrYRn5Y`jga"; // weak
const char aO6uH[] = "(O6U,H\""; // idb
_UNKNOWN unk_6020B8; // weak
_UNKNOWN unk_6020C8; // weak
char byte_6020E0; // weak
char s1; // idb
char byte_602110[]; // weak
char byte_602120[33]; // weak
char byte_602141[7]; // idb
__int64 qword_602148; // weak
__int64 qword_602150; // weak
__int64 qword_602158; // weak
__int64 qword_602160; // weak
__int64 qword_602178; // weak
//----- (0000000000400630) ----------------------------------------------------
__int64 (**init_proc())(void)
{
__int64 (**result)(void); // rax
result = &_gmon_start__;
if ( &_gmon_start__ )
return (__int64 (**)(void))_gmon_start__();
return result;
}
// 6021D8: using guessed type __int64 _gmon_start__(void);
//----- (0000000000400650) ----------------------------------------------------
__int64 sub_400650()
{
return qword_602010();
}
// 400650: using guessed type __int64 sub_400650();
// 602010: using guessed type __int64 (*qword_602010)(void);
//----- (0000000000400700) ----------------------------------------------------
// 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))init, fini, a3, &v5);
__halt();
}
// 400706: positive sp value 8 has been found
// 40070D: variable 'v3' is possibly undefined
//----- (0000000000400730) ----------------------------------------------------
void *sub_400730()
{
return &unk_6020C8;
}
//----- (0000000000400760) ----------------------------------------------------
__int64 sub_400760()
{
return 0LL;
}
//----- (00000000004007A0) ----------------------------------------------------
void *sub_4007A0()
{
void *result; // rax
if ( !byte_6020E0 )
{
result = sub_400730();
byte_6020E0 = 1;
}
return result;
}
// 6020E0: using guessed type char byte_6020E0;
//----- (00000000004007D0) ----------------------------------------------------
__int64 sub_4007D0()
{
return sub_400760();
}
//----- (00000000004007D7) ----------------------------------------------------
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rax
size_t v4; // rax
int i; // [rsp+1Ch] [rbp-24h]
int n; // [rsp+20h] [rbp-20h]
int m; // [rsp+24h] [rbp-1Ch]
int k; // [rsp+28h] [rbp-18h]
int j; // [rsp+2Ch] [rbp-14h]
if ( ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL) == -1 )
goto LABEL_2;
if ( a1 > 4 )
{
qword_602148 = strtol(a2[1], 0LL, 10);
if ( qword_602148 )
{
qword_602150 = strtol(a2[2], 0LL, 10);
if ( qword_602150 )
{
qword_602158 = strtol(a2[3], 0LL, 10);
if ( qword_602158 )
{
qword_602160 = strtol(a2[4], 0LL, 10);
if ( qword_602160 )
{
if ( -24 * qword_602148 - 18 * qword_602150 - 15 * qword_602158 - 12 * qword_602160 == -18393
&& 9 * qword_602158 + 18 * (qword_602150 + qword_602148) - 9 * qword_602160 == 4419
&& 4 * qword_602158 + 16 * qword_602148 + 12 * qword_602150 + 2 * qword_602160 == 7300
&& -6 * (qword_602150 + qword_602148) - 3 * qword_602158 - 11 * qword_602160 == -8613 )
{
qword_602178 = qword_602158 + qword_602150 * qword_602148 - qword_602160;
sprintf(byte_602141, "%06x", qword_602178);
v4 = strlen(byte_602141);
MD5(byte_602141, v4, byte_602110);
for ( i = 0; i <= 15; ++i )
sprintf(&byte_602120[2 * i], "%02x", (unsigned __int8)byte_602110[i]);
printf(off_602080, byte_602120);
exit(0);
}
}
}
}
}
LABEL_2:
printf("password : ");
__isoc99_scanf("%s", &s1);
if ( strlen(&s1) > 0x10 )
{
puts("the password must be less than 16 character");
exit(1);
}
for ( j = 0; j < strlen(&s1); ++j )
*(&s1 + j) ^= 6u;
if ( !strcmp(&s1, a7yq2hryrn5yJga) )
{
v3 = strlen(&s1);
MD5(&s1, v3, byte_602110);
for ( k = 0; k <= 15; ++k )
sprintf(&byte_602120[2 * k], "%02x", (unsigned __int8)byte_602110[k]);
printf(off_602080, byte_602120);
exit(0);
}
puts("bad password!");
exit(0);
}
printf("password : ");
__isoc99_scanf("%s", &s1);
if ( strlen(&s1) > 0x10 )
{
puts("the password must be less than 16 character");
exit(1);
}
for ( m = 0; m < strlen(&s1); ++m )
{
*(&s1 + m) ^= 2u;
++*(&s1 + m);
*(&s1 + m) = ~*(&s1 + m);
}
if ( !memcmp(&s1, &unk_6020B8, 9uLL) )
{
for ( n = 0; n < strlen(aO6uH); n += 2 )
{
aO6uH[n] ^= 0x45u;
aO6uH[n + 1] ^= 0x26u;
}
puts(aO6uH);
}
else
{
puts("bad password!");
}
return 0LL;
}
// 4006A0: using guessed type __int64 __fastcall MD5(_QWORD, _QWORD, _QWORD);
// 4006E0: using guessed type __int64 __isoc99_scanf(const char *, ...);
// 602148: using guessed type __int64 qword_602148;
// 602150: using guessed type __int64 qword_602150;
// 602158: using guessed type __int64 qword_602158;
// 602160: using guessed type __int64 qword_602160;
// 602178: using guessed type __int64 qword_602178;
//----- (0000000000400DE0) ----------------------------------------------------
void __fastcall init(unsigned int a1, __int64 a2, __int64 a3)
{
signed __int64 v3; // rbp
__int64 i; // rbx
v3 = &off_601DF8 - &funcs_400E29;
init_proc();
if ( v3 )
{
for ( i = 0LL; i != v3; ++i )
(*(&funcs_400E29 + i))();
}
}
// 601DF0: using guessed type __int64 (__fastcall *funcs_400E29)();
// 601DF8: using guessed type __int64 (__fastcall *off_601DF8)();
//----- (0000000000400E54) ----------------------------------------------------
void term_proc()
{
;
}
// nfuncs=33 queued=10 decompiled=10 lumina nreq=0 worse=0 better=0
// ALL OK, 10 function(s) have been successfully decompiled
Análisis estático
Anti-debug
Si la función ptrace retorna -1, significa que el programa está siendo depurado y redirige a LABEL_2.
if (ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL) == -1) {
goto LABEL_2;
}
Cálculos y validaciones
El programa espera al menos 5 argumentos (nombre del programa y cuatro números enteros). Si se proporcionan los cuatro números enteros, se realizan los siguientes cálculos:
if (-24 * qword_602148 - 18 * qword_602150 - 15 * qword_602158 - 12 * qword_602160 == -18393
&& 9 * qword_602158 + 18 * (qword_602150 + qword_602148) - 9 * qword_602160 == 4419
&& 4 * qword_602158 + 16 * qword_602148 + 12 * qword_602150 + 2 * qword_602160 == 7300
&& -6 * (qword_602150 + qword_602148) - 3 * qword_602158 - 11 * qword_602160 == -8613)
Esto es un sistema de ecuaciones lineales mondo y lirondo que debe ser resuelto para encontrar los valores correctos de qword_602148, qword_602150, qword_602158 y qword_602160. Una vez resuelto el sistema de ecuaciones se realiza la operación:
qword_602178 = qword_602158 + qword_602150 * qword_602148 - qword_602160;
A continuación se pasa el resultado de la variable qword_602178 a hexadecimal y se genera su hash MD5.
Solución en Python
Lo más rápido en esta ocasión es usar Python, pero esto se puede resolver hasta con lápiz y papel 😉
from sympy import symbols, Eq, solve
import hashlib
# Definir las variables
A, B, C, D = symbols('A B C D')
# Definir las ecuaciones
eq1 = Eq(-24*A - 18*B - 15*C - 12*D, -18393)
eq2 = Eq(9*C + 18*(A + B) - 9*D, 4419)
eq3 = Eq(4*C + 16*A + 12*B + 2*D, 7300)
eq4 = Eq(-6*(A + B) - 3*C - 11*D, -8613)
# Resolver el sistema de ecuaciones
solution = solve((eq1, eq2, eq3, eq4), (A, B, C, D))
# Verificar si se encontró una solución
if solution:
print("Solución encontrada:")
print(solution)
# Obtener los valores de A, B, C y D
A_val = solution[A]
B_val = solution[B]
C_val = solution[C]
D_val = solution[D]
# Mostrar los valores encontrados
print(f"A = {A_val}")
print(f"B = {B_val}")
print(f"C = {C_val}")
print(f"D = {D_val}")
# Calcular qword_602178
qword_602178 = C_val + B_val * A_val - D_val
qword_602178 = int(qword_602178) # Convertir a entero de Python
print(f"qword_602178 = {qword_602178}")
# Convertir qword_602178 a una cadena en formato hexadecimal
byte_602141 = f"{qword_602178:06x}"
print(f"byte_602141 (hex) = {byte_602141}")
# Calcular el MD5 de la cadena
md5_hash = hashlib.md5(byte_602141.encode()).hexdigest()
print(f"MD5 hash = {md5_hash}")
# Generar la flag
flag = f"FLAG-{md5_hash}"
print(f"Flag = {flag}")
else:
print("No se encontró una solución.")
Al ejecutar el script veremos algo como esto:
Solución encontrada:
{A: 227, B: 115, C: 317, D: 510}
A = 227
B = 115
C = 317
D = 510
qword_602178 = 25912
byte_602141 (hex) = 006538
MD5 hash = 21a84f2c7c7fd432edf1686215db....
Flag = FLAG-21a84f2c7c7fd432edf1686215db....
ThisIsLegal.com – Realistic Challenge 1
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.
Introducción
Firebug
Links
Keygen para el CrackMe Pythagoras de Spider
Introducción
Hoy tenemos aquí un bonito crackme matemático realizado por Spider. El crackme está realizado en ensamblador y precisamente por eso, vamos a tener que lidiar con ciertas peculiaridades al realizar el keygen con un lenguaje de bajo nivel.
Al inicio comprueba la longitud del nombre y de el número de serie. El nombre debe tener al menos 6 caracteres y el número de serie debe tener 10. Os adelanto ya que la asignación de memoria del nombre es de 9 caracteres, es decir, da igual la longitud del nombre que solo va a usar 9.
004014AD | E8 1A 02 00 00 | call <pythagoras.GetWindowTextA> | ;Lee el nombre 004014B2 | 83 F8 06 | cmp eax,6 | ;Nombre >=6 caracteres 004014B5 | 0F 82 03 01 00 00 | jb pythagoras.4015BE | 004014BB | 6A 14 | push 14 | 004014BD | 68 D9 31 40 00 | push pythagoras.4031D9 | ;004031D9:"1234567890" 004014C2 | FF 35 10 32 40 00 | push dword ptr ds:[403210] | 004014C8 | E8 FF 01 00 00 | call <pythagoras.GetWindowTextA> | ;Lee el serial 004014CD | 83 F8 0A | cmp eax,A | ;Serial debe tener 10 (A) caracteres 004014D0 | 0F 85 E8 00 00 00 | jne pythagoras.4015BE |
Sabiendo esto introducimos Nombre: deurus y Serial: 1234567890
A continuación chequea que nuestro serial tenga caracteres hexadecimales.
004014DA | 8A 81 D9 31 40 00 | mov al,byte ptr ds:[ecx+4031D9] | ; ecx+004031D9:"1234567890" 004014E0 | 3C 00 | cmp al,0 | ; contador del bucle 004014E2 | 74 1F | je pythagoras.401503 | ; fin del bucle 004014E4 | 3C 30 | cmp al,30 | ; 0x30 = número 1 004014E6 | 0F 82 D2 00 00 00 | jb pythagoras.4015BE | ; < 30 bad boy 004014EC | 3C 46 | cmp al,46 | ; 0x46 = letra F 004014EE | 0F 87 CA 00 00 00 | ja pythagoras.4015BE | ; > 46 bad boy 004014F4 | 3C 39 | cmp al,39 | ; 0x39 = número 9 004014F6 | 76 08 | jbe pythagoras.401500 | ; <=39 ok continua el bucle 004014F8 | 3C 41 | cmp al,41 | ; 0x41 = letra A 004014FA | 0F 82 BE 00 00 00 | jb pythagoras.4015BE | ; <41 bad boy 00401500 | 41 | inc ecx | ; contador += 1 00401501 | EB D7 | jmp pythagoras.4014DA | ; bucle
Continua realizando un sumatorio con nuestro nombre, pero tenemos que tener especial cuidado al tratamiento de los datos, ya que el crackme al estar hecho en ensamblador puede jugar con los registros como quiere y eso nos puede inducir a error.
0040150B | 3C 00 | cmp al,0 | ; ¿Fin bucle? 0040150D | 74 05 | je pythagoras.401514 | ; Salta fuera del bucle si procede 0040150F | 02 D8 | add bl,al | ; bl = bl + al 00401511 | 41 | inc ecx | ; contador +=1 00401512 | EB F1 | jmp pythagoras.401505 | ; bucle
Si os fijáis utiliza registros de 8 bits como son AL y BL. Debajo os dejo una explicación de EAX pero para EBX es lo mismo.
EAX
-----------------------------------
AX
-----------------
AH AL
-------- --------
00000000 00000000 00000000 00000000
(8bit) (8bit) (8bit) (8bit)
EAX (32 bit)
--------
AX (16 bit)
----
AHAL (AH y AL 8 bit)
--------
00000000
El uso de registros de 8 bits nos implica tomar precauciones al realizar el Keygen debido a que por ejemplo, en .Net no tenemos la capacidad de decirle que haga una suma y que nos devuelva solamente 8 bits del resultado. Veamos como ejemplo para el nombre «deurus». La suma de los caracteres hexadecimales quedaría:
64+65+75+72+75+73 = 298, es decir, EAX = 00000298
Pero recordad que el crackme solo cogerá el 98 que es lo correspondiente al registro AL. De momento nos quedamos con nuestro SUMNOMBRE = 98.
Primera condición
A continuación coge los dos primeros caracteres del serial y les resta nuestro SUMNOMBRE y comprueba que el resultado esté entre 4 (0x4) y -4 (0xFC).
0040154B | 0F B6 05 F3 31 40 00 | movzx eax,byte ptr ds:[4031F3] | 00401552 | 8A C8 | mov cl,al | 00401554 | 2A CB | sub cl,bl | ; CL = CL - BL | CL = 12 - 98 = 7A 00401556 | 80 F9 04 | cmp cl,4 | ; Compara CL con 4 00401559 | 7F 63 | jg pythagoras.4015BE | ; Salta si es mayor 0040155B | 80 F9 FC | cmp cl,FC | ; Compara CL con FC (-4) 0040155E | 7C 5E | jl pythagoras.4015BE | ; Salta si es menor
Como veis, el resultado de la resta da 7A (122) que al ser mayor que 4 nos echa vilmente. Aquí de nuevo utiliza registros de 8 bits por lo que debemos tener cuidado con las operaciones matemáticas para no cometer errores, veamos un ejemplo para clarificar de aquí en adelante.
Utilizando 8 bits ----------------- 12 - 98 = 7A que en decimal es 122 Utilizando 16 bits ------------------ 0012 - 0098 = FF7A que en decimal es -134
Ahora ya veis la diferencia entre FC (252) y FFFC (-4). Estrictamente, el crackme comprueba el rango entre 4 (4) y FC (122) al trabajar con registros de 8 bits pero nosotros, como veremos más adelante tomaremos el rango entre 4 y -4. De momento, para poder continuar depurando cambiamos los dos primeros caracteres del serial de 12 a 98, ya que 98 – 98 = 0 y cumple la condición anterior.
Introducimos Nombre: deurus y Serial: 9834567890
Segunda condición
Analicemos el siguiente código.
00401560 | F7 E0 | mul eax | ; EAX = EAX * EAX 00401562 | 8B D8 | mov ebx,eax | ; EBX = EAX 00401564 | 0F B7 05 F4 31 40 00 | movzx eax,word ptr ds:[4031F4] | ; EAX = 3456 (4 dígitos siguientes del serial) 0040156B | F7 E0 | mul eax | ; EAX = EAX * EAX 0040156D | 03 D8 | add ebx,eax | ; EBX = EBX + EAX 0040156F | 0F B7 05 F6 31 40 00 | movzx eax,word ptr ds:[4031F6] | ; EAX = 7890 (4 últimos dígitos del serial) 00401576 | F7 E0 | mul eax | ; EAX = EAX * EAX 00401578 | 33 C3 | xor eax,ebx | ; EAX 0040157A | 75 42 | jne pythagoras.4015BE | ; Salta si el flag ZF no se activa
En resumen:
- 98 * 98 = 5A40 (98²)
- 3456 * 3456 = 0AB30CE4 (3456²)
- 0AB36724 + 5A40 = 0AB36724
- 7890 * 7890 = 38C75100 (7890²)
- 38C75100 XOR 0AB36724 = 32743624
- Si el resultado del XOR no es cero nuestro serial no pasa la comprobación.
Es decir, Pitágoras entra en escena -> 7890² = 98² + 3456²
Serial = aabbbbcccc
Tercera condición
Finalmente comprueba lo siguiente:
0040157C | 66 A1 F6 31 40 00 | mov ax,word ptr ds:[4031F6] | ; AX = 7890 00401582 | 66 2B 05 F4 31 40 00 | sub ax,word ptr ds:[4031F4] | ; AX = 7890 - 3456 = 443A 00401589 | 2C 08 | sub al,8 | ; AL = 3A - 8 = 32 0040158B | 75 31 | jne pythagoras.4015BE | ; Si el resultado de la resta no ha sido cero, serial no válido 0040158D | 6A 30 | push 30 | 0040158F | 68 B0 31 40 00 | push pythagoras.4031B0 | ;004031B0:":-) Well done!!!" 00401594 | 68 7F 31 40 00 | push pythagoras.40317F | ;0040317F:"Bravo, hai trovato il seriale di questo CrackMe!" 00401599 | FF 75 08 | push dword ptr ds:[ebp+8] |
En resumen:
- 7890 – 3456 – 8 = 0
Creación del Keygen
Nuestro serial tiene que cumplir tres condiciones para ser válido.
- a – SUMNOMBRE debe estar entre 4 y -4
- c² = a² + b²
- c – b – 8 = 0
Como hemos dicho anteriormente, tomaremos el SUMNOMBRE y le sumaremos y restaremos valores siempre y cuando el resultado esté entre 4 y -4. Para deurus hemos dicho que el SUMNOMBRE es 98 por lo que los posibles valores de «a» se pueden ver debajo. Además debemos tener en cuenta que el crackme solo lee los 9 primeros dígitos del nombre.
98-4 = 94 98-3 = 95 98-2 = 96 98-1 = 97 98-0 = 98 98+1 = 99 98+2 = 9A 98+3 = 9B 98+4 = 9C
Es evidente que para encontrar el valor de «c» vamos a tener que utilizar fuerza bruta chequeando todos los valores de «b» comprendidos entre 0 y FFFF (65535). Además, como trabajaremos en un lenguaje de alto nivel, debemos descartar los resultados decimales. Esto nos limitará los seriales válidos asociados a un determinado nombre. Si realizáramos el keygen en ensamblador obtendríamos bastantes más seriales válidos.
Una vez encontrados los valores enteros de la operación «c² = a² + b²», se debe cumplir que «c – b – 8 = 0», lo que nos limitará bastante los resultados.
Private Sub btn_generar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_generar.Click
Try
If txt_nombre.TextLength > 5 Then
lst_serials.Items.Clear()
Dim tmp, c, cx As String
Dim sumanombre, tmp2 As Integer
If txt_nombre.TextLength > 9 Then tmp2 = 8 Else tmp2 = txt_nombre.TextLength - 1
'Calculo el SUMNOMBRE
For i = 0 To tmp2
sumanombre += Asc(Mid(txt_nombre.Text, i + 1, 1)) 'Acumulo suma
tmp = Strings.Right(Hex(sumanombre).ToString, 2) 'Solo 8 bits (Registro AL)
sumanombre = Val("&H" & tmp) 'Paso a decimal
Next
tmp = Strings.Right(Hex(sumanombre).ToString, 2)
sumanombre = CInt("&H" & tmp)
txtdebug.Text = "- SumNombre = " & Hex(sumanombre) & vbCrLf
txtdebug.Text &= "----------------------------------------------" & vbCrLf
Dim a(8) As Integer
'
'a - sumanombre >=4 y <=4
'
a(0) = sumanombre - 4
a(1) = sumanombre - 3
a(2) = sumanombre - 2
a(3) = sumanombre - 1
a(4) = sumanombre
a(5) = sumanombre + 1
a(6) = sumanombre + 2
a(7) = sumanombre + 3
a(8) = sumanombre + 4
txtdebug.Text &= "- Posibles valores de 'a'" & vbCrLf
For i = 0 To a.Length - 1
txtdebug.Text &= Hex(a(i)) & " "
Next
txtdebug.Text &= "----------------------------------------------" & vbCrLf
txtdebug.Text &= "- Buscando valores de b y c" & vbCrLf
txtdebug.Text &= "Serial = aabbbbcccc" & vbCrLf
'
'c = sqr(a^2 + b^2)
'
txtdebug.Text &= "(1) c = raiz(a^2 + b^2)" & vbCrLf
txtdebug.Text &= "(2) c - b - 8 = 0" & vbCrLf
For i = 0 To a.Length - 1 ' todas las posibilidades de a
For b = 0 To 65535 'b -> 0000 - FFFF
c = Math.Sqrt(a(i) ^ 2 + b ^ 2)
If c.Contains(".") Then 'busco enteros
Else
cx = c - b - 8
cx = Hex(cx).PadLeft(4, "0"c)
lbl_info.Text = cx
If cx = "0000" Then
txtdebug.Text &= " (1) " & Hex(c).PadLeft(4, "0"c) & " = raiz(" & Hex(a(i)).PadLeft(2, "0"c) & "^2 + " & Hex(b).PadLeft(4, "0"c) & "^2)" & vbCrLf
lst_serials.Items.Add(Hex(a(i)).PadLeft(2, "0"c) & Hex(b).PadLeft(4, "0"c) & Hex(c).PadLeft(4, "0"c))
txtdebug.Text &= " (2) " & Hex(c).PadLeft(4, "0"c) & " - " & Hex(b).PadLeft(4, "0"c) & " - 8 = 0" & vbCrLf
End If
End If
Application.DoEvents()
Next
Next
lbl_info.Text = "Búsqueda finalizada"
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Enlaces
Andy’s Keygenme Keygen (AutoIt)
Introducción
Hoy vamos a ver como extraer el script de un ejecutable compilado por Autoit, modificarlo y recompilarlo como nuestro keygen. Como comprobareis si no se ofusca o se toman otro tipo de medidas recuperar información sensible es muy sencillo.
AutoIt es un lenguaje freeware multiproposito y de automatización para Microsoft Windows. Es un Visual Basic Killer, ya que mejora las características de los ejecutables (entre otras portabilidad, velocidad y peso, no fat-coding), y facilitan la programación con un buen repertorio de funciones «pre-diseñadas», y usando un Basic de fácil aprendizaje. Se ha expandido desde sus comienzos de automatización incluyendo muchas mejoras en el diseño del lenguaje de programación y sobre todo en nuevas funcionalidades.
El Script
Func CHECKKEY($USER, $PASS) Local $OPKEY = "", $SIG = "" Local $USER_LEN = StringLen($USER) Local $PASS_LEN = StringLen($PASS) If $USER_LEN < $PASS_LEN Then MsgBox(0, "ERROR", "Invalid username or key.") Exit ElseIf $USER_LEN < 4 Then MsgBox(0, "ERROR", "Invalid username or key.") Exit EndIf $PASS_INT = Int($USER_LEN / $PASS_LEN) $PASS_MOD = Mod($USER_LEN, $PASS_LEN) $OPKEY = _STRINGREPEAT($PASS, $PASS_INT) & StringLeft($PASS, $PASS_MOD) For $INDEX = 1 To $USER_LEN $SIG &= Chr(BitXOR(Asc(StringMid($USER, $INDEX, 1)), Asc(StringMid($OPKEY, $USER_LEN - $INDEX + 1, 1)))) Next If $SIG = _STRINGREPEAT(Chr(32), $USER_LEN) Then MsgBox(0, "INFO", "Your key was registered.") Exit Else MsgBox(0, "INFO", "Your key is invalid.") EndIf EndFunc
El Algoritmo
El algoritmo es tremendamente sencillo ya que es nuestro nombre al revés y en mayúsculas.
Modificando el script para generar nuestro propio keygen
El decompilador se llama myAut2exe y tiene este aspecto.
Programar en AutoIt es muy sencillo e intuitivo. Nuestro keygen quedaría así.
$MAIN = GUICreate("Another keygen by deurus", 300, 80, -1, -1, 382205952, 385)
$NAME_LBL = GUICtrlCreateLabel("Username", 5, 5, 60, 20, BitOR(4096, 1))
$NAME_INP = GUICtrlCreateInput("", 70, 5, 225, 20, 1)
$PASS_LBL = GUICtrlCreateLabel("Key", 5, 30, 60, 20, BitOR(4096, 1))
$PASS_INP = GUICtrlCreateInput("", 70, 30, 225, 20, 1)
$REGISTER = GUICtrlCreateButton("Register", 5, 55, 60, 20)
$GIVE_UP = GUICtrlCreateButton("Generate", 70, 55, 60, 20) <- Change name of button, Give Up by Generate
$TASK = GUICtrlCreateButton("?", 140, 55, 20, 20)
$AUTHOR = GUICtrlCreateLabel("keygen by deurus", 165, 55, 130, 20, BitOR(4096, 1))
GUISetState(@SW_SHOW, $MAIN)
While True
$MSG = GUIGetMsg()
Switch $MSG
Case $REGISTER
Call("CHECKKEY", GUICtrlRead($NAME_INP), GUICtrlRead($PASS_INP))
Case $GIVE_UP
Call("GETKEY", GUICtrlRead($NAME_INP), GUICtrlRead($PASS_INP)) <- Add the function to the button
Case $TASK
MsgBox(0, "Info", "keygen by deurus")
Case - 3
Exit
EndSwitch
Sleep(15)
WEnd
Func GETKEY($USER, $PASS) <- this is our keygen function
Local $OPKEY = "", $SIG = ""
Local $USER_LEN = StringLen($USER)
Local $PASS_LEN = StringLen($USER)
If $USER_LEN < 4 Then
GUICtrlSetData($PASS_INP ,"min 4 chars");
Else
For $INDEX = 1 To $USER_LEN
$SIG = Chr(BitXOR(Asc(StringMid($USER, $INDEX, 1)), 32)) & $SIG
Next
GUICtrlSetData($PASS_INP ,$SIG);
EndIf
EndFunc
Func CHECKKEY($USER, $PASS) <- check function, the original
Local $OPKEY = "", $SIG = ""
Local $USER_LEN = StringLen($USER)
Local $PASS_LEN = StringLen($PASS)
If $USER_LEN < $PASS_LEN Then
MsgBox(0, "ERROR", "Invalid username or key.")
ElseIf $USER_LEN < 4 Then
MsgBox(0, "ERROR", "Invalid username or key.")
Exit
EndIf
$PASS_INT = Int($USER_LEN / $PASS_LEN)
$PASS_MOD = Mod($USER_LEN, $PASS_LEN)
$OPKEY = _STRINGREPEAT($PASS, $PASS_INT) & StringLeft($PASS, $PASS_MOD)
For $INDEX = 1 To $USER_LEN
$SIG &= Chr(BitXOR(Asc(StringMid($USER, $INDEX, 1)), Asc(StringMid($OPKEY, $USER_LEN - $INDEX + 1, 1))))
Next
If $SIG = _STRINGREPEAT(Chr(32), $USER_LEN) Then
MsgBox(0, "INFO", "Your key was registered.")
Else
MsgBox(0, "INFO", "Your key is invalid.")
EndIf
EndFunc
Este es el resultado.
Links
Algoritmo de HEdit 2.1.11
Rebuscando entre todo el caos que puede llegar a ser mi disco duro, he encontrado una serie de programas que utilizaba antiguamente cuando empezó a interesarme el Cracking. Ya sabéis que no soy partidario de crackear programas comerciales pero hoy voy a hacer una excepción ya que la versión del programa es muy vieja (1997) e incluso podría considerarse abandonware.
Este ejercicio es ideal para los que están empezando ya que es fácil localizar donde está el algoritmo y éste es sumamente sencillo.
Algoritmo
Address Hex dump Command Comments
00402213 E8 78170000 CALL HEdit.00403990
........
004039C0 8BC1 MOV EAX,ECX
004039C2 99 CDQ
004039C3 33C2 XOR EAX,EDX
004039C5 2BC2 SUB EAX,EDX
004039C7 83E0 03 AND EAX,00000003
004039CA 33C2 XOR EAX,EDX
004039CC 2BC2 SUB EAX,EDX
004039CE 8A540C 04 MOV DL,BYTE PTR SS:[ECX+ESP+4] ;Coge el dígito i*3
004039D2 8A5C04 04 MOV BL,BYTE PTR SS:[EAX+ESP+4] ;Coge el dígito i
004039D6 8D4404 04 LEA EAX,[EAX+ESP+4] ;Guarda en memoria 12EE90
004039DA 32DA XOR BL,DL
004039DC 41 INC ECX ; i +=1
004039DD 81F9 00010000 CMP ECX,100 ;El bucle se repite 256 veces (0x100)
004039E3 8818 MOV BYTE PTR DS:[EAX],BL
004039E5 ^ 7C D9 JL SHORT HEdit.004039C0
004039E7 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4]
004039EB 85C0 TEST EAX,EAX ;Comprueba que el serial no sea 0
004039ED 7D 02 JGE SHORT HEdit.004039F1 ;Si es 0 se acabó
004039EF F7D8 NEG EAX
004039F1 3B8424 0C010000 CMP EAX,DWORD PTR SS:[ESP+10C] ;Comprobación de serial válido
004039F8 75 13 JNE SHORT HEdit.00403A0D ;Si no es igual bad boy
004039FA 85C0 TEST EAX,EAX ;Comprueba que el serial no sea 0
004039FC 74 0F JE SHORT HEdit.00403A0D ;Si es 0 se acabó
004039FE B8 01000000 MOV EAX,1
00403A03 5B POP EBX
00403A04 81C4 00010000 ADD ESP,100
00403A0A C2 0800 RETN 8
En resumen hace esto:
- Nombre introducido: deurus
- Convierte el nombre a mayúsculas
D E U R U S
44 45 55 52 55 53 (En Hexadecimal)
1) 55 xor 44 = 11
2) 53 xor 45 = 16
3) 00 xor 55 = 55
4) 00 xor 52 = 52
--------------- solo vale hasta aquí EAX(32 bits)
5) 00 xor 55 = 55
6) 00 xor 53 = 53
7) 00 xor 00 = 00
8) ...
HEX DEC
Serial = 52551611 = 1381307921
Como veis, realiza un bucle 256 veces pero como al final utiliza el registro EAX para hacer la comparación, solamente nos sirven las cuatro primeras operaciones. De hecho, no comprueba ni la longitud del nombre por lo que si introducimos un solo dígito como nombre, el serial será el valor ascii de ese dígito en decimal. La única comprobación que realiza es que el serial no sea 0.
Keygen
Os dejo una prueba de concepto en Javascript.
var nombre = "deurus";
nombre = nombre.toUpperCase();
var serial = "";
serial = serial + nombre.charCodeAt(3).toString(16) + nombre.charCodeAt(2).toString(16);
serial = serial + (nombre.charCodeAt(5) ^ nombre.charCodeAt(1)).toString(16);
serial = serial + (nombre.charCodeAt(2) ^ nombre.charCodeAt(0)).toString(16);
serial = "Nº Serie: " + parseInt(serial,16);
document.write(serial);
Enlaces
ThisIsLegal.com – Realistic Challenge 5
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.
Introducción
Analizando a la víctima
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.
Explotando la víctima
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.
Links
Solución al Crackme 3 de Sotanez
- Introducción
- Activar un botón en memoria
- Activar el botón de forma permanente
- Serial Hardcodeado
- Links
Introducción
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.
Activar un botón en memoria
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.
Activar el botón de forma permanente
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.
Serial Hardcodeado
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
Links
SPECtacular
AVISO: Debido a que este reto está en activo no publicaré a donde pertenece.
En este reto stego nos proporcionan un archivo MP3 y nos dan una pequeña pista con el título.
Inicialmente lo pasé con GoldWave y me fijé en el la parte de control en el SPECtrogram y en el SPECtrum, pero no conseguí ver nada. A punto de rendirme di con un programa online llamado SPEK, que me dio la respuesta al instante.

Se puede apreciar una palabra que escrita en Inglés nos da la solución al reto.
VideoTutorial – Keygen y desempacado UPX para el Crackme#1 de ECloZion
Wechall Training LSB Challenge (Esteganografía)
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.
Introducción
Resumidamente, esta técnica consiste en ocultar información en el bit menos significativo de cada uno de los píxeles de una imagen, consiguiendo así que el cambio realizado sea invisible al ojo humano. El problema de esta técnica, es que la información oculta puede obtenerse fácilmente si esta no se ha codificado previamente o si no se sigue un patrón concreto a la hora de ocultarla.
Desde la web del reto nos avisan de que esto es un simple truco pero espectacular. Nos animan a descargar una imágen y a encontrar la solución oculta.
Aprovecho este reto para presentaros una herramienta vital al enfrentaros a ciertos retos sobre esteganografía, steganabara.
Steganabara tiene dos apartados muy interesantes, uno es «color table» y otro «bit mask«, hoy veremos en acción a «bit mask».
No os preocupéis por la solución ya que cambia para cada usuario y sesión.
Buscando la solución oculta
Abrimos steganabara y empezamos a trastear con bit mask.
Al poco tiempo ya vemos que vamos bien encaminados.
Finalmente no nos cuesta dar con la solución.
Links
- Web del reto
- Steganabara
- Steganabara explained (english)
- Esteganografía: Ocultando el uso de LSB (securityartwork.es)
Descargar contenido multimedia de ciertas webs
Hoy en día, la descarga de contenido multimedia de ciertas webs es imposible o muy difícil. En ciertos casos lo entiendo, exponer el contenido supone una pérdida de ingresos y eso es inaceptable. Las cadenas de TV son tema aparte, emiten contenido por varios medios y les gusta que lo veas y que lo compartas, eso sí, que lo compartas desde su plataforma, ya que lo que estás compartiendo es un enlace, no el vídeo.
Este caso es un caso intermedio entre una plataforma de pago que codifica sus contenidos y una web que nos permita descargar su contenido directamente.
Imaginemos que vemos un vídeo y queremos mandarlo por Whatsapp a nuestros amigos. Lo primero es echar un vistazo al código fuente de la web y localizar el código del reproductor web (player). Para esta tarea podemos ayudarnos de una extensión muy conocida para navegadores como es Firebug. Una vez instalada, la activamos con F12 y mediante el botón Inspect localizamos el player.
...
<p itemprop="keywords" itemscope="itemscope" itemtype="http://schema.org/Text" class="antetitulo" lang="es">EL INTERMEDIO LE PILLA EN "EL TRONO"</p>
<h1 class="title-new" itemprop="headline">Joaquín Reyes se mete en la piel de Juan Carlos I: "Soy tan campechano que podéis llamarme Juan Carlos Palote"</h1>
<sumary class="entradilla" itemprop="description">
<p><p class="MsoNormal">Los reyes eméritos han celebrado sus bodas de esmeralda y
con motivo de tan señalada fecha, Juan Carlos I ha hecho un hueco en su
apretada agenda para concederle unos minutos a <a title="<b>El Intermedio</b>" href="http://www.lasexta.com/temas/el_intermedio-1" target="_blank"><b>El Intermedio</b></a>. Eso sí, en su
versión de <a title="<b>Joaquín Reyes</b>" href="http://www.lasexta.com/temas/joaquin_reyes-1" target="_blank"><b>Joaquín Reyes</b></a>. <o:p></o:p></p> </sumary>
<div class="great-element-multimedia">
<section class="modVideo a3mod_player" data-mod="a3mod_player" data-model="/json/video/7/2017/05/15/591a08c1986b2810b31577c1.json">
<a itemprop="url" href="#" class="icon link-content" title="" data-mod-elem="icon">
<div class="wrap-img" role="banner">
<div itemprop="video" itemscope itemtype="http://schema.org/VideoObject">
<picture>
<!--[if IE 9]><video style="display: none;"><![endif]-->
<source media="(max-width:520px)" srcset="http://fotografias.lasexta.com/clipping/cmsimages02/2017/05/15/14069ECA-B0E4-4F09-A5B7-04B600C016AD/64.jpg" />
<source media="(max-width:1023px)" srcset="http://fotografias.lasexta.com/clipping/cmsimages02/2017/05/15/14069ECA-B0E4-4F09-A5B7-04B600C016AD/60.jpg" />
<source media="(min-width:1024px)" srcset="http://fotografias.lasexta.com/clipping/cmsimages02/2017/05/15/14069ECA-B0E4-4F09-A5B7-04B600C016AD/58.jpg" />
<!--[if IE 9]></video><![endif]-->
<img src="http://fotografias.lasexta.com/clipping/cmsimages02/2017/05/15/14069ECA-B0E4-4F09-A5B7-04B600C016AD/58.jpg" alt="Joaquín Reyes, como el rey Juan Carlos I" title="Joaquín Reyes, como el rey Juan Carlos I" />
</picture>
<meta itemprop="description" content=""/>
<meta itemprop="name" content=""/>
<meta itemprop="thumbnailUrl" content="" />
<meta itemprop="uploadDate" content=""/>
<meta itemprop="url" content=""/>
<meta itemprop="width" content=""/>
<meta itemprop="height" content=""/>
</div>
</div>
</a>
</section>
</div>
...
Si os fijáis bien, el reproductor hace referencia a un archivo json (591a08c1986b2810b31577c1.json), reconstruimos la url y miramos su contenido
{"id":"591a08c1986b2810b31577c1","type":"video","tipo":"video","subtipo":"video","imgThumb":"http://fotografias.lasexta.com/clipping/cmsimages02/2017/05/15/14069ECA-B0E4-4F09-A5B7-04B600C016AD/29.jpg","imgPoster":"http://fotografias.lasexta.com/clipping/cmsimages02/2017/05/15/14069ECA-B0E4-4F09-A5B7-04B600C016AD/31.jpg","live":false,"autoplay":true,"sources":[{"src":"http://vclip.atresmedia.com/vclip/_definst_/smil:assets10/2017/05/15/01229E28-A57E-4AC9-AFE7-EF1C27B5AA2A/es.smil/manifest_mvlist.mpd","type":"application/dash+xml"},{"src":"http://vclip.atresmedia.com/vclip/_definst_/smil:assets10/2017/05/15/01229E28-A57E-4AC9-AFE7-EF1C27B5AA2A/es.smil/playlist.m3u8","type":"application/vnd.apple.mpegurl"}],"omniture":{"section":"Joaquín Reyes","category":"El Intermedio","channel":"lasexta","type":"short","name":"Joaquín Reyes se mete en la piel de Juan Carlos I: \"Soy tan campechano que podéis llamarme Juan Carlos Palote\"","embeddedMode":false},"comscore":{"comscoreTag":"LASEXTA.COM","channel":"lasexta","kantar":{"programID":"1019","firstBroadcastDate":"*null","firstBroadcastTime":"*null","typeTvStream":"0002","kantarGenre":"0","channelId":"240"},"content_form":"short_form"},"urlHits":"http://hits.lasexta.com/l6//591a08c1986b2810b31577c1/3/348128,351435,351827,351865/","duration":"211.797333","embeddedUrl":"<iframe src=\"http://www.lasexta.com/embed/el-intermedio-le-pilla-en-el-trono/video/7/2017/05/15/591a08c1986b2810b31577c1\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen></iframe>","playondraw":true,"nextRelated":{"service_url":"http://www.lasexta.com/json/video/7/2017/05/15/591a08c1986b2810b31577c1_related.json"},"subtitle":[],"titulo":"Joaquín Reyes se mete en la piel de Juan Carlos I: \"Soy tan campechano que podéis llamarme Juan Carlos Palote\"","descripcion":"","sociales":{"hasTwitter":true,"hasFacebook":true,"hasGooglePlus":true,"hasWhatsapp":true,"twitter":"EL INTERMEDIO LE PILLA EN “EL TRONO”","facebook":"EL INTERMEDIO LE PILLA EN “EL TRONO”","googlePlus":"EL INTERMEDIO LE PILLA EN “EL TRONO”","whatsapp":"","hashtag":"","via":"sextaNoticias","urlPage":"https://goo.gl/cu98f0"},"vp_data":{"vp_category":"Atresmedia/Lasexta/programas/el-intermedio*","vp_tags":"","vp_content_form":"short_form"}}
Se puede ver a simple vista una lista de reproducción playlist.m3u8, cuyo contenido contiene más listas de reproducción con diferentes calidades.
#EXTM3U #EXT-X-VERSION:3 #EXT-X-STREAM-INF:BANDWIDTH=796400,CODECS="avc1.77.30,mp4a.40.5",RESOLUTION=640x360 chunklist_b724000.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1159400,CODECS="avc1.77.30,mp4a.40.5",RESOLUTION=640x360 chunklist_b1054000.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1643400,CODECS="avc1.77.30,mp4a.40.5",RESOLUTION=720x404 chunklist_b1494000.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=2248400,CODECS="avc1.77.31,mp4a.40.5",RESOLUTION=1280x720 chunklist_b2044000.m3u8
Reconstruimos la URL para la lista de reproducción de mayor calidad e inspeccionamos su contenido.
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, media_b2044000_0.ts #EXTINF:10.0, media_b2044000_1.ts #EXTINF:10.0, media_b2044000_2.ts #EXTINF:10.0, media_b2044000_3.ts #EXTINF:10.0, media_b2044000_4.ts #EXTINF:10.0, media_b2044000_5.ts #EXTINF:10.0, media_b2044000_6.ts #EXTINF:10.0, media_b2044000_7.ts #EXTINF:10.0, media_b2044000_8.ts #EXTINF:10.0, media_b2044000_9.ts #EXTINF:10.0, media_b2044000_10.ts #EXTINF:10.0, media_b2044000_11.ts #EXTINF:10.0, media_b2044000_12.ts #EXTINF:10.0, media_b2044000_13.ts #EXTINF:10.0, media_b2044000_14.ts #EXTINF:10.0, media_b2044000_15.ts #EXTINF:10.0, media_b2044000_16.ts #EXTINF:10.0, media_b2044000_17.ts #EXTINF:10.0, media_b2044000_18.ts #EXTINF:10.0, media_b2044000_19.ts #EXTINF:10.0, media_b2044000_20.ts #EXTINF:1.92, media_b2044000_21.ts #EXT-X-ENDLIST
Se pueden ver 21 archivos con extensión TS de 10 segundos cada uno a excepción del último que dura 1.92 segundos. Los archivos TS no son más que archivos MP4 por lo que una vez descargados, los podemos unir con MP4Tools por ejemplo.
La tarea es costosa, pero si os apetece enviar un vídeo en vez de un enlace, ya sabéis que en determinados casos se puede hacer.













































































