[HACKTHEBOX] MACHINE — CONNECTED (FÁCIL) [HACKTHEBOX] MACHINE — ORION (FÁCIL) [HACKTHEBOX] MACHINE — CAP (FÁCIL) [HACKTHEBOX] MACHINE — REACTOR (FÁCIL) [HACKTHEBOX] MACHINE — DEVHUB (MEDIO)
HackTheBox • Write-up • Máquina Media

Connected.

RCE sobre un FreePBX vulnerable expuesto en un subdominio, shell como el usuario asterisk vía webshell PHP, y escalada final a root abusando de incron y de un bypass del control de integridad de firma de módulos de FreePBX. Del reconocimiento a las dos flags, paso a paso.

PlataformaHackTheBox
DificultadFÁCIL
Vector inicialRCE en FreePBX → webshell PHP → reverse shell
Escaladaincron + bypass de firma de módulos → root
CVEsCVE-2025-57819
Autorkeltich · KeltichCibSec
Nmap + Fuzzing→ FreePBX RCE→ Webshell PHP→ Reverse shell→ SSH (user)→ incron + firma bypass→ root
// 01

Reconocimiento

Primero realizamos un ping ICMP para verificar que la conectividad con la VPN es correcta:

Ping ICMP verificando conectividad con la VPN
Ping ICMP confirmando conectividad a través de la VPN

Con conectividad confirmada empezamos con el escaneo de puertos de la máquina:

Escaneo Nmap — puertos abiertos
Nmap — descubrimiento de puertos abiertos

Aparecen tres puertos diferenciados: el 22, por el que corre SSH; el 80, con un servicio web por HTTP; y el 443, con un servicio para la página que funciona por SSL. Con estos puertos identificados lanzamos un segundo escaneo para ver la versión de los servicios en ejecución:

Escaneo Nmap detallado — versiones de servicios
Nmap — detección de versiones de servicios

Vemos que corre un servidor web Apache. Reconocida toda la información de los puertos, convertimos la IP de la página a un dominio en nuestro /etc/hosts:

Asignación del dominio en /etc/hosts
Entrada del dominio de la víctima añadida a /etc/hosts

Al entrar en el dominio que hemos creado en /etc/hosts nos encontramos con la siguiente página:

Página principal del dominio configurado
Portal inicial servido por el dominio

Tras descubrir el portal, realizamos fuzzing a la página y encontramos una serie de cosas interesantes, entre ellas dos subdominios:

Fuzzing revelando dos subdominios
Fuzzing — descubrimiento de subdominios

Añadimos esas rutas a nuestro /etc/hosts:

Subdominios añadidos a /etc/hosts
Subdominios añadidos a /etc/hosts

Si vamos a connected.htb/admin encontramos el portal inicial. Sin embargo, connected.htb/ucp nos lleva a un panel de entrada de datos que pide usuario y contraseña:

Panel de login de FreePBX (UCP)
Panel UCP de FreePBX solicitando credenciales

Investigando un poco sobre FreePBX descubrimos que es una interfaz gráfica web de código abierto que permite gestionar Asterisk, un software libre que convierte una computadora estándar en una potente centralita telefónica. Aunque esta información no es especialmente relevante para la explotación, sí lo es un detalle: la versión de FreePBX que utiliza es vulnerable.

Versión vulnerable de FreePBX detectada
Versión de FreePBX en uso — vulnerable
// 02

Explotación

Esta versión de FreePBX contiene la vulnerabilidad CVE-2025-57819, que consiste en un RCE (ejecución remota de código). Para explotarla usamos el exploit publicado en este repositorio:

Exploit github.com/watchtowrlabs/watchTowr-vs-FreePBX-CVE-2025-57819

Ejecutamos el exploit contra la URL adecuada:

Ejecución del exploit de CVE-2025-57819
Ejecución del exploit CVE-2025-57819

El exploit nos crea una webshell PHP con la que podremos entrar en el sistema mediante una reverse shell generada en revshells.com. Un ejemplo de esa webshell:

Webshell PHP creada por el exploit
Webshell PHP creada por el exploit

Para la reverse shell escogemos la PHP popen de revshells.com y la introduciremos en la URL, pero antes nos ponemos a la escucha con netcat:

netcat en escucha por el puerto 4444
netcat a la escucha en el puerto 4444

Para poder insertar la reverse shell a través de la webshell hemos tenido que formatear correctamente el oneliner: el navegador no admite determinados caracteres especiales, así que hay que codificarlo en formato URL para que sea reconocible por la web:

Codificación URL del oneliner de la reverse shell
Reverse shell codificada en formato URL con un formatter

Con la reverse shell escogida y codificada, la insertamos en la URL proporcionada por el exploit:

Reverse shell insertada en la URL de la webshell
Reverse shell insertada en la URL de la webshell

Con ello obtenemos conectividad en el netcat abierto por el puerto 4444:

Conexión de la reverse shell recibida por netcat
Conexión recibida por netcat como usuario asterisk

Somos el usuario asterisk, coherente con lo que ya sabíamos: FreePBX se usa para gestionar Asterisk. Para tener una conexión más directa lanzamos otra reverse shell contra un listener de netcat en el puerto 4445 y obtenemos una bash:

Bash obtenida mediante una segunda reverse shell
Bash obtenida con una segunda reverse shell (puerto 4445)

Vamos al directorio /home/asterisk, donde encontramos la user flag:

User flag localizada en /home/asterisk
User flag localizada en /home/asterisk
User Flag
9cce3617240bb07c1db65074777c7284
// 03

Escalada de privilegios

Antes de escalar, nos conectamos por SSH para disponer de una consola con más comodidades, como el autocompletado por tabulador. Lo hacemos en tres pasos:

Paso 1 En la reverse shell creamos un directorio .ssh y dentro un archivo authorized_keys con nuestra clave SSH pública:
Creación de .ssh y authorized_keys con la clave pública
authorized_keys con nuestra clave SSH pública
Paso 2 En la máquina atacante cargamos nuestra clave SSH privada:
Carga de la clave SSH privada en la máquina atacante
Carga de la clave SSH privada en la máquina atacante
Paso 3 Nos conectamos por SSH a la máquina víctima; ya no nos pide contraseña:
Conexión SSH sin contraseña a la víctima
Acceso por SSH sin contraseña gracias a la clave pública

A continuación pasamos la herramienta de reconocimiento LinPEAS para analizar posibles vectores de escalada. Primero la transferimos a la máquina:

Transferencia de LinPEAS a la máquina víctima
Transferencia de LinPEAS a la máquina víctima

Ya en la conexión SSH, inicializamos LinPEAS y le damos permisos de ejecución para poder lanzarlo:

Permisos de ejecución y lanzamiento de LinPEAS
LinPEAS con permisos de ejecución, listo para ejecutarse

Tras la enumeración con LinPEAS descubrimos que los servicios de incron (iNotify Cron) se configuran y ejecutan en el sistema. Conviene entender qué hace incron: ejecuta tareas cuando un archivo o directorio cambia. Es como cron, que programa tareas para una fecha u hora, solo que incron dispara una acción cuando ocurre algo en el directorio que está auditando (un archivo modificado, borrado, movido, etc.). Es una potencial vía de escalada de privilegios.

Enumeración de incron

Paso 1 Comprobamos si incron está instalado en el sistema:
which incrond
Comprobación de incrond con which
incrond instalado en el sistema
Paso 2 Vemos si el servicio está activo:
systemctl status incrond
Estado del servicio incrond con systemctl
Estado del servicio incrond
Paso 3 Listamos las reglas del usuario actual:
incrontab -l
Listado de reglas de incron del usuario actual
Reglas de incron del usuario actual

A primera vista no tenemos nada con incron, pero si hacemos cat /etc/incron.d/* encontramos las reglas que carga el servicio incrond desde el sistema. Es el equivalente a la diferencia entre crontab -l (cron del usuario) y /etc/cron.d/* (cron global del sistema): con incron ocurre lo mismo.

Tras investigar de forma recursiva los archivos del directorio de incron encontramos lo siguiente:

Reglas de incron en /etc/incron.d
Reglas cargadas por incrond desde /etc/incron.d

Aparecen varias rutas, y una de ellas llama la atención. No es en sí misma una vía de escalada, pero es un punto de entrada interesante hacia un proceso que se ejecuta con más privilegios. En concreto, esta regla:

/var/spool/asterisk/incron IN_MODIFY,IN_ATTRIB,IN_CLOSE_WRITE /usr/bin/sysadmin_manager $#

Que nos indica lo siguiente:

Qué hace la regla
  • incrond vigila el archivo /var/spool/asterisk/incron.
  • Cada vez que ese archivo se modifica, cambia sus atributos o se cierra tras una escritura, se ejecuta sysadmin_manager.
  • El nombre del archivo que disparó el evento se pasa como argumento al script ($# en la sintaxis de incron).

Desde una perspectiva de seguridad esta ruta es un punto de interés por varias razones: por control de acceso (si un usuario sin privilegios puede modificar /var/spool/asterisk/incron, puede provocar la ejecución de sysadmin_manager); por superficie de ataque (cualquier dato que el script lea o cualquier argumento que procese debe validarse correctamente); y por el procesamiento de entradas (si sysadmin_manager interpreta de forma insegura el contenido del archivo o el argumento recibido, podría existir una vulnerabilidad).

A continuación revisamos los permisos que tenemos sobre las rutas /var/spool/asterisk/incron y /var/spool/asterisk:

Permisos sobre /var/spool/asterisk y su subdirectorio incron
Permisos sobre /var/spool/asterisk y /var/spool/asterisk/incron

Un dato relevante: tanto /var/spool/asterisk como /var/spool/asterisk/incron son drwxrwxr-x asterisk asterisk. Es decir, el usuario asterisk tiene permisos de escritura sobre el directorio que incrond monitoriza. Un proceso que se ejecute como asterisk puede crear, modificar o eliminar archivos dentro de /var/spool/asterisk/incron, lo que disparará la regla configurada. Y además, incrond corre como root:

incrond ejecutándose como root
incrond ejecutándose como root

Esto significa que es capaz de realizar operaciones privilegiadas.

Explicación de la posible escalada

Tenemos permisos de escritura sobre /var/spool/asterisk/incron. Sin embargo, al crear un archivo ahí observamos que desaparece inmediatamente: incrond detecta el evento configurado (IN_MODIFY, IN_ATTRIB o IN_CLOSE_WRITE) y ejecuta /usr/bin/sysadmin_manager, que abre el archivo y lo elimina mediante unlink(). Este comportamiento confirma que el directorio actúa como un buzón de peticiones entre el usuario asterisk y un proceso privilegiado, en lugar de un simple directorio de almacenamiento.

Al revisar el código de sysadmin_manager comprobamos que no ejecuta cualquier archivo de forma indiscriminada. Antes de invocar un hook realiza varias comprobaciones de seguridad:

Controles de sysadmin_manager
  • El nombre del archivo debe seguir un formato válido (modulo_hook o modulo.hook[.parámetros]).
  • El hook solicitado debe existir dentro del módulo correspondiente.
  • El módulo debe disponer de un fichero de firma (module.sig).
  • La firma GPG debe haberse realizado con una de las claves de la lista blanca del sistema.
  • El hash SHA-256 del hook debe coincidir con el registrado en la firma.
  • Los parámetros recibidos se validan para impedir caracteres potencialmente peligrosos.

Solo cuando todas estas comprobaciones son satisfactorias, sysadmin_manager ejecuta el hook con los privilegios de incrond, que en este sistema corre como root. Por tanto, el objetivo ya no es simplemente crear un archivo dentro de /var/spool/asterisk/incron, sino identificar un hook legítimo y firmado que pueda invocarse por este mecanismo y analizar si su implementación introduce una debilidad que permita acciones privilegiadas no previstas.

Explotación mediante incron

Cuando lanzamos un cat del archivo /usr/bin/sysadmin_manager —el script que usa incron sobre el directorio /var/spool/asterisk/incron— y filtramos con less, encontramos una ruta muy interesante. Recordemos que si cualquiera de las acciones (IN_MODIFY, IN_ATTRIB o IN_CLOSE_WRITE) ocurre en ese directorio, el script se encarga de eliminar lo que hayamos creado.

Ruta interesante dentro de sysadmin_manager
Ruta interesante localizada en sysadmin_manager

Al llegar a esa ruta encontramos algo curioso: un directorio llamado ucp que a su vez contiene otro directorio llamado hooks:

Directorio ucp con subdirectorio hooks
Directorio ucp con su subdirectorio hooks

Dentro del directorio ucp está el directorio hooks:

Contenido del directorio hooks
Contenido del directorio hooks

En hooks nos encontramos con una clase de archivos que sysadmin_manager no elimina al introducirlos en /var/spool/asterisk/incron. La idea será insertar en uno de esos archivos una reverse shell:

Reverse shell insertada en un hook legítimo
Reverse shell insertada en el hook legítimo

Después damos permisos de ejecución al archivo logrotate:

Permisos de ejecución para el hook logrotate
Permisos de ejecución sobre el hook logrotate

Bypass del control de integridad de firma

Ahora hacemos un bypass al control de integridad de firma de módulos. FreePBX implementa un sistema de seguridad para evitar que un atacante modifique su código fuente: cada módulo contiene un archivo .sig con los hashes criptográficos (SHA256) de sus archivos legítimos. Si el hash de un archivo no coincide con el del .sig, FreePBX deshabilita el módulo por seguridad. Así que lo que haremos será calcular un nuevo hash:

Cálculo del nuevo hash SHA256 del script malicioso
Cálculo del nuevo hash SHA256 del hook manipulado
Explicación Calculamos la firma digital única (SHA256) de nuestro script malicioso recién creado. Con awk '{print $1}' aislamos únicamente el hash, descartando el nombre del archivo, y lo almacenamos en la variable $NEW_HASH.

Ahora procedemos con la falsificación de la firma digital:

Falsificación de la firma digital con sed
Falsificación de la firma en el archivo .sig con sed
Explicación Usamos el editor de flujo sed para modificar el archivo de firmas en tiempo real (-i). Buscamos la línea correspondiente a hooks/logrotate = [HASH_VIEJO] y la reemplazamos con el nuevo hash calculado en el paso anterior. Al usar tuberías (|) como delimitadores evitamos que las barras (/) de la ruta corrompan la sintaxis del comando.

Auditamos el cambio:

Verificación del reemplazo de la firma
Verificación del reemplazo de la firma
Explicación Inspeccionamos el archivo modificado para asegurarnos visualmente de que la firma fue reemplazada con éxito.

Disparo del proceso privilegiado

Última fase: la explotación mediante incron. El servicio incron (Inotify Cron) vigila directorios específicos del sistema de archivos. Cuando detecta que se crea o modifica un archivo en esos directorios, ejecuta de inmediato una acción programada como root. Accedemos al directorio del trigger:

Acceso al directorio de cola de incron
Acceso al directorio de cola (trigger) de incron
Explicación Nos movemos al directorio de cola donde el proceso incron de FreePBX está configurado para "escuchar" y procesar órdenes de administración.

Finalmente llamamos al proceso de root:

Creación del archivo ucp.logrotate que dispara la regla de incron
Creación de ucp.logrotate — dispara la regla de incron como root
Explicación Creamos un archivo vacío con el formato de nombre exacto que espera la regla de incron. Al detectar la creación de ucp.logrotate, el proceso del sistema despierta, lee de forma transparente el archivo de firmas falso (que ahora es válido para él) y ejecuta nuestro script manipulado con los máximos privilegios del sistema, otorgándonos acceso como root.

En nuestro listener de netcat tenemos ya conectividad como el usuario root, de forma que conseguimos la root flag:

Conexión recibida como usuario root
Conexión recibida como root en netcat
Root flag obtenida
Root flag obtenida
Root Flag
2deb09ca5b05bf0550fab605e75f0c45
root@keltich:~/HackTheBox/Connected
root@keltich:~$

COMANDOS

← Volver a Artículos