lunes, 6 de abril de 2009

Solución al reto 1 de Panda (I parte, fracaso absoluto)

-------------------------------------------------------------------- Solución al reto 1 de Panda (I parte, fracaso absoluto) Solución al reto 1 de Panda (II parte, FPqué!?) Solución al reto 1 de Panda (III parte, las dos comprobaciones) --------------------------------------------------------------------

El día 1 de este mes, abril, Panda organizó unos retos orientados al estudio de las aplicaciones o ingeniería inversa, vamos, al cracking.

En total eran 3 retos separados en el tiempo, el primero de cada uno se llevaba un jugoso premio, una PSP, un IPOD y un miniportátil.

Yo me enteré de los retos el mismo día que salió el primero gracias a Pedro Laguna. El primer reto aún puede encontrarse en su web. Mirror en google groups

Tras abrirlo vemos una ventana de consola pidiéndonos un password:image

Incorrecto, ya decía yo que no podía tener tanta suerte. Lo abrimos con OllyDbg

image

No se ve nada interesante a primera vista. Lo primero que se me ocurre es buscar las cadenas que usa el programa para localizar la cadena “bad!” que imprime cuando introducimos un password incorrecto y encontrar la cadena que se mostrará cuando el password sea correcto. Botón derecho sobre la zona central, “Search for > All referenced text strings”.

image

Encuentro:

  • “bad!”, la cadena mostrada cuando se introduce el password incorrectamente
  • “Password: ”, lo que imprime printf al comienzo
  • “%d-%f-%f-%c”, parece una típica cadena de formato usada en scanf, tendría sentido ya que espera un entero, guion, dos float separados por guión y un carácter. Algo así 1234-678.45-234,43-T
  • “%s!”, a saber puede ser el formato cadena usado en printf o scanf

Lo raro es que no encontramos ninguna cadena que nos muestre que hemos introducido el password correctamente.

Ahora se me ocurren varias posibilidades.

  • Inspeccionar las instrucciones que hagan uso de la cadena “bad!” , antes de llegar ahí tiene que haber una comparación que nos lleve a la zona buena o a esta mala. Lo malo es que puede ser mucho antes e ir de adelante hacia atrás es mas complicado.
  • Ver donde se usa la cadena de formato típica de scanf y tracear hacía delante viendo que se hace con los valores introducidos hasta llegar a una zona que decida si mostrarnos el mensaje bueno o malo.

Sigamos la segunda ya que el programa no parece muy largo. Botón derecho sobre la posible cadena de formato “Follow in Disassembler”

image

Pues si, va a ser una cadena usada por scanf. Sabemos que los 5 parámetros insertados en la pila antes de llamar a scanf serán:

  1. La dirección de la cadena de formato
  2. La dirección donde se guardará el primer entero, %d
  3. La dirección donde se guardará el primer float, %f1
  4. La dirección donde se guardará el segundo float, %f2
  5. La dirección donde se guardará el carácter %c

Ponemos un breakpoint en el CALL scanf, ejecutamos, tras parar en el breakpoint vemos el estado de la pila, encontramos todos los parámetros pasados al CALL:

image

Podemos poner un breakpoint en cada una de las 4 direcciones para que el programa detenga su ejecución cuando se lean o escriban esos parámetros. De este modo tendríamos una idea de las operaciones que se hace con los números que introducimos para verificar si es un password correcto o no.

Haremos eso, seleccionamos cada dirección del stack, clic derecho, “Follow in dump”.

image

Seleccionamos los 4 primeros bytes que es lo que ocupa un entero, botón derecho “Breakpoint > Hardware, on access > Dword”. Seguimos el mismo procedimiento para los otros 3 valores, teniendo en cuenta que un float también ocupa 4 bytes y un carácter ocupa uno.

Perfecto, ahora recordemos que el programa lo tenemos parado en el breakpoint que pusimos a la instrucción Call scanf. Así que pulsamos F8 para ejecutar scanf.

El programa estará a la espera de que introduzcamos el password por la consola, nosotros introduciremos el valor “1-2.0-3.0-A”.

El programa parará varias veces ya que accede a las zonas de memoria donde guarda los valores recogidos desde la consola y donde pusimos los hardware breakpoint. Pulsamos F9 hasta ver que nos encontramos en la siguiente instrucción del CALL scanf.

Podremos comprobar en el DUMP, que en las direcciones que vimos en la pila se sitúan los valores que hemos introducido por consola.

image

Vemos la ‘A’, 40400000, 40000000 y 00000001. Recordad que se usa Little-Endian. Los dos float, se almacenan en coma flotante de ahí que no se distinga a primera vista el 2.0 y el 3.0.

Seguimos pulsando F9 y vemos que el programa se va deteniendo según usa los valores recogidos desde la consola. Vemos que se detiene a veces en instrucciones muy raras.

image

Buscando con el perrito del ciego de lycos, encontramos que son instrucciones del coprocesador matemático, la FPU, “operaciones para trabajar con números en coma flotante”. Mierda !

Seguimos pulsando F9 y deteniéndonos por los malditos hardware breakpoints. Hasta que el programa finaliza sin habernos dado cuenta de que ha pasado.

Doble mierda, plan fallido ! Mi idea era que durante el progreso hubiese encontrado cómo fácilmente se mueven los valores a los registros habituales y se usan instrucciones comunes para compararlos con algún valor esperado. Pero lo mas cercano que he encontrado han sido un montón de instrucciones raras de la FPU.

Primera aproximación fallida. Tendremos que ir poco a poco viendo lo que hacen instrucciones posteriores al scanf, hasta comprender porque nuestro password no es correcto.

Continuará...

No hay comentarios:

Publicar un comentario en la entrada