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.

Intro

This crackme is for the crack challenge 6 of canyouhack.it.

In this crackme the goal is to turn on all the lights. Note that a light off to the next, so if we interrupt this, we win.

Tools

Exeinfo (For crackme info)

Delphi Decompiler (For decompile)

 OllyDbg (For debug)

Decompiling

With Delphi Decompiler we can found easy the buttons and his offsets.
Go to the offset 401A64 in OllyDbg and analyze the code.
We view two jumps, one turn ON the light and the other Turn OFF the next light. Patching the call from offset 401A8B we get the serial.

Links


st2 arcade
He de iniciar esta entrada diciendo que la segunda temporada de Stranger Things es sencillamente genial. Son 9 horas intensas
Intro Hoy tenemos un crackme realizado en Visual C++ 6. Es el típico serial asociado a un nombre. El algoritmo
Aviso: Este crackme forma parte de una serie de pruebas de Yoire.com que todavía está en activo. Lo ético si
Aquí os dejo un video tutorial. El crackme lo podeis encontrar en crackmes.de.

st2 arcade

He de iniciar esta entrada diciendo que la segunda temporada de Stranger Things es sencillamente genial. Son 9 horas intensas que no dejan indiferente a nadie y además en el capítulo 8 nos han dejado una de esas perlas informáticas que tanto nos gustan.

La escena la protagoniza Bob Newby, un buen hombre amante de la electrónica de aquella época que trabaja en RadioShack y transcurre en el laboratorio secreto de Hawkins. En un momento dado, Bob propone «saltarse» la seguridad del laboratorio y para ello se traslada al sótano donde se encuentran los «servidores».

El PC de la época

Para comprender esta escena hay que situarse temporalmente. Estamos hablando de los años 80, en concreto la escena transcurre en 1984 y los equipos de los que dispone el laboratorio son unos maravillosos IBM. No se llega a apreciar bien el modelo de IBM utilizado pero teniendo en cuenta que el monitor que aparece es un terminal IBM 3180, la búsqueda se reduce a los sistemas compatibles S/36, S/38, AS/400, 5294 ó 5394.

IBM 3180

IBM 3180 (https://www.argecy.com/3180)

Cracking BASIC or BASIC Cracking?

La escena plantea un ataque de fuerza bruta a un código de 4 dígitos como se puede observar en la imagen a continuación. Esto puede parecer una chorrada hoy día pero podía suponer un pequeño reto para un micro de 8 bits.

Cracking Basic or Basic Cracking?

Cracking Basic or Basic Cracking?

A simple vista se aprecian una serie de bucles recursivos, una llamada a una función y una sentencia condicional. Desconozco si la sintaxis del lenguaje es la correcta pero mucho me temo que es más bien una mezcla de BASIC y pseudocódigo. Pero lo que más me ha llamado la atención sin duda es que la palabra THEN parece que se sale del monitor como si estuviera realizado en post-producción. Os invito a que ampliéis la imagen y comentéis lo que os parece a vosotr@s.

Os dejo aquí el código para los más curiosos.

10 DIM FourDigitPassword INTEGER
20 FOR i = 0 TO 9
30 		FOR j = 0 TO 9
40			FOR k = 0 TO 9
50				FOR l = 0 TO 9
60					FourDigitPassword = getFourDigits (i,j,k,l)
70					IF checkPasswordMatch(FourDigitPassword) = TRUE THEN
80						GOTO 140
90					END
100				NEXT l
110			NEXT k
120		NEXT j
130 NEXT i
140 PRINT FourDigitPassword

Aunque  la entrada está dentro del contexto de los Blooper Tech Movies, digamos que en esta ocasión no voy a ir más allá. La escena es creíble y queda bien integrada en la época en la que se desarrolla el capítulo. Por esto mismo, solamente espero que las temporadas venideras sean tan buenas y cuiden tanto los detalles como sus predecesoras.

Referencias

[1] Ficha IMDB – Stranger Thing

[2] Wikia de Stranger Things

[3] IBM 3180

[4] BASIC

Intro

Hoy tenemos un crackme realizado en Visual C++ 6. Es el típico serial asociado a un nombre.

El algoritmo

Localizamos con Olly la rutina de comprobación del serial y empezamos a analizar. Vemos una serie de Calls que lo único que hacen es comprobar el tamaño de nuestro nombre y serial y si es <5 dígitos nos tira afuera.

saltos_iniciales

Una vez pasada la traba anterior procede con un bucle para el nombre y otro para el serial. Yo he metido deurus y 123456. El bucle del nombre hace xor al los dígitos ascii con un valor incremental a partir de 1. Reconvierte el valor resultante en su caracter correspondiente y lo almacena.

00401576     |.  B9 01000000   MOV ECX,1                         ; ECX = 1
0040157B     |.  33D2          XOR EDX,EDX
0040157D     |.  8B45 E4       MOV EAX,[LOCAL.7]                 ; EAX = Nombre
00401580     |>  8A18          /MOV BL,BYTE PTR DS:[EAX]         ; BL = digito que toque  <--
00401582     |.  32D9          |XOR BL,CL                        ; digito XOR ECX
00401584     |.  8818          |MOV BYTE PTR DS:[EAX],BL         ; sustituye el digito nombre por el resultante del xor
00401586     |.  41            |INC ECX                          ; ECX++
00401587     |.  40            |INC EAX                          ; Siguiente digito
00401588     |.  8038 00       |CMP BYTE PTR DS:[EAX],0
0040158B     |.^ 75 F3         \JNZ SHORT crackme3.00401580      ; Bucle -->

 Ejemplo:

d  e  u  r  u  s
64 65 75 72 75 73

(d)64 xor 1 = 65(e)
(e)65 xor 2 = 67(g)
(u)75 xor 3 = 76(v)
(r)72 xor 4 = 76(v)
(u)75 xor 5 = 70(p)
(s)73 xor 6 = 75(u)

Nombre:    deurus
Resultado: egvvpu

Hace lo mismo con el serial pero con el valor incremental a partir de 0xA (10).

00401593     |.  B9 0A000000    MOV ECX,0A                      ; ECX = A
00401598     |.  33D2           XOR EDX,EDX
0040159A     |.  8B45 F0        MOV EAX,[LOCAL.4]               ; EAX = Serial
0040159D     |>  8A18           /MOV BL,BYTE PTR DS:[EAX]       ; BL = digito que toque  <--
0040159F     |.  32D9           |XOR BL,CL                      ; BL XOR CL
004015A1     |.  8818           |MOV BYTE PTR DS:[EAX],BL       ; sustituye el digito serial por el resultante del xor
004015A3     |.  41             |INC ECX                        ; ECX++
004015A4     |.  40             |INC EAX                        ; Siguiente digito
004015A5     |.  8038 00        |CMP BYTE PTR DS:[EAX],0
004015A8     |.^ 75 F3          \JNZ SHORT crackme3.0040159D    ; Bucle -->

Ejemplo:

1  2  3  4  5  6
31 32 33 34 35 35

(1)31 xor A = 3B(;)
(2)32 xor B = 39(9)
(3)33 xor C = 3F(?)
(4)34 xor D = 39(9)
(5)35 xor E = 3B(;)
(6)36 xor F = 39(9)

Serial:    123456
Resultado: ;9?9;9

A continuación compara «egvvpu» con «;9?9;9» byte a byte.

KeyGen

El KeyGen quedaría así

for(int i = 0; i <= strlen(Nombre); i = i + 1)
                {
                        Serial[i] = (Nombre[i]^(i+1))^(0xA + i);
                }

 Links


Introducción Desempacado Eliminar la NAG Password Nº serie asociado a un nombre Checkbox Trackbar Links Introducción Aquí tenemos un Crackme
Intro Hoy nos enfrentamos a un crackme realizado en Delphi con un algoritmo bastante sencillo. Está empacado con UPX pero
Introducción Siguiendo con los crackmes que contienen RSA, esta vez tenemos un Keygenme del grupo PGC (Pirates Gone Crazy) que
Warning: This challenge is still active and therefore should not be resolved using this information. Aviso: Este reto sigue en

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....

Introducción

 Este un crackme muy interesante para principiantes ya que la rutina no es muy compleja. Está hecho en ensamblador.

Saltar el antidebug

Arrancamos el crackme en Olly damos al play y se cierra. Buscamos en las «Intermodular Calls» y vemos «IsDebuggerPresent«, clickamos sobre ella y vemos el típico call, lo NOPeamos.

names

Aquí vemos el call.

isdebuggerpresent

Call Nopeado.

antidebug

Encontrando un serial válido

Encontrar en serial válido en esta ocasión es muy sencillo, basta con buscar en las «String References» el mensaje de «Bad boy» y fijarse en la comparación.

comparacion

 El algoritmo

Si nos fijamos en el serial generado nos da muchas pistas pero vamos a destriparlo ya que tampoco tiene mucha complicación. De nuevo miramos en las «String references» y clickamos sobre el mensaje de «bad boy«. Encima de los mensajes vemos claramente la rutina de creación del serial.

004010EB        |.  83F8 04             CMP EAX,4                      ;Longitud del nombre >4
004010EE        |.  72 05               JB SHORT Ice9.004010F5
004010F0        |.  83F8 0A             CMP EAX,0A                     ;Longitud del nombre <=10
004010F3        |.  76 15               JBE SHORT Ice9.0040110A
004010F5        |>  6A 00               PUSH 0                                ; /Style = MB_OK|MB_APPLMODAL
004010F7        |.  68 04304000         PUSH Ice9.00403004                    ; |Title = "Error, Bad Boy"
004010FC        |.  68 1C304000         PUSH Ice9.0040301C                    ; |Text = "name must be at least 4 chars"
00401101        |.  6A 00               PUSH 0                                ; |hOwner = NULL
00401103        |.  E8 70010000         CALL <JMP.&user32.MessageBoxA>        ; \MessageBoxA
........
00401183         .  3BD3                CMP EDX,EBX
00401185         .  74 15               JE SHORT Ice9.0040119C
00401187         .  8A07                MOV AL,BYTE PTR DS:[EDI]
00401189         .  3C 5A               CMP AL,5A                     ;Compara que el dígito < 5A
0040118B         .  7E 05               JLE SHORT Ice9.00401192
0040118D         >  03C8                ADD ECX,EAX                   ;ECX + Ascii(dígito)
0040118F         .  47                  INC EDI 
00401190         .^ EB EE               JMP SHORT Ice9.00401180
00401192         >  3C 41               CMP AL,41                     ;Compara que el dígito > 41
00401194         .  7D 02               JGE SHORT Ice9.00401198
00401196         .  EB 02               JMP SHORT Ice9.0040119A
00401198         >  04 2C               ADD AL,2C                     ;Si cumple lo anterior dígito +2C
0040119A         >^ EB F1               JMP SHORT Ice9.0040118D
0040119C         >  81C1 9A020000       ADD ECX,29A                   ;ECX + 29A
004011A2         .  69C9 39300000       IMUL ECX,ECX,3039             ;ECX * 3039
004011A8         .  83E9 17             SUB ECX,17                    ;ECX - 17
004011AB         .  6BC9 09             IMUL ECX,ECX,9                ;ECX * 9
004011AE         .  33DB                XOR EBX,EBX
004011B0         .  8BC1                MOV EAX,ECX                   ;Mueve nuestro SUM en EAX
004011B2         .  B9 0A000000         MOV ECX,0A                    ;ECX = A
004011B7         >  33D2                XOR EDX,EDX
004011B9         .  F7F1                DIV ECX                       ;SUM / ECX (Resultado a EAX)
004011BB         .  80C2 30             ADD DL,30
004011BE         .  881433              MOV BYTE PTR DS:[EBX+ESI],DL
004011C1         .  83C3 01             ADD EBX,1
004011C4         .  83F8 00             CMP EAX,0
004011C7         .  74 02               JE SHORT Ice9.004011CB
004011C9         .^ EB EC               JMP SHORT Ice9.004011B7
004011CB         >  BF C8304000         MOV EDI,Ice9.004030C8
004011D0         >  8A4433 FF           MOV AL,BYTE PTR DS:[EBX+ESI-1]
004011D4         .  8807                MOV BYTE PTR DS:[EDI],AL
004011D6         .  47                  INC EDI 
004011D7         .  4B                  DEC EBX
004011D8         .  83FB 00             CMP EBX,0
004011DB         .^ 75 F3               JNZ SHORT Ice9.004011D0
004011DD         .  C607 00             MOV BYTE PTR DS:[EDI],0               ;Coje letras del nombre en función
004011E0         .  8D3D B4304000       LEA EDI,DWORD PTR DS:[4030B4]         ;del resultado anterior
004011E6         .  68 B7304000         PUSH Ice9.004030B7                    ;  ASCII "rus"
004011EB         .  68 C8304000         PUSH Ice9.004030C8                    ;  ASCII "134992368rus"
004011F0         .  E8 BB000000         CALL Ice9.004012B0                    ; Concatena
004011F5         .  68 C8304000         PUSH Ice9.004030C8                    ; /String2 = "136325628rus"
004011FA         .  68 98314000         PUSH Ice9.00403198                    ; |String1 = "12345"
004011FF         .  E8 98000000         CALL <JMP.&kernel32.lstrcmpA>         ; \lstrcmpA

Resumen (valores hexadecimales):

  • Len(Nombre ) >=4 y <=A
  • Comprueba si el dígito está es mayúsculas y si está le sume 2C al valor ascii.
  • Suma el valor ascii de todos los dígitos menos el último.
  • SUM + 29A
  • SUM * 3039
  • SUM – 17
  • SUM * 9

Finalmente concatena letras siguiendo este criterio:

  • Len(nombre) = 4 -> coje la última letra
  • Len(nombre) = 5 -> coje las dos últimas
  • Len(nombre) = 6 -> coje las tres últimas
  • Len(nombre) = 7 -> coje las cuatro últimas
  • Len(nombre) = 8 -> coje las cinco últimas
  • Len(nombre) = 9 -> coje las seis últimas
  • Len(nombre) = A -> coje las siete últimas

Ejemplo para deurus

d  e  u  r  u  (s)
64+65+75+72+75 = 225
225 + 29A   = 4BF
4BF * 3039  = E4DE87
E4DE87 - 17 = E4DE70
E4DE70 * 9  = 80BD1F0
;Pasamos a decimal y concatenamos
134992368rus

Ejemplo para Deurus

D       e  u  r  u  (s)
44(+2C)+65+75+72+75 = 25D
25D + 29A   = 4F7
4BF * 3039  = EF6AFF
EF6AFF - 17 = EF6AE8
EF6AE8 * 9  = 86AC228
;Pasamos a decimal y concatenamos
141214248rus

Como curiosidad decirtos que con el tiempo valores del estilo 29A y 3039 os pegarán rápido al ojo ya que equivalen a 666 y 12345 en decimal. Por cierto 29A fue un grupo de hackers creadores de virus muy conocido en la escena Nacional e Internacional.

Links


Intro Aquí tenemos un crackme clásico realizado en Visual C++. La única particularidad que tiene es que no muestra MessageBox
Intro Extensión PPM Clave cifrada Un nuevo lenguaje de programación Enlaces Intro Hoy tenemos aquí un reto de esteganografía bastante
Introducción Funcionamiento de RSA OllyDbg Calculando la clave privada (d) Ejemplo operacional Keygen Links Introducción Segunda crackme con RSA que
Warning: This challenge is still active and therefore should not be resolved using this information. Aviso: Este reto sigue en

Intro

Aquí tenemos un crackme clásico realizado en Visual C++. La única particularidad que tiene es que no muestra MessageBox al introducir bien o mal el serial, simplemente cambia una imagen de un emoticono. Si observamos el comportamiento del crackme notaremos que inicialmente el emoticono está neutral y al fallar se pone triste y por lo tanto es de suponer que al acertar se pondrá contento.

El BreakPoint

Intermodular Calls

Al mirar en las Intermodular Calls de OllyDbg vemos que LoadIconA es un buen candidato para ubicar la comprobación del serial. Si nos fijamos hay tres llamadas, ponemos un breakpoint en las tres y enseguida llegamos a la zona de comprobación del serial.

La comprobación

00401180   . 6A FF          PUSH -1
00401182   . 68 68194000    PUSH CrackMe_.00401968
00401187   . 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
0040118D   . 50             PUSH EAX
0040118E   . 64:8925 000000>MOV DWORD PTR FS:[0],ESP
00401195   . 83EC 0C        SUB ESP,0C
00401198   . 53             PUSH EBX
00401199   . 55             PUSH EBP
0040119A   . 8BE9           MOV EBP,ECX
0040119C   . 56             PUSH ESI
0040119D   . 57             PUSH EDI
0040119E   . 8D4C24 10      LEA ECX,DWORD PTR SS:[ESP+10]
004011A2   . E8 2F050000    CALL <JMP.&MFC42.#540>
004011A7   . 8D4C24 14      LEA ECX,DWORD PTR SS:[ESP+14]
004011AB   . C74424 24 0000>MOV DWORD PTR SS:[ESP+24],0
004011B3   . E8 1E050000    CALL <JMP.&MFC42.#540>
004011B8   . 8D4424 10      LEA EAX,DWORD PTR SS:[ESP+10]
004011BC   . 8BCD           MOV ECX,EBP
004011BE   . 50             PUSH EAX
004011BF   . 68 E9030000    PUSH 3E9
004011C4   . C64424 2C 01   MOV BYTE PTR SS:[ESP+2C],1
004011C9   . E8 02050000    CALL <JMP.&MFC42.#3097>                  ;  Lee el tamano del nombre
004011CE   . 8D4C24 14      LEA ECX,DWORD PTR SS:[ESP+14]
004011D2   . 51             PUSH ECX
004011D3   . 68 EA030000    PUSH 3EA
004011D8   . 8BCD           MOV ECX,EBP
004011DA   . E8 F1040000    CALL <JMP.&MFC42.#3097>                  ;  Lee el tamano del serial
004011DF   . 51             PUSH ECX
004011E0   . 8D5424 14      LEA EDX,DWORD PTR SS:[ESP+14]
004011E4   . 8BCC           MOV ECX,ESP
004011E6   . 896424 1C      MOV DWORD PTR SS:[ESP+1C],ESP
004011EA   . 52             PUSH EDX
004011EB   . E8 DA040000    CALL <JMP.&MFC42.#535>
004011F0   . 8D4424 1C      LEA EAX,DWORD PTR SS:[ESP+1C]   
004011F4   . 8BCD           MOV ECX,EBP       
004011F6   . 50             PUSH EAX                 
004011F7   . E8 D4010000    CALL CrackMe_.004013D0 
004011FC   . 50             PUSH EAX
004011FD   . 8D4C24 14      LEA ECX,DWORD PTR SS:[ESP+14]
00401201   . C64424 28 02   MOV BYTE PTR SS:[ESP+28],2
00401206   . E8 B9040000    CALL <JMP.&MFC42.#858>
0040120B   . 8D4C24 18      LEA ECX,DWORD PTR SS:[ESP+18]
0040120F   . C64424 24 01   MOV BYTE PTR SS:[ESP+24],1
00401214   . E8 A5040000    CALL <JMP.&MFC42.#800>
00401219   . 8B4C24 10      MOV ECX,DWORD PTR SS:[ESP+10]
0040121D   . 8B5424 14      MOV EDX,DWORD PTR SS:[ESP+14]
00401221   . 8B41 F8        MOV EAX,DWORD PTR DS:[ECX-8]
00401224   . 8B4A F8        MOV ECX,DWORD PTR DS:[EDX-8]
00401227   . 3BC1           CMP EAX,ECX                              ;  CMP len nombre y len serial
00401229   . 0F85 2C010000  JNZ CrackMe_.0040135B
0040122F   . 83F8 03        CMP EAX,3                                ;  len nombre >=3
00401232   . 0F8C 23010000  JL CrackMe_.0040135B
00401238   . 50             PUSH EAX
00401239   . E8 7A040000    CALL <JMP.&MFC42.#823>
0040123E   . 8BF0           MOV ESI,EAX
00401240   . 8B4424 14      MOV EAX,DWORD PTR SS:[ESP+14]
00401244   . 83C4 04        ADD ESP,4
00401247   . 33C9           XOR ECX,ECX
00401249   . 8B50 F8        MOV EDX,DWORD PTR DS:[EAX-8]
0040124C   . 4A             DEC EDX
0040124D   . 85D2           TEST EDX,EDX
0040124F   . 7E 37          JLE SHORT CrackMe_.00401288
.......
1ºBUCLE
.......
00401251   > 8A1401         MOV DL,BYTE PTR DS:[ECX+EAX]
00401254   . 8A5C01 01      MOV BL,BYTE PTR DS:[ECX+EAX+1]
00401258   . 8B4424 14      MOV EAX,DWORD PTR SS:[ESP+14]
0040125C   . 0FBED2         MOVSX EDX,DL
0040125F   . 0FBE0401       MOVSX EAX,BYTE PTR DS:[ECX+EAX]
00401263   . 8D4410 FE      LEA EAX,DWORD PTR DS:[EAX+EDX-2]
00401267   . 99             CDQ
00401268   . 2BC2           SUB EAX,EDX
0040126A   . 0FBED3         MOVSX EDX,BL
0040126D   . D1F8           SAR EAX,1
0040126F   . 40             INC EAX
00401270   . 83EA 02        SUB EDX,2
00401273   . 3BC2           CMP EAX,EDX
00401275   . 0F94C0         SETE AL
00401278   . 880431         MOV BYTE PTR DS:[ECX+ESI],AL
0040127B   . 8B4424 10      MOV EAX,DWORD PTR SS:[ESP+10]
0040127F   . 41             INC ECX
00401280   . 8B50 F8        MOV EDX,DWORD PTR DS:[EAX-8]
00401283   . 4A             DEC EDX
00401284   . 3BCA           CMP ECX,EDX
00401286   .^7C C9          JL SHORT CrackMe_.00401251
........
Última comprobación
........
00401288   > 0FBE1401       MOVSX EDX,BYTE PTR DS:[ECX+EAX]
0040128C   . 0FBE78 01      MOVSX EDI,BYTE PTR DS:[EAX+1]
00401290   . 8B4424 14      MOV EAX,DWORD PTR SS:[ESP+14]
00401294   . 83C7 FE        ADD EDI,-2
00401297   . 0FBE0401       MOVSX EAX,BYTE PTR DS:[ECX+EAX]
0040129B   . 8D4410 FE      LEA EAX,DWORD PTR DS:[EAX+EDX-2]
0040129F   . 99             CDQ
004012A0   . 2BC2           SUB EAX,EDX
004012A2   . D1F8           SAR EAX,1
004012A4   . 40             INC EAX
004012A5   . 3BC7           CMP EAX,EDI
004012A7   . 0F94C2         SETE DL
004012AA   . 881431         MOV BYTE PTR DS:[ECX+ESI],DL

La comprobación es muy sencilla, en resumen hace esto con todas las letras del nombre excepto la última:

1º Caracter
(1ºname + 1ºserial - 2 = X)
(X / 2)
(X + 1)
(2ºname - 2 = Y)
¿Y = X?
2º Caracter
(2ºname + 2ºserial - 2 = X)
(X / 2)
(X + 1)
(3ºname - 2 = Y)
¿Y = X?
...
Con el último caracter del nombre hace lo siguiente:
(6ºname + 6ºserial - 2 = X)
(X / 2)
(X + 1)
(2ºname - 2 = Y)
¿Y = X?
---------
Para revertir la primera parte de la comprobación para el nombre deurus quedaría:
X1 = (((2ºname-2-1)*2)+2)-1ºname
X2 = (((3ºname-2-1)*2)+2)-2ºname
X3 = (((4ºname-2-1)*2)+2)-3ºname
X4 = (((5ºname-2-1)*2)+2)-4ºname
X5 = (((6ºname-2-1)*2)+2)-5ºname
X6 = (((2ºname-2-1)*2)+2)-6ºname

Keygen

var nombre = "deurus";
nombre = nombre.toUpperCase();
var serial = "";
var tmp = "";

var i;
for (i = 0; i < nombre.length-1 ; i++) {
  tmp = ((nombre.charCodeAt(i+1)-2-1)*2+2)-nombre.charCodeAt(i);
  serial += String.fromCharCode(tmp);
}

tmp = ((nombre.charCodeAt(1)-2-1)*2+2)-nombre.charCodeAt(nombre.length-1);
serial += String.fromCharCode(tmp);

document.write(serial);

Enlaces

Y eso es todo, ¡a disfrutar!

Introducción

Segunda crackme con RSA que afrontamos. Esta vez se trata de un crackme realizado en VC++ 7.0 y en sus entrañas utiliza RSA-127. Una cosa que no comenté en la entrega anterior (RSA-200), es que conviene utilizar el plugin Kanal de PEiD para localizar cuando se utilizan números grandes o determinados hashes como MD5 o SHA1.

16-02-2015 01-49-36

Otra cosa es que os quería comentar es la coletilla 127. Esta lo determina el módulo n e indica el número de bits de éste.

Funcionamiento de RSA

  1. Inicialmente es necesario generar aleatoriamente dos números primos grandes, a los que llamaremos p y q.
  2. A continuación calcularemos n como producto de p y q:
    n = p * q
  3. Se calcula fi:
    fi(n)=(p-1)(q-1)
  4. Se calcula un número natural e de manera que MCD(e, fi(n))=1 , es decir e debe ser primo relativo de fi(n). Es lo mismo que buscar un numero impar por el que dividir fi(n) que de cero como resto.
  5. Mediante el algoritmo extendido de Euclides se calcula d que es el inverso modular de e.
    Puede calcularse d=((Y*fi(n))+1)/e para Y=1,2,3,... hasta encontrar un d entero.
  6. El par de números (e,n) son la clave pública.
  7. El par de números (d,n) son la clave privada.
  8. Cifrado: La función de cifrado es.
    c = m^e mod n
  9. Descifrado: La función de descifrado es.
    m = c^d mod n

OllyDbg

Con OllyDbg analizamos la parte del código que nos interesa.

0040109B    .  68 00010000         PUSH 100                                  ; /Count = 100 (256.)
004010A0    .  52                  PUSH EDX                                  ; |Buffer = RSA127.<ModuleEntryPoint>
004010A1    .  68 EA030000         PUSH 3EA                                  ; |ControlID = 3EA (1002.)
004010A6    .  8B8C24 28020000     MOV ECX,DWORD PTR SS:[ESP+228]            ; |
004010AD    .  51                  PUSH ECX                                  ; |hWnd = NULL
004010AE    .  FF15 F0B04000       CALL DWORD PTR DS:[<&USER32.GetDlgItemTex>; \GetDlgItemTextA
004010B4    .  8D5424 04           LEA EDX,DWORD PTR SS:[ESP+4]
004010B8    .  57                  PUSH EDI
004010B9    .  52                  PUSH EDX                                  ;  RSA127.<ModuleEntryPoint>
004010BA    .  50                  PUSH EAX                                  ;  kernel32.BaseThreadInitThunk
004010BB    .  E8 201E0000         CALL RSA127.00402EE0
004010C0    .  83C4 0C             ADD ESP,0C
004010C3    .  8D9424 04010000     LEA EDX,DWORD PTR SS:[ESP+104]
004010CA    .  68 00010000         PUSH 100                                  ; /Count = 100 (256.)
004010CF    .  52                  PUSH EDX                                  ; |Buffer = RSA127.<ModuleEntryPoint>
004010D0    .  68 EB030000         PUSH 3EB                                  ; |ControlID = 3EB (1003.)
004010D5    .  8B8C24 28020000     MOV ECX,DWORD PTR SS:[ESP+228]            ; |
004010DC    .  51                  PUSH ECX                                  ; |hWnd = NULL
004010DD    .  FF15 F0B04000       CALL DWORD PTR DS:[<&USER32.GetDlgItemTex>; \GetDlgItemTextA
004010E3    .  8D9424 04010000     LEA EDX,DWORD PTR SS:[ESP+104]
004010EA    .  52                  PUSH EDX                                  ;  RSA127.<ModuleEntryPoint>
004010EB    .  8B4C24 04           MOV ECX,DWORD PTR SS:[ESP+4]
004010EF    .  51                  PUSH ECX
004010F0    .  E8 5B1F0000         CALL RSA127.00403050
004010F5    .  68 08B14000         PUSH RSA127.0040B108                      ;  ASCII "666AAA422FDF79E1D4E41EDDC4D42C51"
004010FA    .  55                  PUSH EBP
004010FB    .  E8 501F0000         CALL RSA127.00403050
00401100    .  68 2CB14000         PUSH RSA127.0040B12C                      ;  ASCII "29F8EEDBC262484C2E3F60952B73D067"
00401105    .  56                  PUSH ESI
00401106    .  E8 451F0000         CALL RSA127.00403050
0040110B    .  53                  PUSH EBX
0040110C    .  55                  PUSH EBP
0040110D    .  56                  PUSH ESI
0040110E    .  8B5424 24           MOV EDX,DWORD PTR SS:[ESP+24]
00401112    .  52                  PUSH EDX                                  ;  RSA127.<ModuleEntryPoint>
00401113    .  E8 38250000         CALL RSA127.00403650
00401118    .  53                  PUSH EBX
00401119    .  57                  PUSH EDI
0040111A    .  E8 31130000         CALL RSA127.00402450
0040111F    .  83C4 30             ADD ESP,30
00401122    .  85C0                TEST EAX,EAX                              ;  kernel32.BaseThreadInitThunk
00401124    .  74 12               JE SHORT RSA127.00401138
00401126    .  B8 01000000         MOV EAX,1
0040112B    .  81C4 08020000       ADD ESP,208
00401131    .  5B                  POP EBX                                   ;  kernel32.7590EE1C
00401132    .  5D                  POP EBP                                   ;  kernel32.7590EE1C
00401133    .  5E                  POP ESI                                   ;  kernel32.7590EE1C
00401134    .  5F                  POP EDI                                   ;  kernel32.7590EE1C
00401135    .  C2 1000             RETN 10
00401138    >  6A 40               PUSH 40                                   ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
0040113A    .  68 5CB14000         PUSH RSA127.0040B15C                      ; |Title = "Yeah!"
0040113F    .  68 50B14000         PUSH RSA127.0040B150                      ; |Text = "Nice job!!!"
00401144    .  6A 00               PUSH 0                                    ; |hOwner = NULL
00401146    .  FF15 F4B04000       CALL DWORD PTR DS:[<&USER32.MessageBoxA>] ; \MessageBoxA

El código nos proporciona el exponente público (e) y el módulo (n).

  • e = 29F8EEDBC262484C2E3F60952B73D067
  • n = 666AAA422FDF79E1D4E41EDDC4D42C51

Finalmente realiza un PowMod con el número de serie del disco C y el par de claves (e,n).

Calculando la clave privada (d)

Una vez localizados los datos anteriores lo siguiente es factorizar para obtener los primos p y q y finalmente d.

RSA127_rsatool

d = 65537

Ejemplo operacional

Nº serie disco C = -1295811883
Serial = hdd.getBytes()^d mod n
Serial = 2d31323935383131383833^65537 mod 666AAA422FDF79E1D4E41EDDC4D42C51
Serial = 1698B6CE6BE0D388C31E8E7895AF445A

RSA127_bigint

Keygen

El keygen está hecho en Java ya que permite trabajar con números grandes de forma sencilla.

JButton btnNewButton = new JButton("Generar");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                BigInteger serial = new BigInteger("0");
                BigInteger n = new BigInteger("136135092290573418981810449482425576529");
                BigInteger d = new BigInteger("415031");
                String hdd = t1.getText();
                BigInteger tmp = new BigInteger(hdd.getBytes());
                serial = tmp.modPow(d, n);
                t2.setText(serial.toString(16).toUpperCase());
            }
        });

Links


Acabo de montar AperiSolve en una Raspi que tenía por casa pensando que sería coser y cantar, pero me he
Hoy analizamos Copycat, un thriller psicológico de 1995 que, como muchas películas de la época, no pudo resistirse a incorporar
Introducción Funcionamiento de RSA OllyDbg Calculando un serial válido Ejemplo operacional Keygen Links Introducción Empezamos con lo que espero que
Habitualmente suelo descargar shareware por diversión para evaluar de que manera protegen los programadores su software. Cada vez es más

Acabo de montar AperiSolve en una Raspi que tenía por casa pensando que sería coser y cantar, pero me he encontrado con que el repositorio no estaba preparado para todas las distros Linux de forma estándar. El resultado lo he colgado en Github, de modo que para montarlo en vuestra propia Raspi solo tenéis que seguir estos pasos:

1. Clonar el repositorio
git clone https://github.com/deurus/AperiSolve-Raspi3.git
cd AperiSolve-Raspi3/AperiSolve

2. Construir los contenedores
docker compose build
docker compose up -d

3. Abrir la web
http://<IP_RASPI>:5000

Si tenéis curiosidad de la adaptación que he tenido que hacer aquí están los pasos que he seguido:

1. Preparar el sistema
sudo apt update
sudo apt install -y git docker.io docker-compose
sudo usermod -aG docker $USER
newgrp docker

2. Clonar AperiSolve
git clone https://github.com/Zeecka/AperiSolve.git
cd AperiSolve

3. Crear la estructura de build para la imagen ARM/x86
nano docker-compose.yml

y pega este contenido:

FROM python:3.11-slim

RUN apt-get update && apt-get install -y \
    zip \
    p7zip-full \
    binwalk \
    foremost \
    exiftool \
    steghide \
    ruby \
    binutils \
    pngcheck \
    && rm -rf /var/lib/apt/lists/*

COPY aperisolve/ /aperisolve/

RUN pip install --no-cache-dir -r /aperisolve/requirements.txt

WORKDIR /aperisolve

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "wsgi:app"]

4. Arreglar docker-compose.yml para ser válido y compatible

services:
  web:
    image: aperisolve-local
    build: .
    container_name: aperisolve-web
    ports:
      - "5000:5000"
    depends_on:
      - redis
      - postgres
    environment:
      DB_URI: "postgresql://aperiuser:aperipass@postgres:5432/aperisolve"

  worker:
    image: aperisolve-local
    container_name: aperisolve-worker
    depends_on:
      - redis
      - postgres
    environment:
      DB_URI: "postgresql://aperiuser:aperipass@postgres:5432/aperisolve"

  redis:
    image: redis:7
    container_name: aperisolve-redis

  postgres:
    image: postgres:16
    container_name: aperisolve-postgres
    environment:
      POSTGRES_USER: aperiuser
      POSTGRES_PASSWORD: aperipass
      POSTGRES_DB: aperisolve
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

5. Modificar aperisolve/config.py
nano config.py

y pega este contenido:

from pathlib import Path

IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".tiff"]

WORKER_FILES = ["binwalk", "foremost", "steghide", "zsteg"]

RESULT_FOLDER = Path(__file__).parent.resolve() / "results"
RESULT_FOLDER.mkdir(parents=True, exist_ok=True)

6. Modificación de aperisolve/app.py

Sustituir la línea: app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI")
por:
default_db = "postgresql://aperiuser:aperipass@postgres:5432/aperisolve"
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI", default_db)

7. Construir la imagen
docker build -t aperisolve-local .

8. Levantar los contenedores
docker compose down
docker compose up -d

9. Comprobar logs
docker logs aperisolve-web --tail=50
docker logs aperisolve-worker --tail=50

10. Acceder a la web
 - Desde cualquier máquina de la red local: http://IP-DE-LA-MAQUINA:5000
 - Desde la Raspi: http://localhost:5000

11. Limpieza (cuando necesites)
 - Reiniciar contenedores:
docker compose restart
 - Borrar resultados antiguos:
sudo rm -r aperisolve/results/*

Hoy analizamos Copycat, un thriller psicológico de 1995 que, como muchas películas de la época, no pudo resistirse a incorporar elementos tecnológicos que, vistos desde una perspectiva actual, nos sacan una sonrisa. Vamos a desmontar algunos gazapos tecnológicos y curiosidades relacionadas con los sistemas informáticos que aparecen en la película.

El escritorio de tres pantallas: ¿el futuro en 1995?

La protagonista, la Dra. Helen Hudson (Sigourney Weaver), trabaja en un escritorio con tres pantallas, algo futurista para la época. En 1995, esto no era tan común como hoy en día. Para lograrlo, probablemente necesitaría tres ordenadores conectados de forma independiente, ya que los sistemas operativos y hardware de la época no solían soportar múltiples monitores en una sola máquina. Esto plantea preguntas interesantes sobre la logística de su set-up: ¿Cómo sincronizaba su trabajo entre tres PCs?

Un detalle curioso es que, en algunas tomas, se distingue la marca Compaq en los equipos. Compaq era una de las compañías líderes en la fabricación de ordenadores personales durante los 90 y conocida por sus soluciones de alta calidad. Este dato refuerza la idea de que el set-up de Helen estaba diseñado para representar lo último en tecnología de la época, aunque hoy resulte un tanto rudimentario. La elección de Compaq no es casual: en ese momento, era sinónimo de equipos potentes, usados tanto en oficinas como en entornos domésticos avanzados.

Internet y la magia de los módems

En una escena, Helen navega por internet con lo que suponemos es un módem de 28.8 kbps (o como mucho, un flamante 33.6 kbps, tecnología de vanguardia allá por 1995). Hasta ahí, vale. Sin embargo, la fluidez de su conexión sorprende: carga archivos, recibe correos y no se queda esperando con una pantalla de “Conectando…”. Pero lo mejor llega cuando, estando conectada, ¡suena el teléfono! En la realidad, esto cortaría la conexión o comunicaría, a menos que tuviera dos líneas telefónicas (algo raro en domicilios particulares de la época) o algún dispositivo milagroso que no conocemos.

¿Qué sistema operativo usa?

Aunque no se distingue claramente el sistema operativo, vemos una interfaz gráfica con ventanas y una consola de comandos. Esto podría ser un guiño a Windows 3.1 o Windows 3.11, ya maduro en esa época aunque la interfaz no termina de encajar. Sin embargo, también podría ser una mezcla ficticia para hacer que el entorno luciera “tecnológico” sin comprometerse demasiado con la realidad. Detalle curioso: en los 90, las películas solían personalizar las interfaces para no tener problemas legales.

El email como el epicentro de la tecnología

En los 90, el email era el rey. En las películas, los escritorios siempre tenían un gran icono de correo (a menudo animado, porque lo cool siempre parpadeaba). En Copycat, Helen recibe un correo con un archivo AVI de unos 30 segundos, lo cual plantea otra duda técnica: ¿Cuánto espacio ocupaba ese archivo en 1995?

Un AVI de 30 segundos probablemente tendría una resolución baja (320×240 píxeles o menos) y una tasa de compresión eficiente para la época, pero aun así podría pesar entre 2 y 5 MB, dependiendo de la calidad del audio y vídeo. Eso hubiera supuesto una odisea por email, ya que los servidores de la época limitaban los adjuntos a unos pocos cientos de KB. ¿Quizás el villano usó un protocolo privado para saltarse las restricciones?

Tomorrow.AVI

Tras recibir un inquietante archivo AVI, la protagonista llama a la policía, lo que desencadena una conversación cargada de decisiones tecnológicas cuestionables:

  • «¿Cómo le han enviado esto?» / «Consiguiendo su dirección de internet»: El archivo es descrito como enviado a través de «su dirección de internet», un término extraño para la época en la que lo habitual habría sido referirse al correo electrónico. Esto refleja un intento de sonar sofisticado sin usar los términos correctos.
  • «¿No podríamos localizarlo?»: La respuesta de los policías es que no pueden rastrear el origen del archivo «a no ser que esté conectado». Sin embargo, incluso en 1995, las cabeceras de los emails contenían suficiente información para rastrear el servidor de origen, aunque la práctica era más rudimentaria que en la actualidad. Ignorar esto parece una licencia creativa del guion o un concepto equivocado de localizar asociándolo quizá a las llamadas telefónicas.
  • «Es demasiado grande para pasarlo a disco»: Aquí surge el principal obstáculo: el archivo AVI es considerado «demasiado grande» para transferirlo a un disquete de 3,5 pulgadas (con una capacidad máxima de 1,44 MB). Aunque esto tiene sentido desde una perspectiva técnica, resulta extraño que fuera posible enviarlo por email en primer lugar, dado que los servidores de correo de la época tenían limitaciones más estrictas que un disquete. Esto sugiere una inconsistencia en la lógica tecnológica de la escena.
  • «Lo pasaremos a vídeo»: Ante la imposibilidad de transferirlo a un disquete, la solución propuesta es convertir el archivo a un formato reproducible en un dispositivo analógico (probablemente una cinta VHS) para transportarlo físicamente. Aunque esta decisión es plausible dentro de las limitaciones tecnológicas de la época, omite soluciones más digitales, como volver a enviarlo por email (¿acaso la policía no tenía correo electrónico?). Además, surge la pregunta de por qué no se recurre a los forenses técnicos de la policía (o del FBI) para analizar el disco duro, quienes, curiosamente, no aparecen en ningún momento de la película.
  • «Oh, Dios. ¿Cómo sabes todas estas cosas?» / «Malgasté mi juventud en los salones de videojuegos»: Esta frase añade un toque humorístico, pero no tiene relación alguna con las habilidades necesarias para resolver el problema en cuestión. Más bien, refuerza la desconexión entre los diálogos y las acciones tecnológicas presentadas.

Conclusión

Copycat (1995) es un buen ejemplo de cómo el cine de los 90 abordaba la tecnología con una mezcla de admiración y confusión. Desde la exageración de tener tres monitores en el escritorio de Helen hasta la torpe gestión del archivo Tomorrow.AVI, la película refleja tanto las limitaciones tecnológicas de la época como las libertades creativas de los guionistas.

En el caso del archivo AVI, los personajes deciden que no se puede gestionar digitalmente y optan por convertirlo a vídeo analógico, ignorando soluciones más simples como volver a enviarlo por correo electrónico (suponiendo que fuera posible). Este detalle, combinado con la ausencia aparente de personal técnico en la policía, subraya una desconexión entre la narrativa y las capacidades reales de la tecnología, incluso para 1995.

Aunque estos detalles pueden parecer cómicos 30 años después, forman parte del encanto de un cine que imaginaba el futuro sin comprender del todo su presente. Más que errores, son un recordatorio de cómo la tecnología ha evolucionado y de cómo nuestra percepción de ella también lo ha hecho.

Enlaces

  • Copycat [IMDb]
  • Historia de Internet [Wikipedia]
  • Correo electrónico [Wikipedia]
  • Compaq [Wikipedia]
  • Silicon Cowboys: la historia de cómo Compaq retó (y venció) a IBM y Apple [Xataka]
  • Formato de vídeo AVI [Wikipedia]
  • Analysis of video file formats in forensics (.avi example) [DiViLine]

Galería

Introducción

Empezamos con lo que espero que sea una serie de crackmes RSA. En este caso en particular y como el propio autor nos adelanta, se trata de RSA-200.

En criptografía, RSA (Rivest, Shamir y Adleman) es un sistema criptográfico de clave pública desarrollado en 1977. Es el primer y más utilizado algoritmo de este tipo y es válido tanto para cifrar como para firmar digitalmente.

 Funcionamiento de RSA

  1. Inicialmente es necesario generar aleatoriamente dos números primos grandes, a los que llamaremos p y q.
  2. A continuación calcularemos n como producto de p y q:
    n = p * q
  3. Se calcula fi:
    fi(n)=(p-1)(q-1)
  4. Se calcula un número natural e de manera que MCD(e, fi(n))=1 , es decir e debe ser primo relativo de fi(n). Es lo mismo que buscar un numero impar por el que dividir fi(n) que de cero como resto.
  5. Mediante el algoritmo extendido de Euclides se calcula d que es el inverso modular de e.
    Puede calcularse d=((Y*fi(n))+1)/e para Y=1,2,3,... hasta encontrar un d entero.
  6. El par de números (e,n) son la clave pública.
  7. El par de números (d,n) son la clave privada.
  8. Cifrado: La función de cifrado es.
    c = m^e mod n
  9. Descifrado: La función de descifrado es.
    m = c^d mod n

OllyDbg

Con OllyDbg analizamos la parte del código que nos interesa.

00401065  |>push    19                          ; /Count = 19 (25.)
00401067  |>push    00404330                    ; |Buffer = dihux_ke.00404330
0040106C  |>push    2711                        ; |ControlID = 2711 (10001.)
00401071  |>push    dword ptr [ebp+8]           ; |hWnd
00401074  |>call    <GetDlgItemTextA>           ; \GetDlgItemTextA
00401079  |>cmp     eax, 5                      ;  Tamaño nombre >= 5
0040107C  |>jb      00401214
00401082  |>cmp     eax, 14                     ;  Tamaño nombre <= 0x14
00401085  |>ja      00401214
0040108B  |>mov     [404429], eax
00401090  |>push    96                          ; /Count = 96 (150.)
00401095  |>push    00404349                    ; |Buffer = dihux_ke.00404349
0040109A  |>push    2712                        ; |ControlID = 2712 (10002.)
0040109F  |>push    dword ptr [ebp+8]           ; |hWnd
004010A2  |>call    <GetDlgItemTextA>           ; \GetDlgItemTextA
004010A7  |>test    al, al
........
004010D8  |>xor     ecx, ecx                    ;  Case 0 of switch 004010B6
004010DA  |>/push    0
004010DC  |>|call    <__BigCreate@4>
004010E1  |>|mov     [ecx*4+404411], eax
004010E8  |>|inc     ecx
004010E9  |>|cmp     ecx, 6
004010EC  |>\jnz     short 004010DA
004010EE  |>push    dword ptr [404411]          ; /Arg3 = 00B60000
004010F4  |>push    10                          ; |16??
004010F6  |>push    0040401F                    ; |Arg1 = 0040401F ASCII "8ACFB4D27CBC8C2024A30C9417BBCA41AF3FC3BD9BDFF97F89"
004010FB  |>call    <__BigIn@12>                ; \dihux_ke.004013F3
00401100  |>push    dword ptr [404415]          ; /Arg3 = 00C70000
00401106  |>push    10                          ; |Arg2 = 00000010
00401108  |>push    00404019                    ; |Arg1 = 00404019 ASCII "10001"
0040110D  |>call    <__BigIn@12>                ; \dihux_ke.004013F3
00401112  |>push    dword ptr [404425]          ; /Arg3 = 00CB0000
00401118  |>push    10                          ; |Arg2 = 00000010
0040111A  |>push    00404349                    ; |Arg1 = 00404349 ASCII "123456789123456789"
0040111F  |>call    <__BigIn@12>                ; \dihux_ke.004013F3
00401124  |>push    00404330                    ; /String = "deurus"
00401129  |>call    <lstrlenA>                  ; \lstrlenA
0040112E  |>push    dword ptr [404419]
00401134  |>push    eax
00401135  |>push    00404330                    ;  ASCII "deurus"
0040113A  |>call    <__BigInB256@12>
0040113F  |>push    dword ptr [404421]          ;  c
00401145  |>push    dword ptr [404411]          ;  n = 8ACFB4D27CBC8C2024A30C9417BBCA41AF3FC3BD9BDFF97F89
0040114B  |>push    dword ptr [404415]          ;  e = 10001
00401151  |>push    dword ptr [404425]          ;  serial
00401157  |>call    <__BigPowMod@16>            ;  c = serial^e (mod n)
0040115C  |>mov     eax, 1337
00401161  |>push    0                           ; /Arg4 = 00000000
00401163  |>push    dword ptr [40441D]          ; |x
00401169  |>push    eax                         ; |0x1337
0040116A  |>push    dword ptr [404421]          ; |c
00401170  |>call    <__BigDiv32@16>             ; \x = c/0x1337
00401175  |>push    dword ptr [40441D]          ;  x
0040117B  |>push    dword ptr [404419]          ;  nombre
00401181  |>call    <__BigCompare@8>            ; ¿x = nombre?
00401186  |>jnz     short 0040119C
00401188  |>push    0                           ; /Style = MB_OK|MB_APPLMODAL
0040118A  |>push    00404014                    ; |Title = "iNFO"
0040118F  |>push    00404004                    ; |Text = "Serial is valid"
00401194  |>push    dword ptr [ebp+8]           ; |hOwner
00401197  |>call    <MessageBoxA>               ; \MessageBoxA
0040119C  |>xor     ecx, ecx
0040119E  |>/push    dword ptr [ecx*4+404411]
004011A5  |>|call    <__BigDestroy@4>
004011AA  |>|inc     ecx
004011AB  |>|cmp     ecx, 6
004011AE  |>\jnz     short 0040119E

 Lo primero que observamos es que el código nos proporciona el exponente público (e) y el módulo (n).

  • e = 10001
  • n = 8ACFB4D27CBC8C2024A30C9417BBCA41AF3FC3BD9BDFF97F89

A continuación halla c = serial^d mod n. Finalmente Divide c entre 0x1337 y lo compara con el nombre.

Como hemos visto en la teoría de RSA, necesitamos hallar el exponente privado (d) para poder desencriptar, según la fórmula vista anteriormente.

  • Fórmula original: m=c^d mod n
  • Nuestra fórmula: Serial = x^d mod n. Siendo x = c * 0x1337

Calculando un serial válido

Existen varios ataques a RSA, nosotros vamos a usar el de factorización. Para ello vamos a usar la herramienta RSA Tool. Copiamos el módulo (n), el exponente público (e) y factorizamos (Factor N).

rsatool1

Hallados los primos p y q, hallamos d (Calc. D).

rsatool4

Una vez obtenido d solo nos queda obtener x, que recordemos es nombre * 0x1337.

Cuando decimos nombre nos referimos a los bytes del nombre en hexadecimal, para deurus serían 646575727573.

Ejemplo operacional

Nombre: deurus

x = 646575727573 * 0x1337 = 7891983BA4EC4B5
Serial = x^d mod n
Serial = 7891983BA4EC4B5^32593252229255151794D86C1A09C7AFCC2CCE42D440F55A2D mod 8ACFB4D27CBC8C2024A30C9417BBCA41AF3FC3BD9BDFF97F89
Serial = FD505CADDCC836FE32E34F5F202E34D11F385DEAD43D87FCD

Como la calculadora de Windows se queda un poco corta para trabajar con números tan grandes, vamos a usar la herramienta Big Integer Calculator. A continuación os dejo unas imágenes del proceso.

bigint_1

bigint_2

crackme_dihux_solved

Keygen

En esta ocasión hemos elegido Java ya que permite trabajar con números grandes de forma sencilla, os dejo el código más importante.

dihux_keygenme1_keygen

JButton btnNewButton = new JButton("Generar");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
BigInteger serial = new BigInteger("0");
BigInteger n = new BigInteger("871332984042175151665553882265818310920539633758381377421193");//módulo
BigInteger d = new BigInteger("316042180198461106401603389463895139535543421270452849695277");//exponente privado
BigInteger x = new BigInteger("4919");//0x1337
String nombre = t1.getText();
BigInteger nombre2 = new BigInteger(nombre.getBytes());
nombre2 = nombre2.multiply(x);
serial = nombre2.modPow(d, n);
t2.setText(serial.toString(16).toUpperCase());
}
});

Links


Warning: This challenge is still active and therefore should not be resolved using this information. Aviso: Este reto sigue en
Intro Aquí tenemos un crackme clásico realizado en Visual C++. La única particularidad que tiene es que no muestra MessageBox
Aviso: Este crackme forma parte de una serie de pruebas de Yoire.com que todavía está en activo. Lo ético si
Intro Hoy tenemos un crackme hecho en ensamblador y que cuenta con tres niveles. En el primero de todos nos

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.

Table of Contents

Intro

This crackme is for the challenge Mobile 2 of canyouhack.it.
This time you need to understand how the crackme works over the web.

Decompiling

The crackme is given again at Google Play, so the first step is to install and recover the APK for decompiling. The latter, I leave to you.
Open the victim with APK Studio and view the content of Mobile2.java
First we view one link:
http://canyouhack.it/Content/Challenges/Mobile/2/index.php
 If we go to the link, we view one string like a hash: 68a571bcf7bc9f76d43bf931f413ab2c. Umm, it’s like MD5. Go to decrypt online and we get the pass: «canyouhack.it». But if we test this password in the crackme, surprise!, nothing happens. We need to continue analyzing the code. Later we view the next interesting link:
«http://canyouhack.it/Content/Challenges/Mobile/2/submit.php?Token=» + Mobile2.token + «&Attempts=»
The program submit one token and concatenate with the number of attempts. Ok but what is the token and what is the number of attempts?
In this point we have to try with the information we already have.
Testing with the link of bottom we get “Nice try!” message.
http://canyouhack.it/Content/Challenges/Mobile/2/submit.php?Token=68a571bcf7bc9f76d43bf931f413ab2c&&Attempts=0
Testing with the link of bottom we get “Very Good, the password is Top*****!” message.
http://canyouhack.it/Content/Challenges/Mobile/2/submit.php?Token=68a571bcf7bc9f76d43bf931f413ab2c&&Attempts=1

  Links