
Analyse CVE-2024-42327
Ziel: 10.129.231.176
Informationen: Ich weiß, dass mein Ziel ein Zabbix-Server ist. Ich habe ein Standardbenutzerkonto erhalten, um mich in Zabbix anzumelden: Benutzer matthew, Passwort 96qzn0h2e1k3. Dieses Konto hat einen Standardbenutzer ohne zusätzliche Gruppen oder Berechtigungen.
Wie üblich beginnen wir mit der Aufzählung, wir führen einen Portscan mit nmap durch.

Die Ausgabe von nmap zeigt uns, dass der Standard-SSH-Port und Apache2 ebenfalls auf dem Standardport laufen. Außerdem laufen auf den Ports 10051 und 10050 Dienste von Zabbix.
Wir greifen auf Zabbix zu, indem wir die IP in die Browser-URL eingeben, und zwar auf dem Standard-HTTP-Port, Port 80.

Dies ist der Zabbix-Anmeldebildschirm. Ich melde mich mit dem erhaltenen Benutzer an.


In der Fußzeile habe ich die Zabbix-Version gefunden:

Mit Google habe ich recherchiert, ob es bereits eine CVE für diese Zabbix-Version gibt.

Nach langer Recherche sah ich, dass diese Version anfällig für CVE-2024-42327 ist, bei dem es um eine SQL-Injection zum Abrufen von Datenbankdaten und zur Rechteausweitung geht, sowie für CVE-2024-36467, das es erlaubt, die Benutzerrolle auf Superuser zu ändern, indem fehlende Zugriffskontrollen ausgenutzt werden.
https://nvd.nist.gov/vuln/detail/CVE-2024-36467
https://nvd.nist.gov/vuln/detail/CVE-2024-42327
In der Zabbix-Dokumentation wird erklärt, wie man HTTP-Anfragen stellt, um die API aufzurufen.

https://www.zabbix.com/documentation/current/en/manual/api
Ich habe die Anfrage mit dem Aufruf von apiinfo.version gesendet, wie in der Dokumentation beschrieben.

Was uns Folgendes zurückgab:
{"jsonrpc":"2.0","result":"7.0.0","id":1}
Für den nächsten Test habe ich einige Parameter in dieser Anfrage geändert und sie erneut gesendet.

In method habe ich appinfo.version in user.login geändert und die Parameter username und password hinzugefügt. Dies habe ich ebenfalls in der Zabbix-Dokumentation gesehen.

Es wurde ein Token zurückgegeben:
{"jsonrpc":"2.0","result":"9566174b00c9c3ca552abc1a52d670ba","id":1}
Nach weiterer Recherche entschied ich mich, das Zabbix-Repository auf GitHub zu besuchen.
https://github.com/zabbix/zabbix
Ich suchte nach CUser und fand eine Datei CUser.php.

Wir fanden die Funktion user.update:
public function update(array $users) {
$this->validateUpdate($users, $db_users);
self::updateForce($users, $db_users);
return ['userids' => array_column($users, 'userid')];
}
Ich fand keine Autorisierungsprüfung, also beschloss ich, meine Rolle auf Superuser zu ändern. Ich kehrte zur Anfrage zurück und passte das Payload an.

Es wurde ein Fehler mit der Meldung "invalid params" zurückgegeben.
Nach einer erneuten langen Analyse des Codes fanden wir diese Funktion:
/**
* Additional check to exclude an opportunity to deactivate himself.
*
* @param array $users
* @param array $users[]['usrgrps'] (optional)
*
From this snippet, we understand that we cannot change our roles because our role is checked
from extracting our data from the API token, and verifying against the database if we are that user.
But following the code we see that usrgrps has no validation at all, and therefore can be abused
to add ourselves into multiple groups at once. As long as the group is not disabled and the group
allows GUI access we can abuse this to change our current role with the following command:
User ID 3 is matthew , User group 7 is the Zabbix administrators group and user group 13 is the
Internal group which both hold unrestrictive privileges. The response indicates that the change
was successful:
* @throws APIException
*/
private function checkHimself(array $users) {
foreach ($users as $user) {
if (bccomp($user['userid'], self::$userData['userid']) == 0) {
if (array_key_exists('roleid', $user) && $user['roleid'] !=
self::$userData['roleid']) {
self::exception(ZBX_API_ERROR_PARAMETERS, _('User cannot change
own role.'));
}
if (array_key_exists('usrgrps', $user)) {
$db_usrgrps = DB::select('usrgrp', [
'output' => ['gui_access', 'users_status'],
'usrgrpids' => zbx_objectValues($user['usrgrps'], 'usrgrpid')
]);
foreach ($db_usrgrps as $db_usrgrp) {
if ($db_usrgrp['gui_access'] == GROUP_GUI_ACCESS_DISABLED
|| $db_usrgrp['users_status'] ==
GROUP_STATUS_DISABLED) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('User cannot add himself to a disabled group or a
group with disabled GUI access.')
);
}
}
}
break;
}
}
}
Laut diesem Code-Snippet können wir unsere Rollen nicht ändern, da unsere Rolle überprüft wird, indem unsere Daten aus dem API-Token extrahiert und in der Datenbank verifiziert wird, ob wir dieser Benutzer sind. Aber wenn wir den Code weiterverfolgen, sehen wir, dass usrgrps überhaupt keine Validierung hat, und daher missbraucht werden kann, um uns selbst zu mehreren Gruppen gleichzeitig hinzuzufügen. Es gibt keine Prüfung, die verhindert, dass ein Benutzer sich selbst zu Gruppen hinzufügt, zu denen er keinen Zugriff haben sollte.
Versuchen wir, die fehlende Validierung für eine Rechteausweitung zu nutzen. Ich habe das Payload bearbeitet und die Anfrage erneut gesendet.

userid 3 bezieht sich auf die ID des Benutzers matthew. usrgrps enthält eine Liste von Gruppen-IDs: 13, eine interne Gruppe, und 7, die Zabbix-Administratorengruppe. Die Antwort des Servers bestätigt den Erfolg des Vorgangs:
{"jsonrpc":"2.0","result":{"userids":["3"]},"id":1}
Jetzt können wir die Benutzergruppen unseres aktuellen Benutzers extrahieren. Wir ändern die Anfrage und senden sie erneut.

Bei der Überprüfung der Antwort sehen wir, dass der Benutzer mit ID 3 in den Gruppen "Zabbix administrators" und "Internal" ist.
{"jsonrpc":"2.0","result":[{"userid":"1","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]},{"userid":"2","usrgrps":
[{"usrgrpid":"8","name":"Guests"}]},{"userid":"3","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]}],"id":1}