Continuamos con los BTM awards. Esta vez analizaremos brevemente una escena de la película del casi siempre excelente James Cameron, Mentiras Arriesgadas. En esta ocasión vamos a analizar una situación que se da mucho en el cine de Hollywood, esto es, el Plug and Play mágico. Cuando vemos películas de espías, es habitual encontrarnos con situaciones en las que el protagonista conecta un «algo» en el ordenador al que quiere acceder y ¡chas!, como por arte de magia sin tocar ninguna tecla se copian o se borran unos archivos, le da acceso remoto a algún compañero etc.

BTM

Este film no iba a ser menos y es que cuando Harry Tasker (Arnold Schwarzenegger) con sus inigualables dotes para el espionaje, entra en la mansión del objetivo en cuestión, conecta un módem, lo enciende y sin teclear un solo comando le da a su compañero Faisil (Grant Heslov) que se encuentra en una furgoneta a unos kilómetros,  acceso a la máquina, nos quedamos perplejos.

vlcsnap-2015-11-25-11h24m51s404

Esta situación es posible en la vida real, lo que la hace difícil de creer es que Harry no teclee ni un solo comando al conectar el módem, independientemente del Sistema Operativo que corra la máquina. Si nos situamos un poco, estamos hablando del año 1995, con una máquina corriendo Windows 3.1 y estamos conectando un módem a un puerto RS-232. En aquella época, por avanzada que fuera la tecnología espía, es difícil de creer que las cosas funcionen solas. Otra cosa a destacar es que a no ser que Faisil estuviera conectados a un poste de teléfono, la conexión tendría que ser inalámbrica, casi una quimera hace 20 años. A continuación os muestro la secuencia.

Como se puede observar en el vídeo, incluso parece que el equipo de Faisil, que también corre Windows 3.1, accede al equipo en modo escritorio remoto, tecnología que no existía en aquella época. Para que la secuencia tuviera un mínimo de credibilidad, Harry al conectar el módem y encender el equipo, debiera de haber introducido un par de comandos como mínimo para asignarle un puerto COM al módem y así iniciar la comunicación con Faisil. Ni que decir tiene que Faisil hubiera tenido que hacer todas las transmisiones mediante línea de comandos.

Aunque la película es entretenida y me gustó mucho cuando la vi allá por el año 1998, no nos queda más remedio que ponerle nuestro sello BTM de NO credibilidad.

sellazoment

Enlaces

Otros posts que te pueden interesar

Los retos criptográficos son muy variados y muchas veces la dificultad está en saber a que te enfrentas. En este
Introducción Javascript 1 (Serial a la vista) Javascript 2 (La función charAt()) Javascript 3 (Input) Javascript 4 (Fuerza bruta manual) Javascript
Introducción Recién rescatados del inframundo que es mi disco duro, os traigo un paquete de seis crackmes facilones para vuestro
Aquí tenemos un crackme fuera de lo común, más que nada por que está programado en Brainfuck, un lenguaje de

Los retos criptográficos son muy variados y muchas veces la dificultad está en saber a que te enfrentas. En este caso pasa eso, te dan un código y si no has visto algo parecido en la vida, no sabes por donde empezar. El título del autor da una pequeña pista pero para los desconocedores no es suficiente. La pista es el título y dice «WTF?!?» y el código a descifrar es el siguiente:

[-]>[-]<
>+++++++++++[<+++++++++++>-]<.
>+++[<--->-]<-.
>++[<++>-]<++.
+.
>++++[<---->-]<-.
---.
+++.
.
>+++[<+++>-]<.
>+++[<--->-]<+.
>++++[<++++>-]<-.
>++++[<---->-]<--.
>+++[<+++>-]<-.
>++[<-->-]<--.
-.

Si eres una persona con recursos, realizaras varias búsquedas por la red y al final llegarás a la conclusión de que te enfrentas a BRAINFUCK, un lenguaje de programación esotérico como ya vimos en el reto de Root-Me.

Enlaces

Introducción

Los retos de Javascript son los retos más sencillos que podemos encontrar. Muchas veces solamente mirando el código fuente obtenemos la respuesta. Suponen una mala implementación de seguridad debido a que el código se ejecuta del lado del cliente, por lo que el código fuente es accesible y por lo tanto, javascript no garantiza seguridad alguna. En estos cinco casos haremos un recorrido por lo más básico, cinco retos fáciles de superar y que nos proporcionan los conocimientos base para Javascript. Dicho esto os puedo asegurar que en ocasiones he encontrado retos javascript realmente complicados que requieren de horas descifrarlos y en los que es fácil tirar la toalla.

Cuando el reto lo requiera, es buena idea utilizar un compilador online para obtener de forma rápida el valor de una variable o realizar una prueba concreta. Yo utilizo Jsfiddle para realizar pruebas pero existen muchos más.

Javascript 1

Este primer reto es lo básico, en el código fuente se pueden apreciar directamente el usuario y la clave.

<script language=JavaScript>
function Verify(name,pass)
{
if (name=="admin" & pass=="3***3")
	{
	location.href = name + pass + '.htm';
	}
else 
	{
	alert("Si ya fallamos el primero...");
	};
}
</script>

Javascript 2

Este segundo reto es bastante sencillo pero ya te obliga a conocer la función charAt() de Javascript. Dicha función lo que hace es coger el caracter indicado mediante un índice que comienza en cero. Por ejemplo si nombre = deurus y hacemos letra = nombre.charAt(3), estariámos extrayendo la cuarta letra, es decir, la letra r de la variable nombre.

function Verify(name,pass)
{
var name1 = "CrawlinG", pass1 = "capriccio"
	if (name==name1 & pass==pass1)
	{
	location.href = name + ".htm";
	}
else 
	{
	var x =  name1.charAt(7) + pass1.charAt(3)+ name1.charAt(2) + pass1.charAt(5) +  name1.charAt(5) + pass1.charAt(1);x = x.toLowerCase();
	var y =  name.charAt(3) + name.charAt(1) + pass.charAt(1)+ pass.charAt(6) +  pass.charAt(7) + name.charAt(2);var x1 = "des" + y;
	if (x==y){location.href = x1 + ".htm"}else{alert("Esto no va bien");location.href = "js2.htm"}
	}
}

Lo interesante está en la formación de las variables x e y. La variable x se forma de las variables name1 y pass1, formando la palabra gracia. Por otro lado, la variable y se forma con el nombre y clave que introduzcamos nosotros. Vemos que la variable x e y deben ser iguales, por lo tanto debemos construir un nombre (name) y una clave (pass) que cumpla con lo siguiente:

  • 4ª letra del nombre = 1ª letra de la palabra «gracia»
  • 2ª letra del nombre = 2ª letra de la palabra «gracia»
  • 2ª letra de la clave = 3ª letra de la palabra «gracia»
  • 7ª letra de la clave = 4ª letra de la palabra «gracia»
  • 8ª letra de la clave = 5ª letra de la palabra «graci
  • 3ª letra del nombre = 6ª letra de la palabra «gracia«

Como véis simplemente se trata de interpretar correctamente la función charAt() y de fijarse bien en los nombres de las variables.

Javascript 3

Este reto nos muestra diálogo donde nos pide la contraseña para validar el reto. Al fallar  o cancelar vuelve al índice para no dejarnos ver el código fuente. Aquí se pueden seguir varios caminos como bloquear el uso de javascript en el navegador o instalar un plugin en chrome o firefox para habilitar/deshabilitar de forma rápida el uso de javascript.

Una vez deshabilitado javascript vemos lo siguiente:

<script language="JavaScript" src="js3.gif" type=text/javascript>
<!--
function verify()
{
var pass="thebest";
var password=prompt("Introduce el password para superar el nivel","");
	if (password==pass)
		{
		location.href = pass + ".htm";
		}
	else
		{
		alert("No vamos bien...");
		location.href = "index.htm";
		}
}
//-->
</script>

Aquí el truco es darse cuenta que el código que se está ejecutando esta en «js3.gif» y no el código que nos muestra como válida la clave thebest. Si descargamos el archivo js3.gif y lo abrimos con un archivo de texto vemos nuestra querida clave.

function verify()
{
var pass="mo****ver";
var password=prompt("Introduce el password para superar el nivel","");
	if (password==pass)
		{
		location.href = pass + ".htm";
		}
	else
		{
		alert("No vamos bien...");
		location.href = "index.htm";
		}
}

Javascript 4

En este reto ya entramos con que la clave no es reversible y la debemos obtener por fuerza bruta. En este reto utiliza una nueva función como charCodeAt() que lo que hace es obtener el valor ascii del caracter indicado.

function Verify(pass1)
{
var cont1= 2, cont2= 6
var suma1 = 0, suma2 = 0
var pass2 = "FDRLF"
for(i = 0; i < pass1.length; i++) 
{
suma1 += (pass1.charCodeAt(i) * cont1);
cont1++
}
for(i = 0; i < pass2.length; i++) 
{
suma2 += (pass2.charCodeAt(i) * cont2);
cont2++
}
if (suma1==suma2)
{
window.location=suma1+".htm";
}
else
{
alert ("Algo no va bien...");
}
}

Vemos dos bucles en los que se calculan sendos valores suma que finalmente se comparan. la variable suma1 se calcula mediante nuestro password y la variable suma2 la obtiene de la palabra «FDRLF». Con el script que os muestro a continuación obtenemos que usando como clave deurus, suma1 = 3048 y suma2 = 2936. Nuestro punto de referencia es suma2 = 2936, de modo que vamos alterando con paciencia la variable pass1 obteniendo valores cercanos a 2936. Por ejemplo «deurua» nos da suma1 = 2922, un valor bastante cercano.

var pass1 = "deurus";
var cont1= 2, cont2= 6
var suma1 = 0, suma2 = 0
var pass2 = "FDRLF"
for(i = 0; i < pass1.length; i++) 
{
suma1 += (pass1.charCodeAt(i) * cont1);
cont1++
}
for(i = 0; i < pass2.length; i++) 
{
suma2 += (pass2.charCodeAt(i) * cont2);
cont2++
}
alert (suma1);
alert (suma2);

La solución a este reto es múltiple. Dos claves válidas son por ejemplo dfurqfzwfabz.

Javascript 5

Este último reto es similar al anterior pero ya nos obliga a crearnos una pequeña herramienta que nos busque el serial válido.

function Verify(pass)
{
var suma=0
var cadena = "abcdefghijklmnopqrstuvwxyz"
for (var i = 0; i < pass.length; i++) 
	{
	var letra = pass.charAt(i)
	var valor = (cadena.indexOf(letra))
	valor++
	suma *= 26
	suma += valor
	}
if (suma==6030912063)
	{
	window.location=pass+".htm";
	}
else
	{
	alert ("Algo no va bien...");
	}
}

Para esta ocasión utiliza una nueva función llamada indexOf() que lo que hace es devolver un número entero que representa la posición en la que se encuentra el parámetro pasado a la función. Por ejemplo, si tengo variable = deurus y realizo posición = variable.indexOf(«s»), obtengo como resultado 5 (se empieza a contar desde cero).

Las operaciones que realiza el bucle son las siguientes:

  • Coge las letras del nombre una a una.
  • valor = posición de nuestra letra dentro de la variable de texto llamada cadena.
  • valor = valor + 1.
  • Multiplica la variable suma por 26.
  • Suma = suma + valor.

Aunque el proceso de recuperación de esta clave es algo más largo, podemos acortarlo introduciendo una clave de inicio de fuerza bruta próxima al objetivo. Al ser una función bastante lineal podemos rápidamente mediante pruebas con nuestro código de fuerza bruta o con un compilador online, establecer que la clave tendrá 7 caracteres e incluso que para ahorrar tiempo podemos aproximar la clave para que su valor suma esté cercano al valor suma buscado 6030912063.

Realizando pruebas obtenemos:

  • Clave = aaaaaaa -> suma = 321272407
  • Clave = zzzzzzz -> suma = 8353082582
  • Clave = smaaaaa -> suma = 6024332887
  • Clave = smkkkkk -> suma = 6029085437

Como vemos, la clave smkkkkk ya está bastante próxima al objetivo y será un buen punto para lanzar la fuerza bruta.

Os dejo el código de fuerza bruta en .Net

Module Module1
    Sub Main()
inicio:
        Console.WriteLine("-------------------------")
        Console.WriteLine("Modo [1] Prueba password")
        Console.WriteLine("Modo [2] Fuerza bruta")
        Console.WriteLine("-------------------------")
        Dim modo = Console.ReadLine()
        '
        If modo = 2 Then
            Console.WriteLine("¿Password para comenzar?")
            Dim pass = Console.ReadLine()
inicio2:
            Dim cadena As String = "abcdefghijklmnopqrstuvwxyz"
            Dim valor As Integer = 0
            Dim suma As Long = 0
            Dim letra As String
            For i = 0 To pass.Length - 1
                letra = Mid(pass, i + 1, 1)
                valor = cadena.IndexOf(letra)
                valor += 1
                suma *= 26
                suma += valor
            Next
            Console.WriteLine("Password: " & pass & " - Sum: " & suma.ToString)
            pass = IncrementString(pass)
            If suma = 6030912063 Then
                MsgBox("Password is " & pass)
            Else
                If pass = "aaaaaaaa" Then
                    Console.WriteLine("pass not found")
                    Console.ReadKey()
                Else
                    GoTo inicio2
                End If
            End If
        End If
        '------------------------------------------------
        If modo = 1 Then
            Console.WriteLine("Password:")
            Dim pass = Console.ReadLine()
            Dim cadena As String = "abcdefghijklmnopqrstuvwxyz"
            Dim valor As Integer = 0
            Dim suma As Long = 0
            Dim letra As String
            For i = 0 To pass.Length - 1
                letra = Mid(pass, i + 1, 1)
                valor = cadena.IndexOf(letra)
                valor += 1
                suma *= 26
                suma += valor
            Next
            Console.WriteLine("Password: " & pass & " - Sum: " & suma.ToString)
            Console.WriteLine(".......")
            Console.WriteLine("Good = 6030912063")
            Console.WriteLine("Suma = " & suma.ToString)
            Console.ReadKey()
            Console.Clear()
            GoTo inicio
        End If
    End Sub
    Function IncrementString(ByVal strString As String) As String
        '
        ' Increments a string counter
        ' e.g.  "a" -> "b"
        '       "az" -> "ba"
        '       "zzz" -> "aaaa"
        '
        ' strString is the string to increment, assumed to be lower-case alphabetic
        ' Return value is the incremented string
        '
        Dim lngLenString As Long
        Dim strChar As String
        Dim lngI As Long

        lngLenString = Len(strString)
        ' Start at far right
        For lngI = lngLenString To 0 Step -1
            ' If we reach the far left then add an A and exit
            If lngI = 0 Then
                strString = "a" & strString
                Exit For
            End If
            ' Consider next character
            strChar = Mid(strString, lngI, 1)
            If strChar = "z" Then
                ' If we find Z then increment this to A
                ' and increment the character after this (in next loop iteration)
                strString = Left$(strString, lngI - 1) & "a" & Mid(strString, lngI + 1, lngLenString)
            Else
                ' Increment this non-Z and exit
                strString = Left$(strString, lngI - 1) & Chr(Asc(strChar) + 1) & Mid(strString, lngI + 1, lngLenString)
                Exit For
            End If
        Next lngI
        IncrementString = strString
        Exit Function

    End Function
End Module

Enlaces

Introducción

Recién rescatados del inframundo que es mi disco duro, os traigo un paquete de seis crackmes facilones para vuestro uso y disfrute. Desgraciadamente ya no está en activo la web de retos de donde los saqué así que os los dejo en descargas.

Los cuatro primero están realizados en Dev-C++ 4.9.9.2 siendo de estilo consola de comandos. Los dos restantes compilados con MingWin32 GCC 3.x carecen de GUI y vamos, que no se han esmerado mucho en darles forma.

Level 1

No cuesta mucho dar con el código interesante mediante las referencias de texto. En Ollydbg clic derecho sobre el código y Search for > All referenced text strings.

004012E1   |.  8845 E8         MOV BYTE PTR SS:[EBP-18],AL                                    ; ||||
004012E4   |.  C70424 11304000 MOV DWORD PTR SS:[ESP],level1.00403011                         ; ||||ASCII "Input Serial: "
004012EB   |.  E8 C0050000     CALL <JMP.&msvcrt.printf>                                      ; |||\printf
004012F0   |.  8D45 C8         LEA EAX,[LOCAL.14]                                             ; |||
004012F3   |.  894424 04       MOV DWORD PTR SS:[ESP+4],EAX                                   ; |||
004012F7   |.  C70424 20304000 MOV DWORD PTR SS:[ESP],level1.00403020                         ; |||ASCII "%s"
004012FE   |.  E8 9D050000     CALL <JMP.&msvcrt.scanf>                                       ; ||\scanf
00401303   |.  8D45 D8         LEA EAX,[LOCAL.10]                                             ; ||
00401306   |.  8D55 C8         LEA EDX,[LOCAL.14]                                             ; ||
00401309   |.  894424 04       MOV DWORD PTR SS:[ESP+4],EAX                                   ; ||
0040130D   |.  891424          MOV DWORD PTR SS:[ESP],EDX                                     ; ||level1.00403022
00401310   |.  E8 7B050000     CALL <JMP.&msvcrt.strcmp>                                      ; |\strcmp
00401315   |.  8945 C4         MOV [LOCAL.15],EAX                                             ; |
00401318   |.  837D C4 00      CMP [LOCAL.15],0                                               ; |
0040131C   |.  75 0E           JNZ SHORT level1.0040132C                                      ; |
0040131E   |.  C70424 23304000 MOV DWORD PTR SS:[ESP],level1.00403023                         ; |ASCII "Well done. \n"
00401325   |.  E8 86050000     CALL <JMP.&msvcrt.printf>                                      ; \printf
0040132A   |.  EB 0C           JMP SHORT level1.00401338
0040132C   |>  C70424 30304000 MOV DWORD PTR SS:[ESP],level1.00403030                         ; |ASCII "Wrong. \n"
00401333   |.  E8 78050000     CALL <JMP.&msvcrt.printf>                                      ; \printf
00401338   |>  C70424 39304000 MOV DWORD PTR SS:[ESP],level1.00403039                         ; |ASCII "PAUSE"
0040133F   |.  E8 3C050000     CALL <JMP.&msvcrt.system>                                      ; \system
00401344   |.  B8 00000000     MOV EAX,0
00401349   |.  C9              LEAVE
0040134A   \.  C3              RETN

La madre del cordero está en la dirección 401310 que es donde se lleva a cabo la función de comparación strcmp.

756296A0 msvcrt.strcmp     8B5424 04         MOV EDX,DWORD PTR SS:[ESP+4]
756296A4                   8B4C24 08         MOV ECX,DWORD PTR SS:[ESP+8] 
756296A8                   F7C2 03000000     TEST EDX,3				; 0-3 = 4 bucles. Divide la comprobación en 4 bloques
756296AE                   75 3C             JNZ SHORT msvcrt.756296EC		; salta si hemos terminado los 4 bucles
756296B0                 > 8B02              MOV EAX,DWORD PTR DS:[EDX]		; coge 4 caracteres del serial (INICIO BUCLE)
756296B2                   3A01              CMP AL,BYTE PTR DS:[ECX]		; compara el 1º/5º/9º/13º dígito en función del bucle
756296B4                   75 2E             JNZ SHORT msvcrt.756296E4		; salto a zona mala
756296B6                   0AC0              OR AL,AL
756296B8                   74 26             JE SHORT msvcrt.756296E0
756296BA                   3A61 01           CMP AH,BYTE PTR DS:[ECX+1]		; compara el 2º/6º/10º/14º dígito en función del bucle
756296BD                   75 25             JNZ SHORT msvcrt.756296E4		; salto a zona mala
756296BF                   0AE4              OR AH,AH
756296C1                   74 1D             JE SHORT msvcrt.756296E0
756296C3                   C1E8 10           SHR EAX,10
756296C6                   3A41 02           CMP AL,BYTE PTR DS:[ECX+2]		; compara el 3º/7º/11º/15º dígito en función del bucle
756296C9                   75 19             JNZ SHORT msvcrt.756296E4		; salto a zona mala
756296CB                   0AC0              OR AL,AL
756296CD                   74 11             JE SHORT msvcrt.756296E0
756296CF                   3A61 03           CMP AH,BYTE PTR DS:[ECX+3]		; compara el 4º/8º/12º/16º dígito en función del bucle
756296D2                   75 10             JNZ SHORT msvcrt.756296E4		; salto a zona mala
756296D4                   83C1 04           ADD ECX,4
756296D7                   83C2 04           ADD EDX,4
756296DA                   0AE4              OR AH,AH
756296DC                 ^ 75 D2             JNZ SHORT msvcrt.756296B0		; Si no hemos terminado... 
756296DE                   8BFF              MOV EDI,EDI                         
756296E0                   33C0              XOR EAX,EAX			; EAX = 0 que es lo deseado
756296E2                   C3                RETN				; salimos de la función superando la comprobación
756296E3                   90                NOP							
756296E4                   1BC0              SBB EAX,EAX			; Zona mala
756296E6                   D1E0              SHL EAX,1
756296E8                   83C0 01           ADD EAX,1				; EAX = 1 implica bad boy
756296EB                   C3                RETN				; salimos de la función

Si atendemos al volcado vemos el serial bueno Kcgcv8LsmV3nizfJ.

0060FEF0  31 32 33 34 35 36 37 38 39 30 00 75 40 19 18 00  1234567890.u@.
0060FF00  4B 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A  Kcgcv8LsmV3nizfJ

Curiosamente, si introducimos el serial bueno el crackme no lo acepta. Fijándome en la comprobación veo que al introducir un serial de 16 caracteres inserta un carácter nulo (0x00) alterando el serial correcto y falseando la comprobación.

0060FEF0  4B 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A  Kcgcv8LsmV3nizfJ
0060FF00  00 63 67 63 76 38 4C 73 6D 56 33 6E 69 7A 66 4A  .cgcv8LsmV3nizfJ

Ahora ya no podemos comprobarlo pero recuerdo que la web consideraba válido el serial Kcgcv8LsmV3nizfJ, por lo que considero lo anteriormente citado un bug o un intento de despiste del autor.

Level 2

Es exactamente igual que el anterior cambiando el serial por 6LPw3vDYja9KrT2V.

Level 3

La comprobación del serial es igual a las dos anteriores pero añade una función intermedia que suma 0xD a cada carácter de nuestro serial

00401355                 |.  A1 03304000     MOV EAX,DWORD PTR DS:[403003]                  ; ||
0040135A                 |.  8945 E8         MOV [LOCAL.6],EAX                              ; ||
0040135D                 |.  A1 07304000     MOV EAX,DWORD PTR DS:[403007]                  ; ||
00401362                 |.  8945 EC         MOV [LOCAL.5],EAX                              ; ||
00401365                 |.  A1 0B304000     MOV EAX,DWORD PTR DS:[40300B]                  ; ||
0040136A                 |.  8945 F0         MOV [LOCAL.4],EAX                              ; ||
0040136D                 |.  A1 0F304000     MOV EAX,DWORD PTR DS:[40300F]                  ; ||
00401372                 |.  8945 F4         MOV [LOCAL.3],EAX                              ; ||
00401375                 |.  C70424 13304000 MOV DWORD PTR SS:[ESP],level3.00403013         ; ||ASCII "Input Serial: "
0040137C                 |.  E8 CF050000     CALL <JMP.&msvcrt.printf>                      ; |\printf
00401381                 |.  8D45 D8         LEA EAX,[LOCAL.10]                             ; |
00401384                 |.  894424 04       MOV DWORD PTR SS:[ESP+4],EAX                   ; |
00401388                 |.  C70424 00304000 MOV DWORD PTR SS:[ESP],level3.00403000         ; |ASCII "%s"
0040138F                 |.  E8 AC050000     CALL <JMP.&msvcrt.scanf>                       ; \scanf
00401394                 |.  8D5D E8         LEA EBX,[LOCAL.6]
00401397                 |.  8D45 D8         LEA EAX,[LOCAL.10]
0040139A                 |.  890424          MOV DWORD PTR SS:[ESP],EAX
0040139D                 |.  E8 EEFEFFFF     CALL level3.00401290			    ; NUEVA FUNCIÓN SUMA
004013A2                 |.  895C24 04       MOV DWORD PTR SS:[ESP+4],EBX                   ; ||
004013A6                 |.  890424          MOV DWORD PTR SS:[ESP],EAX                     ; ||
004013A9                 |.  E8 82050000     CALL <JMP.&msvcrt.strcmp>                      ; |\strcmp
004013AE                 |.  8945 D4         MOV [LOCAL.11],EAX                             ; |
004013B1                 |.  837D D4 00      CMP [LOCAL.11],0                               ; |
004013B5                 |.  75 0E           JNZ SHORT level3.004013C5                      ; |
004013B7                 |.  C70424 22304000 MOV DWORD PTR SS:[ESP],level3.00403022         ; |ASCII "Well done."
004013BE                 |.  E8 8D050000     CALL <JMP.&msvcrt.printf>                      ; \printf
004013C3                 |.  EB 0C           JMP SHORT level3.004013D1
004013C5                 |>  C70424 2D304000 MOV DWORD PTR SS:[ESP],level3.0040302D         ; |ASCII "Wrong. \n"
004013CC                 |.  E8 7F050000     CALL <JMP.&msvcrt.printf>                      ; \printf
004013D1                 |>  C70424 36304000 MOV DWORD PTR SS:[ESP],level3.00403036         ; |ASCII "PAUSE"
004013D8                 |.  E8 43050000     CALL <JMP.&msvcrt.system>                      ; \system
004013DD                 |.  B8 00000000     MOV EAX,0
004013E2                 |.  8B5D FC         MOV EBX,[LOCAL.1]                              
004013E5                 |.  C9              LEAVE
004013E6                 \.  C3              RETN
--------
004012A4                 |> /8B45 08         /MOV EAX,[ARG.1]                               ; |
004012A7                 |. |890424          |MOV DWORD PTR SS:[ESP],EAX                    ; |
004012AA                 |. |E8 B1060000     |CALL <JMP.&msvcrt.strlen>                     ; \strlen
004012AF                 |. |3945 FC         |CMP [LOCAL.1],EAX
004012B2                 |. |73 1C           |JNB SHORT level3.004012D0
004012B4                 |. |8B45 08         |MOV EAX,[ARG.1]
004012B7                 |. |8B55 FC         |MOV EDX,[LOCAL.1]
004012BA                 |. |01C2            |ADD EDX,EAX
004012BC                 |. |8B45 08         |MOV EAX,[ARG.1]
004012BF                 |. |0345 FC         |ADD EAX,[LOCAL.1]
004012C2                 |. |0FB600          |MOVZX EAX,BYTE PTR DS:[EAX]
004012C5                 |. |04 0D           |ADD AL,0D					    ; char + 0xD
004012C7                 |. |8802            |MOV BYTE PTR DS:[EDX],AL
004012C9                 |. |8D45 FC         |LEA EAX,[LOCAL.1]
004012CC                 |. |FF00            |INC DWORD PTR DS:[EAX]
004012CE                 |.^\EB D4           \JMP SHORT level3.004012A4
--------
756296A0 msvcrt.strcmp     8B5424 04         MOV EDX,DWORD PTR SS:[ESP+4]
756296A4                   8B4C24 08         MOV ECX,DWORD PTR SS:[ESP+8]
756296A8                   F7C2 03000000     TEST EDX,3
756296AE                   75 3C             JNZ SHORT msvcrt.756296EC
756296B0                   8B02              MOV EAX,DWORD PTR DS:[EDX]
756296B2                   3A01              CMP AL,BYTE PTR DS:[ECX]
756296B4                   75 2E             JNZ SHORT msvcrt.756296E4
756296B6                   0AC0              OR AL,AL
756296B8                   74 26             JE SHORT msvcrt.756296E0
756296BA                   3A61 01           CMP AH,BYTE PTR DS:[ECX+1]
756296BD                   75 25             JNZ SHORT msvcrt.756296E4
756296BF                   0AE4              OR AH,AH
756296C1                   74 1D             JE SHORT msvcrt.756296E0
756296C3                   C1E8 10           SHR EAX,10
756296C6                   3A41 02           CMP AL,BYTE PTR DS:[ECX+2]
756296C9                   75 19             JNZ SHORT msvcrt.756296E4
756296CB                   0AC0              OR AL,AL
756296CD                   74 11             JE SHORT msvcrt.756296E0
756296CF                   3A61 03           CMP AH,BYTE PTR DS:[ECX+3]
756296D2                   75 10             JNZ SHORT msvcrt.756296E4
756296D4                   83C1 04           ADD ECX,4
756296D7                   83C2 04           ADD EDX,4
756296DA                   0AE4              OR AH,AH
756296DC                 ^ 75 D2             JNZ SHORT msvcrt.756296B0
756296DE                   8BFF              MOV EDI,EDI
756296E0                   33C0              XOR EAX,EAX
756296E2                   C3                RETN
756296E3                   90                NOP
756296E4                   1BC0              SBB EAX,EAX
756296E6                   D1E0              SHL EAX,1
756296E8                   83C0 01           ADD EAX,1
756296EB                   C3                RETN

En la comparación vemos que el serial bueno es AvrQQsXjDk25Jrh por lo que si restamos 0xD (13 en decimal) a cada carácter obtendremos el serial bueno.

0060FF10  41 76 72 51 51 73 58 6A 44 6B 32 35 4A 72 68 00  AvrQQsXjDk25Jrh.

		  41 76 72 51 51 73 58 6A 44 6B 32 35 4A 72 68
	                                                      - D
		  34 69 65 44 44 66 4B 5D 37 5E 25 28 3D 65 5B
		  4  i  e  D  D  f  K  ]  7  ^  %  (  =  e  [
		  
		  Serial bueno: 4ieDDfK]7^%(=e[

Level 4

La comprobación del serial es igual que la anterior pero sustituyendo la función que sumaba un valor a cada dígito del serial por una que genera un hash con nuestro serial y después lo compara con otro hash almacenado en memoria. Si no nos viene a la mente el tipo de hash que puede ser PEiD ya nos avisaba de que efectivamente el crackme incorpora la función MD5.

La función MD5 hace tiempo que no se considera segura debido a la existencia de numerosos «diccionarios» de hashes que hacen que encontremos la solución en segundos. Yo he utilizado la web MD5 online pero existen muchas más.

0060FE5C   004013BF  RETURN to level4.004013BF from <JMP.&msvcrt.strcmp>
0060FE60   0060FEA0  ASCII "e807f1fcf82d132f9bb018ca6738a19f"
0060FE64   0060FEE0  ASCII "fe01d67a002dfa0f3ac084298142eccd"


e807f1fcf82d132f9bb018ca6738a19f == 1234567890
fe01d67a002dfa0f3ac084298142eccd == orange

Level 5

La carta de presentación de este crackme es la imagen que veis arriba. Al explorarlo unos minutos enseguida nos damos cuenta de que no realiza ninguna comprobación y que nos está haciendo perder el tiempo. Ahí es cuando empezamos a revisar el ejecutable más a fondo y enseguida encontramos la solución con nuestro amigo el editor hexadecimal.

the answer is AttachedString

Level 6

Misma carta de presentación que el anterior y misma ausencia de comprobación del serial. En esta ocasión echando un vistazo a los recursos encontramos la solución rápidamente.

Enlaces

Aquí tenemos un crackme fuera de lo común, más que nada por que está programado en Brainfuck, un lenguaje de programación esotérico bastante complejo.

[-]>[-]<>++++++++[<++++++++++>-]<.+++++++++++++++++.>+++[<++++++>-]<..++++.-
-------.+++.--------------.>++++++[<------>-]<-.>+++++[<------>-]<-.,>,>,>,>
>>>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++>>>>+++++++++++++++++++++++++++++++++++++++++
+++++++++++>>>>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++>>>>++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<<<
<<<<<<<<<<<<<<<<[>>>>>>>-<<<<<<<-]>>>>>>><<+>>[[-]++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++.<]<[>]<<<<<[>>>>>>>>>>-<<<<<<<<
<<-]>>>>>>>>>><<+>>[[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++.<]<[>]<<<<<<<<[>>>>>>>>>>>>>-<<<<<<<<<<<<<-]>>>>>>>>>>>>><<+>>[
[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.<]<[>]<<<<<<<<<<<[>>>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>><<+>>[
[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++.<]<[>]>>>[-]>[-]<+++++++++++++.---.>+++++++[<++++++++++++>-]<.>+++++++[<
--------->-]<+.>+++++[<++++++++>-]<+.>++++[<+++++++>-]<+.>+++++++[<---------
->-]<.>++++++++[<+++++++++>-]<+.+++++++++++.>+++++++[<----------->-]<.>+++++
++[<+++++++++++>-]<-.>+++++++[<------------>-]<+.>++++++++[<+++++++++++>-]<-
.-----.---------.+++++++++++..---------------.+++++++++.>++++++[<-----------
-->-]<.+++++++.>+++++[<++++++>-]<+.-----.++++++++.+++.>++++++[<------>-]<-.-
------.>++++++++[<++++++++++>-]<-.+++.>+++++++++[<--------->-]<-.+++++++.>++
+++[<++++++>-]<+.-----.+++++++++++.>++++++[<------>-]<-.-------.>++++++++[<+
+++++++++>-]<-.+++.>+++++++++[<--------->-]<-.+++++++.>+++++[<+++++>-]<+.+++
+++++.+++.>++++++[<------>-]<-.+++++++...--------------.>++++++++[<+++++++++
++>-]<+.----------.++++++.>+++++++[<------------>-]<-.>++++++++[<+++++++++>-
]<.-------.>+++[<+++++++>-]<.-----------------.>+++++++[<---------->-]<+.>++
+++++[<++++++++++>-]<.-----.++++++++.+++.-------.-.>++++++[<--------->-]<.--
------------.>+++++[<++++++++>-]<+.>++++[<+++++++>-]<+.>+++++++[<---------->
-]<.>+++++++[<++++++++++++>-]<.------------.---.+++++++++++++.-------------.
>+++++++[<---------->-]<+.>++++++++[<+++++++++>-]<+.++++++++++.>+++++++[<---
--------->-]<+.>++++++[<+++++++++++++>-]<.+.+++++.------------.+.+++++.-----
--.>++++++[<---------->-]<+.------------.>++++++++[<+++++++++++>-]<+.-------
---.++++++.>+++++++[<------------>-]<-.>++++++++[<+++++++++>-]<.-------.>+++
[<+++++++>-]<.-----------------.>+++++++[<---------->-]<+.>++++++++[<+++++++
++++>-]<-.--------------.+++++.>++++++[<------------->-]<.+.

La solución que he encontrado yo, es convertir el código brainfuck a algo más amigable y depurarlo hasta encontrar la solución. La conversión la he realizado con VBBrainFNET y luego la depuración con Visual Studio. El crackme te pide una clave de cuatro cifras para darte la solución, pero si no quieres volverte loco puedes amañar los bucles para encontrar la solución.

¡SUERTE!

Enlaces