Archive

Posts Tagged ‘Ingeniería Inversa’

Sólo quiero bajar algo por ftp! (con FlashFXP xD)

February 5th, 2009 No comments

Hola a todos, el otro día buscando un FlashFXP para bajar algo , encontré la última versión….la bajé….al ejecutarla, me pidió número de serie… utilicé el keygen que lo acompañaba.

Cuando puse el serial el programa siguió su camino, me apareció una ventanita que decía c:\windows\system32 ….

Me pareció muy raro y sospeché de un virus… obviamente seguí utilizando el programa, y NOD me avisó que “algo” se quería conectar… algo con nombre como qsyrjrwes.exe en la carpeta Datos de Programa de mi usuario en Windows XP.

Obviamente, escribí en arroba sobre ese EXE, para ver de que se trataba, era un simple downloader, definido como downloader.Win32… Ya postearé el artículo explicando de qué se trata… ;)

Bueno obviamente, el EXE de flashfxp estaba “envuelto” por un dropper, éste sacaba el downloader, y después hacía ejecutar al flashfxp normalmente…

Empezando a mirar el EXE, encontramos algunas strings que se cargan, y mirándolas por arriba, pienso que son strings encriptadas que desencripta en tiempo de ejecución…

Strings Encriptadas

Seguramente para evitar que los AV’s detecten el proceso…

Cuando debuggeemos por las strings “.dll” y “.exe”, más precisamente en las direcciones 408D03 y 408D15 veremos estas cosas en la pila:

0012FFAC   01141C30  0  ASCII “C:\WINDOWS\system32\niksr.dll”

y luego,

 

0012FFA8   01141CA4  ¤  ASCII “C:\DOCUME~1\SPARKR~1\CONFIG~1\Temp\setup.exe”

Luego de eso, en estas direcciones podremos ver que el ejecutable creado en la carpeta temporal de nuestro windows, posee un icono de flashfxp… es raro.. ;)

 

00408D39  |. A1 C8A94000    MOV EAX,DWORD PTR DS:[40A9C8]

00408D3E  |. E8 BDFDFFFF    CALL setup-pr.00408B00

En estas dos líneas se ejecuta el EXE liberado en la carpeta temporal de Windows. Igualmente no es el EXE final.

Veremos que entrando al CALL mencionado dos líneas más arriba, y mirando un poco más, se crea un objeto Mutex.

Mutex

Veamos para que sirve un mutex (una definición de la red…):

“Un mutex funciona exactamente del mismo modo que las secciones críticas. La única diferencia en las implementaciones Win32 es que la sección crítica esta limitada para ser usada con solamente un proceso. Si tienes un programa que usa varios hilos, entonces la sección crítica es liviana y adecuada para tus necesidades. Sin embargo, cuando escribes una DLL, es muy posible que diferentes procesos usen la DLL en el mismo momento. En este caso, debes usar mutexes, en lugar de secciones críticas.”

Veremos en la imagen, que genera un código único, que se utiliza como nombre del mutex, para crearlo, con la API CreateMutexA.

Seguido de esto, parece que nuestro troyano necesita descomprimir una dll denominada bcdsa.dll, veamos:

EAX apunta al string C:\WINDOWS\system32\bcdsa.dll.

El ejecutable busca el archivo bcdsa.dll y si no existe, lo crea.

fxp1

Luego de crear la DLL, descomprime el segundo EXE como hemos visto que el path estaba en memoria y crea el Thread finalmente con la DLL deseada. Capturemos la DLL, para futuro análisis. ;)

Si vamos a buscar la DLL y vemos propiedades encontraremos una descripción extraña:

fxp2bcdsa

fxp3bcdsa

O es una librería que necesitará el flashfxp final o es algo más…

fxp4

Luego de que el Thread es creado, nos aparecerá la ventanita con el mensaje: “c:\windows\system32″, esto es lo que me hizo sospechar de la actividad de este ejecutable. Es una falla de programación importante, ya que se da a conocer muy sencillamente, parece que el programador tenía pocos recursos para poder darse cuenta cuando la DLL estaba cargada en memoria… :P

Ahora veremos el segundo ejecutable.

Una vez que nuestro amigo está descomprimido veremos que al cargarlo está hecho en C, por eso mismo carga nuestra DLL, que se trata nada más ni nada menos de las MFC, librerías runtime necesarias. :)

Este EXE, descomprimirá el FlashFXP final, pero además agregará la descompresión de un downloader… ;) para fines non santos…

fxp5

El ejecutable de FlashFXP será descomprimido en c:\windows\ bajo el nombre de setup.exe

fxp6

En esta imagen, podemos ver como ejecuta a FlashFXP original y a su vez, descomprime y crea el downloader, cuyo nombre es aleatorio.

Finalmente, tratará de ejecutar el Downloader, como veremos acá:

fxp7

Por último el proceso termina, llamando a ExitProcess. :)

Entonces si queremos nuestro EXE final de FlashFXP, directamente lo buscamos en la carpeta Windows de nuestro sistema.

Nos damos cuenta que el EXE es el original, porque al hacer botón derecho y propiedades, veremos los datos originales de la aplicación. Lo cuál ante un usuario atento, se dará cuenta que los otros ejecutables no son los originales. :)

Es importantísimo poder tener firmado los ejecutables de nuestras aplicaciones, además de poder tener la información guardada como propiedades del ejecutable, de manera que un usuario puede verificar la autenticidad de varias maneras.

Siempre hay que estar atento a actividades extrañas, como por ejemplo la ventana que sale a modo de información avisando que la DLL ya fue creada, para poder continuar la descompresión…. como lo vimos anteriormente.

Eso es todo, espero que les haya servido y gustado. :)

Nos vemos la próxima.

convert this post to pdf.

Solucionando un CrackME de Hispasec!

January 20th, 2009 1 comment

  En el presente escrito se abordará la resolución del CrackME de hispasec, llamado a partir de ahora crackme o reto, detallando las siguientes partes.

  •  ¿Qué se pretende?
  •  Encontrando la zona de interés.
  •  Análisis del algoritmo.
  •  Generación de un fichero válido.
  •  Fallos de diseño.
  •  Despedida y cierre.

  El crackme y el fichero de licencia lo podeis encontrar en el siguiente enlace.

1.- ¿Qué se pretende?

  El objetivo de este reto, es generar un fichero de licencia válido y explicar los fallos de diseño encontrados en los hilos. Quiero comentar que en este documento encontraremos lo que a mi juicio son fallos de diseño, no tienen porque coincidir con los criterios de los autores del reto. Para la resolución de este reto se ha utilizado un depurador y un editor hexadecimal, en mi caso he optado por Ollydbg y por Hex Workshop.    

2.- Encontrando la zona de interés.

  Para llegar a la zona que nos interesa analizar, y sabiendo de antemano que necesitamos un fichero de licencia, tenemos varia maneras de abordar nuestro cometido; explicaré un par de ellas.

  •  Localizando la función de chequeo mediante referencias a cadenas.

Nada más cargar nuestro reto en el depurador, parados en el oep, buscamos referencias a cadenas con search for > All referenced text strings. Obtenemos esto.

img1nk

Podemos ver las cadenas “crackem.lic”, “Good job!” y “Keep trying”, es evidente que nuestro objetivo es “Good job”. Seguimos la cadena y caemos en este punto. img2nk  

En función de un par de comparaciones carga una de las cadenas. Seguimos el código hacia arriba, para ver donde se inicia esta función.

img3nk

Aquí encontramos el inicio de la función, en la dirección 004010B0, vamos a fijarnos un momento que llama a la API CreateFileA, pero el atributo Mode es OPEN_EXISTING. Esto es importante para el siguiente punto.

  •  Localizando la función de chequeo utilizando la API de Windows.

 

Ahora vamos a utilizar la API de Windows para llegar al mismo punto. Nada más cargar nuestro reto en el depurador, parados en el oep, buscamos referencias a APIs cargadas con search for > Name (label) in current module. Obtenemos esto.

img4nk

 

Vamos a poner un BP en cada API específica de ficheros.

 

 

KERNEL32.CreateFileA

KERNEL32.GetFileSize

KERNEL32.GetFileType

KERNEL32.ReadFile

KERNEL32.WriteFile

 

Ejecutamos varias veces y vemos unas cuantas paradas antes de llegar a este BP en la dirección 004010CB, tal como vemos en esta imagen.

img5nk

Seguimos el código hacia arriba, para ver donde se inicia esta función. Encontramos el inicio en la dirección 004010B0.

 

3.- Análisis del algoritmo.

 

Como ya hemos localizado la función de chequeo, ahora vamos a centrarnos en analizarla.

La función comprueba que existe el fichero “crackme.lic” , mira el tamaño del fichero, crea un buffer para guardar los datos, vuelca el contenido del fichero en el buffer creado, lanza los hilos que comprueban si los datos que hemos volcado son válidos y analiza el resultado de los hilos para decidir que cadena muestra. Esto corresponde al siguiente esquema.

img6nk

Bueno, lo realmente interesante esta en los hilos de ejecución, así que vamos a ver que es lo que hacen los mismos. Vamos a fijarnos en el argumento Thread Function, vemos que tiene el parámetro 00401000, este es el inicio de la función que ejecuta el hilo.

 

img7nk

Los bytes del fichero llave deben ser menores de 0Ah, es decir menores de 10d, si el hilo encuentra un byte igual a FFh, termina el análisis. Si nos fijamos, la función tiene dos salidas, una en la que realiza un “XOR EAX,EAX” o lo que es lo mismo, poner EAX a 0; y otra que realiza un “MOV EAX,1″ o lo que es lo mismo, poner EAX a 1.

¿Cómo conseguimos poner EAX a 1?, si solucionamos esta pregunta, tenemos solucionado el problema; para conseguir la ejecución de ese salto, debemos lograr que el resultado de AL tras la ejecución del código sea igual a 09h. Veamos más claramente la ejecución.

img8nk

El proceso le el primer byte del fichero, carga otro byte que utiliza para los cálculos, vamos a llamarlo byte auxiliar o aux; este byte, al principio va a estar a 0. Tras esto realiza una operación con este byte, aux = aux + 4*aux, esto lo guarda en edx. Carga en bl el dato leído del fichero y este dato junto con aux, lo utiliza para acceder a una tabla de bytes; el calculo es el siguiente desplazamiento = dato + aux * 2.

En nuestro caso necesitamos un desplazamiento de 48h, si no conseguimos cargar el 09h, el byte apuntado se convierte en el nuevo aux. Y esto se repite hasta encontrar FFh.

4.- Generación de un fichero válido.

 

Bueno, conociendo el algoritmo, es fácil generar un fichero válido, solo necesitamos conocer la tabla de bytes que hemos comentado anteriormente. Es la siguiente (las cabeceras de la tabla están representadas en decimal.).

1 .- Bytes hexadecimales.

 

0

1

2

3

4

5

6

7

8

9

0

05

01

03

02

01

02

04

03

05

04

10

00

00

00

00

00

02

00

00

00

00

20

02

03

03

00

00

01

01

04

04

05

30

02

03

03

01

06

04

04

05

05

00

40

00

00

05

01

02

03

04

08

08

05

50

05

05

05

04

04

05

05

00

00

00

60

06

06

06

06

06

07

08

08

06

06

70

07

07

09

08

07

07

07

08

08

08

80

08

07

07

08

08

08

08

07

07

  07

 

Necesitamos conseguir un desplazamiento de 72d bytes. Para ello vamos a realizar las siguientes operaciones.

Aux = 0 (la primera pasada del algoritmo).

Data = 06 (Primer byte del fichero).

0 + 0*4 = 0.

6 + 0*2 = 6.

Cargamos el byte que hay con desplazamiento 6; el 04.

No es 09, por tanto lo usamos como nuevo aux.

 

Aux = 04.

Data = 07 (Segundo byte del fichero).

4 + 4*4 = 20.

7 + 20*2 = 47.

Cargamos el byte que hay con desplazamiento 46; el 08.

No es 09, por lo tanto lo usamos como nuevo aux.

 

Aux = 08.

Data = 01 (Tercer byte del fichero).

8 + 8*4 = 40.

1 + 40*2 = 81

Cargamos el byte que hay con desplazamiento 81; el 07;

No es 09, por lo tanto lo usamos como nuevo aux.

 

Aux = 07.

Data = 02 (Cuarto byte del fichero).

7 + 7*4 = 35.

02 + 35*2 = 72.

Cargamos el byte que hay con desplazamiento 72; el 09.

Es 09, por lo tanto terminamos en el return que nos interesa.

 

Si nos fijamos, el segundo hilo, utiliza exactamente la segunda función, además, la tabla de bytes no es modificada, por tanto, sólo tenemos que duplicar la cadena de bytes obtenida anteriormente y replicarla. Al final, añadimos el byte de fin que utiliza el programa, el FFh.

La cadena de bytes que necesitamos escribir para generar un fichero válido es la siguiente: “0607010206070102FF”. Esto lo podemos hacer con nuestro editor hexadecimal preferido. Una vez realizado esto, tenemos solucionado este reto.

 

5.- Fallos de diseño.

 

A continuación, comento lo que a mi juicio son fallos de diseño en el algoritmo.

  •  Existe un fragmento de código, que no es necesario para la resolución del reto,

00401070   .  68 CE070000   push 7CE

00401075   .  FFD6                call esi                                 ;  kernel32.Sleep

00401077   .  EB 04               jmp short crackme.0040107D

 

0040107D   > \E8 67010000  call crackme.004011E9

00401082   .  99                     cdq

00401083   .  B9 32000000   mov ecx,32

00401088   .  F7F9                idiv ecx

0040108A   .  52                    push edx

0040108B   .  FFD6               call esi                                 ;  kernel32.Sleep

 

Si se ha utilizado a modo de código basura, debería de repartirse más por la función o diseñarse de alguna otra manera ya que es muy obvio comprobar que no es necesario analizarlo para la resolución del reto.

 

  •  Los dos hilos que se lanzan para comprobar el fichero llave, utilizan la misma función y esta hace exactamente lo miso. Podríamos haber solucionado esto utilizando por ejemplo dos puntos de entrada para la función o una modificación de la misma. Otra opción hubiese sido utilizar otra función que comprobase otras propiedades del los bytes del fichero.

 

  •  Al utilizar el segundo hilo para chequear los bytes del fichero, si no hemos modificado la función ni hemos utilizado otra función distinta, al menos deberíamos haber cambiado la tabla de bytes para forzar un nuevo cálculo de la segunda parte de los bytes del fichero.

 

6.- Despedida y cierre.

 

Un Saludo a los miembros de Disidents.org, al canal #crackers, a thEpOpE, a NoMuRyTo y a toda la gente que me dejo pero sabe que puede darse por saludada. Espero que no seais muy duros en las críticas de mi primera publicación.

convert this post to pdf.