Redirigiendo el flujo de un programa para obtener una shell. (Buffer overflow)

ALERTA: SPOILER DE ROOT-ME

Hoy vamos a ver como redirigir el flujo de un programa que tiene una función de sistema, en este caso “system()” y lo aprovecharemos para leer el contenido de un fichero al que no tenemos acceso.
Para este PoC, el ASLR está desactivado.

El código del programa es el siguiente:

#include <unistd.h>

#include <sys/types.h>

#include <stdlib.h>

#include <stdio.h>

 

int main()

{

 

  int var;

  int check = 0x04030201;

  char buf[40];

 

  fgets(buf,45,stdin);

 

  printf(“\n[buf]: %s\n“, buf);

  printf(“[check] %p\n“, check);

 

  if ((check != 0x04030201) && (check != 0xdeadbeef))

    printf (“\nYou are on the right way!\n“);

 

  if (check == 0xdeadbeef)

   {

     printf(“Yeah dude! You win!\nOpening your shell…\n“);

     setreuid(geteuid(), geteuid());

     system(“/bin/bash”);

     printf(“Shell closed! Bye.\n“);

   }

   return 0;

}

Podemos observar que el Buffer tiene un tamaño de 40, para empezar vamos a pasarnos a ver que pasa.

Perfecto, vamos por el buen camino. Por cierto, utilizamos el print de python para no tener que escribir 50 “a” de forma manual.

Muy bien, ahora nos vamos al código y vemos que el primer bypass que hay que hacer para llegar a la función system es:

 if (check == 0xdeadbeef)

   {

     printf(“Yeah dude! You win!\nOpening your shell…\n“);

     setreuid(geteuid(), geteuid());

     system(“/bin/bash”);

     printf(“Shell closed! Bye.\n“);

   }

Tenemos que conseguir cambiar el valor de la variable check por 0xdeadbeef. Sabemos que las variables se guardan en memoria de abajo para arriba. Tenemos que conseguir pasando el buffer para poder sobrescribir “check” puesto que es la siguiente variable guardada. Para que la pila nos lo lea, vamos a inyectar un shellcode en formato little-endian y se coma “0xdeadbeef” para poder obtener la shell.

Vamos a probar a hacerlo, el buffer son 40 y seguido inyectaremos el shellcode:

Perfecto! hemos conseguido sobrescribir el valor de check para bypassear la condicional y así obtener la shell que queremos.

El primer paso está hecho, ahora, tenemos un archivo en el directorio que se llama “.passwd” el cual contiene la flag del CTF, para poder leerlo, tendriamos que leerlo desde el flujo del programa, puesto que el usuario desde el cual se ejecuta del programa puede leer el archivo.

Para ello, vamos a inyectar una fila muy larga de “a”, seguida del comando que queremos usar (“cat .passwd”).
Vamos a ir probando, de momento vamos a pasarnos, vamos a intentarlo con 6000:

Perfecto, hemos conseguido sobrescribir el comando, pero nos hemos pasado por mucho, ahora lo que tenemos que hacer es ir afinando la cantidad de “a” que inyectamos hasta que sean las justas para poner el comando…

Voy a probar con menos, 4000…

Al palo… unas pocas menos…. y…. (He tapado la flag para que infringir la norma de la comunidad)

Como podemos observar podemos ejecutar cualquier comando…

El problema de todo esto viene en la funcion fgets, la cual nos deja introducir cadenas de texto mayores que el buffer que la guarda puesto que no compara la longitud de la cadena.

El siguiente traeré uno un poco más complicado!

Un saludo.

Leave a Reply

Your email address will not be published. Required fields are marked *