martes, 19 de marzo de 2019

Reversing(XII): Solución Reto Yoire "04_crackme_hard"

En este post la solución a otro de los retos de 'reversing' de la plataforma Yoire.

Este reto tiene el título "04_crackme_hard" y mi valoración sobre su dificultad es:  ☆☆.

Su enunciado dice lo siguiente:

Descarga y analiza el ejecutable (PE) suministrado, e indica la solución en el recuadro de texto mostrado más abajo.

Y nos dan un archivo ejecutable (04_crackme_hard.exe).

Solución: Abro el archivo en OllyDbg. Lo ejecuto en modo depuración y aparece el siguiente mensaje:
El programa detecta que se está ejecutando desde un depurador ('debugger') y muestra esta ventana con objeto de evitar el análisis.

Intento averiguar qué técnica 'anti-debugging' está utilizando para ver si puedo evitar esa protección. Para ello, reinicio la ejecución en modo depuración y busco todas las llamadas con destino fuera del módulo actual realizadas en el programa (en la parte superior izquierda de la ventana principal: clic botón derecho, 'Search for' > 'All intermodular calls'):
Y obtengo lo siguiente:
En la figura anterior se ve la llamada a la función IsDebuggerPresent, una función de la librería Kernel32.dll que devuelve un valor distinto de 0 si el programa está siendo 'debuggeado' y 0 en caso contrario.

Se trata de una técnica 'anti-debugging' muy fácil de implementar, ya que basta con realizar la llamada a la función y comprobar el valor que devuelve, pero también es muy fácil de evitar.

Hago doble clic sobre esa llamada y voy a la parte del código donde se encuentra:
Como se observa en la figura anterior, justo después de la llamada a esta función, se comprueba el valor del registro EAX y si éste es cero (el programa no está siendo 'debuggeado') se produce un salto a la dirección 0x40102D

Pongo un punto de interrupción en la instrucción de salto condicional (JZ) y ejecuto el programa en modo depuración:
Como se observa en las figuras anteriores, el valor de EAX es diferente de cero (el programa está siendo 'debuggeado') y, por tanto, no se producirá el salto y el programa continuará para mostrar la ventana en la que se indica que se aborta la ejecución.

Para saltarnos esta protección simplemente cambiamos la instrucción JZ por su contraria (JNZ):
Y como se ve en la figura anterior, ahora el salto se produce y el programa se comportará como si no estuviera siendo 'debuggeado', y se me pide que introduzca un número de serie. Incluyo una cadena cualquiera de caracteres y dígitos, por ejemplo: "abc123", y, tras pulsar 'Check serial', se muestra un mensaje de error:
Reinicio la ejecución en modo depuración y, como siempre suelo hacer cuando utilizo OllyDbg, empiezo el análisis buscando todas las cadenas de texto o 'strings' utilizadas en el programa (en la parte superior izquierda de la ventana principal: clic botón derecho, 'Search for' > 'All referenced strings'):
Y obtengo lo siguiente:
Como se observa en la figura anterior, entre las cadenas de texto está el mensaje de error que me ha aparecido al ejecutar el programa: "Sorry, the serial is invalid :("y también el mensaje que supuestamente aparecerá si introduzco el número de serie correcto"Your serial is valid :)". Si hago doble clic sobre este último voy a la parte del código donde se encuentra esta cadena de texto:
Como se ve en la figura anterior, hay 11 comparaciones de caracteres predeterminados con el contenido de ciertos Bytes de memoria en los que se incluyen los caracteres que se introducen como número de serie. Por tanto, el número de serie correcto tiene 11 caracteres de longitud.

Tras cada una de las comparaciones, si los dos caracteres son iguales se continuará con la siguiente comparación, mientras que si son distintos se produce un salto a la dirección 0x00401204 y el programa mostrará el mensaje de error. Si los caracteres en todas las comparaciones son iguales se mostrará el mensaje de éxito.

Para verlo exactamente pongo un punto de interrupción en la primera comparación de caracteres. Ejecuto el programa en modo depuración, me salto la protección 'anti-debugging' como ya he explicado anteriormente, introduzco como número de serie "123456789ab" y el programa se parará en el punto de interrupción que he puesto en la primera comparación. Voy ejecutando una detrás de otra (tras cada una de ellas si los dos caracteres comparados son distintos habrá que cambiar la instrucción JNE que le sigue por su contraria - JE -, para que se continúe con la siguiente comparación) y veo lo siguiente (el primer carácter que se indica es fijo, mientras que el segundo se corresponde con el valor de un Byte de memoria que contiene uno de los caracteres introducidos como número de serie):

- En la primera comparación se compara 'b' (código ASCII 62 en hexadecimal) con 'a' (código ASCII 61 en hexadecimal). El carácter 'a' es el que ocupa la posición 10 entre los caracteres introducidos como número de serie, por lo que 'b' es el décimo carácter del número de serie correcto.

- En la segunda comparación se compara 'y' (código ASCII 79 en hexadecimal) con '8' (código ASCII 38 en hexadecimal). El carácter '8' es el que ocupa la posición 8 entre los caracteres introducidos como número de serie, por lo que 'y' es el octavo carácter del número de serie correcto.

- En la tercera comparación se compara 'l' (código ASCII 6C en hexadecimal) con '6' (código ASCII 36 en hexadecimal). El carácter '6' es el que ocupa la posición 6 entre los caracteres introducidos como número de serie, por lo que 'l' es el sexto carácter del número de serie correcto.

- En la cuarta comparación se compara 'e' (código ASCII 65 en hexadecimal) con '4' (código ASCII 34 en hexadecimal). El carácter '4' es el que ocupa la posición 4 entre los caracteres introducidos como número de serie, por lo que 'e' es el cuarto carácter del número de serie correcto.

- En la quinta comparación se compara 'i' (código ASCII 69 en hexadecimal) con '2' (código ASCII 32 en hexadecimal). El carácter '2' es el que ocupa la posición 2 entre los caracteres introducidos como número de serie, por lo que 'i' es el segundo carácter del número de serie correcto.

- En la sexta comparación se compara 'l' (código ASCII 6C en hexadecimal) con '1' (código ASCII 31 en hexadecimal). El carácter '1' es el que ocupa la posición 1 entre los caracteres introducidos como número de serie, por lo que 'l' es el primer carácter del número de serie correcto.

- En la séptima comparación se compara 'k' (código ASCII 6B en hexadecimal) con '3' (código ASCII 33 en hexadecimal). El carácter '3' es el que ocupa la posición 3 entre los caracteres introducidos como número de serie, por lo que 'k' es el tercer carácter del número de serie correcto.

- En la octava comparación se compara 'o' (código ASCII 6F en hexadecimal) con '5' (código ASCII 35 en hexadecimal). El carácter '5' es el que ocupa la posición 5 entre los caracteres introducidos como número de serie, por lo que 'o' es el quinto carácter del número de serie correcto.

- En la novena comparación se compara 'l' (código ASCII 6C en hexadecimal) con '7' (código ASCII 37 en hexadecimal). El carácter '7' es el que ocupa la posición 7 entre los caracteres introducidos como número de serie, por lo que 'l' es el séptimo carácter del número de serie correcto.

- En la décima comparación se compara 'd' (código ASCII 64 en hexadecimal) con '9' (código ASCII 39 en hexadecimal). El carácter '9' es el que ocupa la posición 9 entre los caracteres introducidos como número de serie, por lo que 'd' es el noveno carácter del número de serie correcto.

- En la undécima comparación se compara 'g' (código ASCII 67 en hexadecimal) con 'b' (código ASCII 62 en hexadecimal). El carácter 'b' es el que ocupa la posición 11 entre los caracteres introducidos como número de serie, por lo que 'g' es el undécimo carácter del número de serie correcto.

Por tanto, el número de serie correctos es: "likeollydbg".

Para comprobar si lo he hecho bien ejecuto el programa e introduzco "likeollydbg" como número de serie:
Pulso 'Check serial' y se muestra el mensaje de éxito:
Y lo único que me falta para superar este reto es introducir el número de serie correcto en la plataforma:

lunes, 18 de marzo de 2019

Reversing(XI): Solución Reto Yoire "01_crackme_very_easy"

En este post la solución a uno de los retos de 'reversing' de la plataforma Yoire.

Este reto tiene el título "01_crackme_very_easy" y mi valoración sobre su dificultad es:  ☆☆.

Su enunciado dice lo siguiente:

Descarga y analiza el ejecutable (PE) suministrado, e indica la solución en el recuadro de texto mostrado más abajo.

Y nos dan un archivo ejecutable (01_crackme_very_easy.exe).

Solución: Ejecuto este fichero y se me pide que introduzca un número de serieIncluyo una cadena cualquiera de caracteres y dígitos, por ejemplo: "abc123", y, tras pulsar 'Check serial', se muestra un mensaje de error:
Utilizo OllyDbg para realizar un análisis dinámico de la aplicación. Abro en esta herramienta el archivo ejecutable y empiezo el análisis buscando todas las cadenas de texto o 'strings' utilizadas en el programa (en la parte superior izquierda de la ventana principal: clic botón derecho, 'Search for' > 'All referenced strings'):
Y obtengo lo siguiente:
Entre ellas hay una cadena muy sospechosa :) "AreYouLookingAtMe?", que posiblemente sea incluso el número de serie que estoy buscando, ya que este reto está catalogado en la propia plataforma como muy fácil. Si hago doble clic sobre este mensaje voy a la parte del código donde se encuentra esa cadena de texto.

Pongo un punto de interrupción en la instrucción en 0x0040113C y otro en la que se encuentra en 0x0040115A. En esta última, en función del valor contenido en el registro EAX, se bifurcará para que el programa muestre el mensaje de error o, por el contrario, se continuará para mostrar el mensaje de éxito.

Ejecuto la aplicación en modo depuración y vuelvo a introducir "abc123" como número de serie. Tras pulsar el botón 'Check serial', el programa se detiene en el primer punto de interrupción que he puesto:  
El registro ECX contiene la dirección a partir de la que se almacena el número de serie que he introducido ("abc123") y EAX contiene la longitud del mismo.

Además, tras la ejecución de la instrucción en la que he puesto el punto de interrupción, EDX contendrá la dirección a partir de la que se almacenará la cadena "AreYouLookingAtMe?":
Un poco más adelante veo como se moverá el primer carácter del número de serie que he introducido ("a") a AL y en la instrucción siguiente que éste se comparará con el primer carácter de la cadena sospechosa ("AreYouLookingAtMe?").
Si ambos caracteres son diferentes en la siguiente instrucción (JNE) se producirá el salto a la instrucción indicada y se continuará hasta mostrar el mensaje de error. En el caso de que sean iguales se repetirá el proceso con el segundo carácter del número de serie introducido y de la cadena sospechosa, y así sucesivamente. Finalmente, si el número de serie introducido coincide con "AreYouLookingAtMe?" se mostrará el mensaje de éxito.

Para ver si estoy en lo cierto ejecuto el programa e introduzco "AreYouLookingAtMe?" como número de serie:
Pulso 'Check serial' y se muestra el mensaje de éxito:
Y lo único que me falta para superar este reto es introducir el número de serie correcto en la plataforma:

domingo, 17 de marzo de 2019

Reversing(X): Solución Reto RingZer0 Team "Windows x86 Reversing is cool!"

En este post la solución a uno de los retos de 'reversing' de la plataforma RingZer0 Team.

Este reto tiene el título "Windows x86 Reversing is cool!" y mi valoración sobre su dificultad es:  ☆☆.

Su enunciado dice lo siguiente:

The key of this challenge is to understood what`s going on.

Y nos dan un archivo ejecutable (1231fa8523f32a9118993946bccfb9ec203.exe).

Solución: Ejecuto este fichero se me pide que introduzca una clave:
Introduzco una cadena cualquiera de caracteres y dígitos, por ejemplo: "abc123", y se muestra un mensaje de error:
Utilizo OllyDbg para realizar un análisis dinámico de la aplicación. Abro en esta herramienta el archivo ejecutable y empiezo el análisis buscando todas las cadenas de texto o 'strings' utilizadas en el programa (en la parte superior izquierda de la ventana principal: clic botón derecho, 'Search for' > 'All referenced strings'):
Y obtengo lo siguiente:
Como se observa en la figura anterior, entre las cadenas de texto está el mensaje de error que me ha aparecido al ejecutar el programa: "Wrong Key!". Si hago doble clic sobre este mensaje voy a la parte del código donde se encuentra esta cadena de texto:
Dos líneas más arriba de la instrucción en 0x0040140B, veo una instrucción que comparará la longitud de la cadena que introduzca como clave con 6, y la instrucción que está justo debajo de ésta (JE) no saltará a la instrucción indicada si dicha longitud es diferente de 6 y, en ese caso, se mostrará el mensaje de error. Es decir, la longitud de la clave correcta es 6.

Para ver lo que he dicho en el párrafo anterior pongo un punto de interrupción en la instrucción de salto condicional (JE) en 0x00401409. Reinicio la ejecución en modo depuración e introduzco nuevamente la cadena "abc123" como clave: 
En las figuras anteriores veo que el registro ECX contiene la dirección a partir de la cual se almacena la cadena de caracteres que he introducido como clave y el registro EAX contiene la longitud de ésta, y, en consecuencia, como el valor de este último registro es igual a 6, en la instrucción en la que he puesto el punto de interrupción se producirá el salto a la dirección 0x0040146F.

A continuación el programa se introduce en un bucle que ejecuta 6 veces (longitud de la cadena incluida como clave y también de la correcta) y realiza una operación XOR entre cada uno de los caracteres de la cadena incluida como clave y el valor D3 en hexadecimal (211 en decimal).

Para ver esto último pongo un punto de interrupción en la instrucción de salto condicional (JB) en 0x00401483 y continúo con la ejecución en modo depuración hasta ese 'breakpoint':
En las figuras anteriores se ve que el registro EBX contiene el valor 0 y el registro EAX contiene la longitud de la cadena que he introducido como clave, y, en consecuencia, como el valor contenido en EBX es menor que 6, en la instrucción en la que he puesto el punto de interrupción se producirá el salto a la dirección 0x00401423.

A partir de la dirección a la que se produce el salto el programa realizará una operación XOR entre el primer carácter de la cadena incluida como clave (el código ASCII en hexadecimal de "a" es 61, en decimal 97) y el valor D3 en hexadecimal (211 en decimal).

Posteriormente el programa comparará el resultado de esa operación XOR con un valor determinado y si ambos son distintos se mostrará el mensaje de error, mientras que si ambos son iguales se continuará con el segundo carácter de la clave introducida, y así sucesivamente.

Para verlo pongo dos puntos de interrupción, el primero en la instrucción que realiza la operación XOR y el segundo en la instrucción de salto condicional (JE) en función de si el resultado de dicha operación es igual a un valor determinado o no.
Como se ve en las figuras anteriores:

1.- En la instrucción XOR en 0x00401430 se almacena en DX el resultado de la operación:

00000061 XOR FFFFFFD3 = FFFFFFB2

2.- En la instrucción CMP en 0x0040144E se compara el valor de AL (97 en hexadecimal) con el valor de DL (B2 en hexadecimal).

3.- Como AL y DL son diferentes no se produce el salto en la instrucción JE en 0x00401450 y se mostrará el mensaje de error.

Por tanto, me queda claro que el primer carácter de la clave tiene que ser el resultado de:

97 XOR D3 = 44  

El carácter correspondiente al código ASCII 44 en hexadecimal (68 en decimal) es "D".

Como he introducido como clave una cadena cualquiera ("abc123") y, como era más que probable, el resultado de la operación XOR del primer carácter ("a", 61 en hexadecimal) con D3 no es igual que el esperado por el programa (97 en hexadecimal), tal y como ya he dicho, el programa finalizará mostrando el mensaje de error. Para evitar esto último y poder calcular los 5 caracteres restantes de la clave correcta hago lo siguiente:

1.- Tras la primera operación XOR modifico DL poniendo 97 en lugar de B2:
Con lo que el programa realizará la operación XOR entre el segundo carácter de la clave introducida ("b", en hexadecimal 62) y D3, almacenándose el resultado en DX:


00000062 XOR FFFFFFD3 = FFFFFFB1

Después se comparará AL (E0) con DL (B1), por lo que el segundo carácter de la clave tiene que ser el resultado de:

E0 XOR D3 = 33  

El carácter correspondiente al código ASCII 33 en hexadecimal (51 en decimal) es "3".

2.- Tras la segunda operación XOR modifico DL poniendo E0 en lugar de B1:
Con lo que el programa realizará la operación XOR entre el tercer carácter de la clave introducida ("c", en hexadecimal 63) y D3, almacenándose el resultado en DX:


00000063 XOR FFFFFFD3 = FFFFFFB0

Después se comparará AL (EB) con DL (B0), por lo que el tercer carácter de la clave tiene que ser el resultado de:

EB XOR D3 = 38  

El carácter correspondiente al código ASCII 38 en hexadecimal (56 en decimal) es "8".

3.- Tras la tercera operación XOR modifico DL poniendo EB en lugar de B0:
Con lo que el programa realizará la operación XOR entre el cuarto carácter de la clave introducida ("1", en hexadecimal 31) y D3, almacenándose el resultado en DX:


00000031 XOR FFFFFFD3 = FFFFFFE2

Después se comparará AL (A0) con DL (E2), por lo que el cuarto carácter de la clave tiene que ser el resultado de:

A0 XOR D3 = 73  

El carácter correspondiente al código ASCII 73 en hexadecimal (115 en decimal) es "s".

4.- Tras la cuarta operación XOR modifico DL poniendo A0 en lugar de E2:
Con lo que el programa realizará la operación XOR entre el quinto carácter de la clave introducida ("2", en hexadecimal 32) y D3, almacenándose el resultado en DX:


00000032 XOR FFFFFFD3 = FFFFFFE1

Después se comparará AL (B8) con DL (E1), por lo que el quinto carácter de la clave tiene que ser el resultado de:

B8 XOR D3 = 6B  

El carácter correspondiente al código ASCII 6B en hexadecimal (107 en decimal) es "k".

5.- Finalmente, tras tras la quinta operación XOR modifico DL poniendo B8 en lugar de E1:
Con lo que el programa realizará la operación XOR entre el sexto carácter de la clave introducida ("3", en hexadecimal 33) y D3, almacenándose el resultado en DX:


00000033 XOR FFFFFFD3 = FFFFFFE0

Después se comparará AL (E1) con DL (E0), por lo que el sexto carácter de la clave tiene que ser el resultado de:

E1 XOR D3 = 32  

El carácter correspondiente al código ASCII 32 en hexadecimal (50 en decimal) es "2".

Por tanto, la clave correcta es "D38sk2". Ejecuto el programa e introduzco esta clave:
Y para superar este reto lo único que me falta por hacer es introducir la flag en la plataforma: