Reconocimiento
Primero realizamos un ping ICMP para verificar que la conectividad con la VPN es correcta:
Con conectividad confirmada empezamos con el escaneo de puertos de la máquina:
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:
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:
Al entrar en el dominio que hemos creado en /etc/hosts nos encontramos con la siguiente página:
Tras descubrir el portal, realizamos fuzzing a la página y encontramos una serie de cosas interesantes, entre ellas dos subdominios:
Añadimos esas rutas a nuestro /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:
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.
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:
github.com/watchtowrlabs/watchTowr-vs-FreePBX-CVE-2025-57819
Ejecutamos el exploit contra la URL adecuada:
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:
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:
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:
Con la reverse shell escogida y codificada, la insertamos en la URL proporcionada por el exploit:
Con ello obtenemos conectividad en el netcat abierto por el puerto 4444:
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:
Vamos al directorio /home/asterisk, donde encontramos la user flag:
9cce3617240bb07c1db65074777c7284
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:
.ssh y dentro un archivo authorized_keys con nuestra clave SSH pública:
A continuación pasamos la herramienta de reconocimiento LinPEAS para analizar posibles vectores de escalada. Primero la transferimos a la máquina:
Ya en la conexión SSH, inicializamos LinPEAS y le damos permisos de ejecución para poder lanzarlo:
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
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:
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:
Que nos indica lo siguiente:
- 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:
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:
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:
- El nombre del archivo debe seguir un formato válido (
modulo_hookomodulo.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.
Al llegar a esa ruta encontramos algo curioso: un directorio llamado ucp que a su vez contiene otro directorio llamado hooks:
Dentro del directorio ucp está el 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:
Después damos permisos de ejecución al archivo 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:
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:
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:
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:
Finalmente llamamos al proceso de root:
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:
2deb09ca5b05bf0550fab605e75f0c45