🧠InÃcio da jornada
ontem foi dia de teoria. IDOR foi fácil, quase leve demais.
- simples de entender
- fácil de identificar
- extremamente comum
Parecia até suspeito.
Hoje vieram os write-ups. Três deles. Tudo fazia sentido. A confiança subiu.
E como toda boa história… a prática tratou de equilibrar as coisas.
🎬 ATO 1 — Expectativa vs realidade
Nome do lab: Insecure Direct Object References
Classificação: Apprentice
Pensamento automático: "5 minutos e acabou"
A realidade observando de canto…
Objetivo
pegar a senha do Carlos e fazer login. Simples. Direto. Sem mistério.
Exploração inicial
Interface:
- e-commerce
- produtos
- conta
- nada demais
Até que… Live chat
Intuição ativada: "É aqui." (essa informação também estava na descrição…)
🎬 ATO 2 — Cadê meus requests?
Primeiro passo clássico: abrir o Caido.
Enviei mensagens no chat…
E então: apenas UMA requisição apareceu
GET /chat HTTP/1.1
Resposta: HTTP/1.1 101 Switching ProtocolE depois? Nada.
Nenhuma requisição para novas mensagens.
🧠Pensamento interno
"Como assim não tem request?"
"Isso não faz sentido…"
Sistema quase entrando em pane.
🎬 ATO 3 — Descobrindo um novo mundo
Hora de pedir ajuda (Gemini)
E então veio a resposta: WebSockets
Diferença essencial:
HTTP:
- Requisição → Resposta
- Cliente inicia
- Stateless
WebSocket:
- Conexão aberta
- Comunicação contÃnua
- Stateful
O momento mágico
HTTP/1.1 101 Switching ProtocolEsse é o handshake
A partir daqui: conexão aberta. Troca contÃnua de mensagens
Ferramenta nova desbloqueada
Dentro do Caido: WS History
E lá estava tudo. As mensagens do chat… em tempo real.
MAGIA.
🎬 ATO 4 — O botão suspeito
Ainda sem IDOR, mas menos perdida.
Hora de explorar mais fundo.
botão: View transcript. Cliquei…
Nova requisição:
POST /download-transcript HTTP/1.1Conteúdo enviado
- histórico completo do chat
- mensagens estruturadas
Insight
"Se a senha do Carlos existe… deve estar no histórico dele."
Pergunta do milhão
Como sair do MEU histórico e acessar o do Carlos?
🎬 ATO 5 — A pista escondida
Enviei a requisição manualmente.
Resposta:
HTTP/1.1 302 Found
Location: /download-transcript/3.txt3.txt… Isso não era aleatório.
Próximo passo
GET /download-transcript/3.txt✔Download realizado ✔Meu histórico
Confirmado!
isso é uma referência direta a um objeto
🎬 ATO 6 — O ataque
Hora do clássico: enviar para o Repeater
Testes:
2.txt… NADA1.txt… BINGO
Conteúdo encontrado
Hi Hal, I think I've forgotten my password…Poxa, Carlos… Jogando a senha direto no chat… vacilo.
Vulnerabilidade confirmada
IDOR clássico:
- acesso direto a arquivos
- sem validação
- sem autenticação adequada
🎬 ATO 7 — Olhando por trás da cortina
Hora de entender o "porquê"
Arquivos encontrados no código-fonte
/resources/js/chat.js/resources/js/viewTranscript.js
Foco: viewTranscript.js
O que o código faz
- Coleta mensagens do chat
- Monta um array:
var transcript = [];- Envia via POST:
var xhr = new XMLHttpRequest();- Após resposta:
window.location = xhr.responseURL;O problema
O servidor responde com:
/download-transcript/3.txtE o navegador simplesmente: acessa e baixa
Sem questionar.
🎬 ATO FINAL — O verdadeiro vilão
No servidor, provavelmente:
/var/www/app/transcripts/Arquivos:
1.txt→ Carlos2.txt→ Maria3.txt→ você
Falha crÃtica
👉 nenhum controle de acesso
O servidor:
- não verifica quem fez a requisição
- não valida o dono do arquivo
Conclusão
O lab parecia fácil. E tecnicamente… é.
Mas trouxe aprendizados importantes:
- nem tudo passa pelo HTTP tradicional
- WebSockets mudam o jogo
- IDs simples podem esconder grandes falhas
E Carlos…
não coloque senha no chat.