sábado, 22 de agosto de 2009

How to PASS wargame CP 2009: BINARIES

Por fin!, última entrada de las soluciones a los retos de seguridad de la CP 2009 Valencia.

// RETO 1 //

Como se puede ver en la imagen, se da un enlace a un archivo .class, el cual lo podemos entender como un archivo compilado de java, así que este programa se podrá ejecutar con la maquina virtual de java, pero no tendremos acceso a su código fuente, o sí?

Lo primero que intentamos es usar strings para darnos una idea del software:

nonroot@plasma:/tmp$ strings OhHai.class
Me,
, I KILL YOU!!!
console
()Ljava/io/Console;
So ... WTF are you? ->
java/io/Console
readLine
9(Ljava/lang/String;ÄLjava/lang/Object;)Ljava/lang/String;
equals
(Ljava/lang/Object;)Z
Hoooray!! Your pass is "
args
ÄLjava/lang/String;
hidden
whoami
clue
line
SourceFile
OhHai.java
éN-+
Esto me da varias pistas, pero nada tangible, ejecutemos el software:

Uhmm, al parecer el programa espera algo que aún no sabemos. En este punto pensamos que estamos en los ejercicios de binarios, cracking o ingeniería inversa, como les quieras llamar. Entonces en la mayoría de los casos tendremos que decompilar, desensamblar y debugguear todo lo que se aparezca.

El procedimiento entonces es usar un desensamblador de archivos .class para tratar de conseguir los .java (código fuente). Después de reblujar todo Internet, concluimos que el mejor es este programa multiplataforma.

Como pueden ver, al abrir el archivo .class, obtenemos el archivo en código fuente tan limpio como si lo acabaran de programar ;)

Que hacemos entonces?, tenemos dos opciones:

1. Le hacemos un seguimiento al programa e intentamos entender lo que hace para así deducir que debemos ingresar en los parámetros de ejecución.

2. Buscamos las líneas donde se compare lo que ingresamos y lo que el programa calcula e imprimimos el resultado, para esto hay que volver a compilar el .java modificado ;).

Las últimas líneas del código me muestran un condicional de algo, que hacemos entonces?, pues quitamos el condicional y ensamblamos nuevamente.


sin el condicional el programa queda así:

De esta forma el programa imprimirá SI o SI, la respuesta ;)
Aquí vemos el resultado:


Conclusiones:

1. Cualquier cosa que se pueda compilar, se puede decompilar, cualquier ensamblador, tiene su desensamblador, ten esto presente.

2. Si eres programador de java y estas pensando que entonces tus .class son vulnerables, la verdad es que TAMBIÉN son vulnerables, la recomendación es que cuando programes validaciones (de lo que sea) no las metas dentro de los mismos ficheros compilados, porque alguien sabrá como sacarlas de allí. Existen suficientes recursos en Internet donde te enseñan un poco de seguridad en la programación en CUALQUIER LENGUAJE.

3. Este es un reto básico de ingeniería inversa, como siempre, si tenemos la herramienta adecuada y conocemos la ruta, no hay nada que hacer.

//FIN RETO 1//

Esto se puso bueno ...

// RETO 2 //
Al ingresar al servidor SSH (un linux), encontrábamos un fichero binario.
Este fichero binario al ejecutarlo me pedía un nombre y luego me decía:

root@plasma:/tmp# date
Fri Jul 31 22:45:05 COT 2009
root@plasma:/tmp# ./reto2
Por favor, dime tu nombre: nando
Lo siento nando No te dare el token hasta el 10-08-2009
root@plasma:/tmp#

Esto nos dice varias cosas:

1. Es un programa que tiene que ver con el tiempo (funciones de tiempo), también la imagen de la presentación del reto apoya esto.

2. El password seria mostrado si pasaba esa fecha.

Que podemos hacer entonces?, lo que primero se nos ocurre es intentar cambiar la fecha del sistema, pero obtenemos un mensaje:

Técnica no valida!!

Y si le cambiamos el nombre al programa:

Técnica no valida!!

Y si lo copiamos por ssh a otra maquina e intentamos ejecutarlo?

Técnica no valida!!

Y si intentamos abrirlo con gdb, el debugguer de linux?

Técnica no valida!!

Y si intentamos debuguearlo con la técnica ptrace?

Técnica no valida!!

Y si intentamos causarle un overflow en la entrada del nombre?
Y si le pasamos el comando string?
Y si nos retiramos del juego? :P


Después de probar unas cuantas técnicas, nos damos cuenta que el binario esta muy protegido y que lo mejor es NO moverlo del sistema, entonces como hacer para explotarlo?

Hacemos memoria y recordamos una vieja, pero efectiva técnica donde podemos hacer un mapeo en memoria de ciertas funciones y luego obligamos al programa objetivo a que use estas funciones en reemplazo de las originales de librerias .h.

Esta técnica se conoce como la de LD_PRELOAD, puedes ver un ejemplo aqui. Los ejemplos mas comunes en Internet son ataques a la función time(), que para nuestra suerte es la que esta usando este programa (o al menos eso creemos).

Entonces hay dos formas de atacar el programa:

1. la dificil, es hacer todo el procedimiento que equivale a programar una función time() ficticia, luego crear una libreria dinamica .so, luego exportar la variable LD_PRELOAD y luego ejecutar el programa.

2. Usar una herramienta que haga eso por nosotros :)

Seleccionamos la opción 2 (por pereza) y descargamos esta libreria la cual promete hacer todo lo que necesitamos. El modo de uso se encuentra en el sitio web, entonces solo tenemos que hacer un "make" y listo, a usarla.

¿Bonito no?, lo que hicimos fue hacer un FAKE de la rutina del tiempo para hacerle creer que estabamos 15 días mas adelante, pueden ver tambien que la fecha real del sistema no se altera, solamente se suplanta en tiempo de ejecución del programa objetivo ;)

Un aplauzo para libfaketime! (PLAP, PLAP, PLAP!)

Conclusiones:

1. Este nivel es un clásico del hacking ;). gracias.

2. Interesante conocer todas las protecciones que usaron para los binarios, para evitar desensamblados, debugging y otro monton de cosas que a uno se le pudieran ocurrir.

3. Al estar tan limitados en los aspectos de reversing con el ejecutable objetivo, no quedaba otro remedio que buscar la técnica que ellos estaban esperando.

4. Un muy buen reto, pero si quieres entender el ataque de LD_PRELOAD es mejor que te crees las librerías a mano y ensayes no solo con la time(), si no con la chown(), chmod() y cualquier otra que se te atraviese, explota, explota, explota!!!!.

// FIN RETO 2 //

I need medic, Requesting backup, I'm going for the bug ...

// RETO 3 //

Cuando entramos al servidor ssh (linux) para este nivel, encontramos un escenario similar al anterior, un binario, estamos dentro de un chroot de ssh, el binario tiene mil protecciones y bueno ...

¿Que hacemos entonces?

Después de intentar algunas cosas, buscar posibles ataques por format string, vemos que no es por ahí el asunto. Entonces debe ser un ataque clasico de overflow o no?

Para poder llevar a cabo un ataque de *overflow clásico, el sistema no debe tener randomizado el stack (sysctl kernel.randomize_va_space=0) y se deben haber deshabilitado las protecciones en el momento de compilación de la aplicación (gcc -fno-stack-protector). Vamos a suponer así es.

Podemos ver en los permisos que el binario tiene el bit suid:
nonroot@plasma:/tmp$ ls -la echo
-rwsr-xr-x 1 root root 9472 2000-08-22 09:44 echo
Entonces buscaremos atacar el software con un stack overflow, intentemos el viejo truco del perl.

Podemos ver que el programa se revienta después de 504 caracteres, eso nos da una pista para poderlo explotar. Se supone que unos cuantos bytes mas adelante podemos sobreescribir el EIP y apuntarlo a donde queramos.

Pongamos un shellcode en memoria e intentemos pegarle:


Con ese programa put.c (si el de aleph), podemos ubicar un shellcode en memoria, a esto se le conoce como huevo.

Con este otro programa find.c, podemos encontrar la dirección de memoria donde se encuentra el huevo, aqui vemos que nos retorna 0xbffff866.

Intentemos pegarle al shellcode:


!! EFECTIVO !!


Lo que hacemos es meterle 504 bytes al buffer y los 4 restantes que sobreescriben EIP son los bytes de la dirección en memoria de nuestro huevo. Para el ataque hay que tener en cuenta que se deben poner los bytes en orden inverso para que nuestro procesador los entienda correctamente.

Despues de explotar este binario lo que podiamos hacer era leer un fichero que tenia como propietario otro usuario (sin permisos de lectura para el jugador del reto = campus02) y listo, con eso pasabamos el nivel.

Conclusiones:

1. Un ejercicio de stackoverflow sencillo.

2. Creo que son las mismas protecciones usadas en el binario anterior, buena por esa!.

3. Los BOFs nunca pasaran de moda, siguen allí, ¿sigues programandolos? (alguien seguirá explotandolos)

//FIN RETO 3 //
Queda uno ...

// RETO 4 //

4 comentarios:

ZethaByte dijo...

Q interesante wargame !

por lo visto lograste completar todos los retos !!

nonroot (c) 2008/2009 dijo...

Hola,
no, no todos los retos los logré pasar, algunos no sabia como hacerlos y otros nunca supe, jaja, si leiste los posts anteriores muchos se tratan de fuerza bruta y como ya lo comente, son desesperantes ;)
Saludos.

Yago Jesus dijo...

Bravo por la redacción tan novelada de los posts y las acertadas deducciones. Si quieres, cuando termines el 4 te hacemos una reseña en el blog

nonroot (c) 2008/2009 dijo...

Yago, gracias por el comentario.
Creo que el punto 4 no podre publicarlo porque se trata de una aplicación en C#. Use el desensamblador con el plugin necesario, pero hasta ahí me da el conocimiento de C#, jaja, intenté reensamblarlo con mono, pero no me funcionó. Que tal si explicas como se resuelve en detalle?, con eso queda completo el solucionario.

Saludos.

Entradas populares