
analyse cve-2024-42327
cible : 10.129.231.176
Informations : Je sais que ma cible est un serveur Zabbix. J'ai reçu un compte utilisateur par défaut pour me connecter au Zabbix : user matthew passwd 96qzn0h2e1k3. Ce compte possède un utilisateur standard, sans groupes ni privilèges supplémentaires.
Comme d'habitude, nous commençons par l'énumération, nous allons faire un scan de ports avec nmap.

La sortie de nmap nous montre que le port SSH standard et Apache2 sont également sur le port standard. Nous avons aussi les ports 10051 et 10050 qui exécutent un service Zabbix.
Accédons à Zabbix en mettant l'IP dans l'URL du navigateur et sur le port HTTP standard, port 80.

Voici l'écran de connexion de Zabbix, je vais me connecter avec l'utilisateur que j'ai reçu.


En bas de page, j'ai trouvé la version de Zabbix :

En utilisant Google (le père des idiots), j'ai cherché s'il existait déjà un CVE pour cette version de Zabbix.

Après un bon moment de recherche, j'ai vu que cette version est vulnérable au CVE-2024-42327 qui parle d'une exploitation d'injection SQL pour obtenir des données de la base de données et élever les privilèges, et au CVE-2024-36467 qui permet de modifier le rôle d'un utilisateur en superutilisateur en abusant de contrôles d'accès absents.
https://nvd.nist.gov/vuln/detail/CVE-2024-36467
https://nvd.nist.gov/vuln/detail/CVE-2024-42327
La documentation de Zabbix explique comment faire des requêtes HTTP pour appeler l'API.

https://www.zabbix.com/documentation/current/en/manual/api
J'ai envoyé la requête en appelant apiinfo.version comme enseigné dans la documentation.

Ce qui nous a renvoyé ceci :
{"jsonrpc":"2.0","result":"7.0.0","id":1}
Pour le test suivant, j'ai modifié quelques paramètres dans cette requête pour la renvoyer.

Dans method, j'ai changé de apiinfo.version à user.login et j'ai ajouté les paramètres username et password. J'ai vu cela aussi dans la documentation de Zabbix.

Cela nous a renvoyé un token :
{"jsonrpc":"2.0","result":"9566174b00c9c3ca552abc1a52d670ba","id":1}
Après encore un temps de recherche, j'ai décidé d'aller dans le dépôt Zabbix sur GitHub.
https://github.com/zabbix/zabbix
J'ai recherché CUser et j'ai trouvé un fichier CUser.php.

Nous avons trouvé la fonction user.update :
public function update(array $users) {
$this->validateUpdate($users, $db_users);
self::updateForce($users, $db_users);
return ['userids' => array_column($users, 'userid')];
}
Je n'ai trouvé aucune vérification d'autorisation, j'ai donc décidé de changer ma fonction en fonction de superutilisateur, je suis retourné à la requête et j'ai ajusté le payload.

Cela m'a renvoyé une erreur avec un message "invalid params".
En analysant encore plus le code, nous avons trouvé cette fonction :
/**
* 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;
}
}
}
D'après ce snippet, nous ne pouvons pas modifier nos rôles car notre rôle est vérifié en extrayant nos données du token API et en vérifiant dans la base de données si nous sommes cet utilisateur. Mais en analysant le code, on voit que usrgrps n'a aucune validation, et donc peut être abusé pour nous ajouter dans plusieurs groupes à la fois. Il n'y a aucune vérification pour empêcher un utilisateur de s'ajouter lui-même à des groupes auxquels il ne devrait pas avoir accès.
Essayons d'élever les privilèges à cause de ce manque de validation, j'ai modifié le payload et renvoyé la requête.

userid 3 correspond à l'ID de l'utilisateur matthew. usrgrps contient une liste d'IDs de groupe : 13 est un groupe interne et 7 est le groupe Zabbix administrators. Notre réponse du serveur confirme le succès de l'opération :
{"jsonrpc":"2.0","result":{"userids":["3"]},"id":1}
Maintenant, nous pouvons extraire les groupes d'utilisateurs de notre utilisateur actuel. Modifions la requête et renvoyons-la.

En vérifiant la réponse, on voit que l'utilisateur avec l'ID 3 est dans les groupes administrateurs Interne et Zabbix.
{"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}