# SECCON 13 CTF Final 作問記

CTF challenge: FastCGI ContentLength uint16 overflow in a Go proxy lets a crafted body smuggle a FCGI_PARAMS record setting HTTP_GIVEMEFLAG=true past nginx filtering.

- Payout: Research
- Program: SECCON 13 CTF super-fastcgi
- Write-up by: RyotaK
- Disclosed: 2025-04-14
- Write-up quality: 8/10
- Original: https://blog.ryotak.net/post/seccon-13-ctf-final-author-writeup/
- Library page: https://bugbountylibrary.com/r/blog%3Ablog-ryotak-net-post-seccon-13-ctf-final-author-writeup
- Tags: area:web domain:web impact:integrity kind:research platform:research tech:go tech:nginx technique:source-review vuln:request-smuggling

**Target:** Go FastCGI client/server proxy behind nginx
**Root cause:** The Go FastCGI client writes the whole request body as a single FCGI_STDIN record, truncating ContentLength to uint16; the child reads only that many bytes and parses the remainder as new FastCGI records.
**Steps:**
1. Read nginx.conf: requests with `$http_givemeflag` are rejected with 403, so goal is to reach child with HTTP_GIVEMEFLAG=true.
2. Note server/fcgi.go writeStdin sets `ContentLength: uint16(contentSize)` and writes full content unsplit.
3. Send a body of 65537 bytes so ContentLength overflows to 1.
4. Craft body `a\x01\x04\x00\x01\x00\x15\x00\x00\x0f\x04HTTP_GIVEMEFLAGtrue\x01\x05\x00\x01\x00\x00\x00\x00[65499 bytes of a]` so child parses `\x04` as FCGI_PARAMS with HTTP_GIVEMEFLAG=true and `\x01\x05...` as terminating FCGI_STDIN.
5. child returns the flag because params["HTTP_GIVEMEFLAG"]=="true".
**How found:** Inspired by DEF CON 32 'SQL Injection Isn't Dead - Smuggling Queries at the Protocol Level'; surveyed binary protocols and noticed the FastCGI client never splits FCGI_STDIN records, so uint16 ContentLength overflows.
**Exploitation:** Attacker sends an oversized body through nginx and the Go server; nginx and server see no Givemeflag header so filtering passes, but the child re-parses the overflowed record stream and receives an injected FCGI_PARAMS record setting HTTP_GIVEMEFLAG=true, returning the flag.
**Insight:** When a proxy re-serializes a length-prefixed binary protocol, check whether length fields are narrower than the buffer actually written; an overflow makes the downstream parser treat body bytes as new protocol records.

## Proof of concept (copied exactly from the original report)

**FastCGI integer overflow smuggling payload**

```
a\x01\x04\x00\x01\x00\x15\x00\x00\x0f\x04HTTP_GIVEMEFLAGtrue\x01\x05\x00\x01\x00\x00\x00\x00[65499バイトのa]
```

**Admin callback request using stolen code**

```
GET /auth/callback?code=接種した「code」パラメーター%26login_target=APP%23&state=a
Host: admin.example.com
Cookie: state=a
```

