Description
Mmm, I wonder what's inside this cookie. The server is baked with Flask.
Setup
Navigate to the challenge URL and log in to obtain a session cookie.
Confirm flask-unsign is installed before brute-forcing.
# Open the challenge URL and note the session cookie in DevToolspip show flask-unsignSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Capture the Flask session cookieObservationI noticed the challenge description says the server is baked with Flask, which suggested that the authentication mechanism relies on Flask's signed session cookies and that inspecting the raw cookie value would reveal the payload structure and field names controlling access.Log in to the site (any username works). Open DevTools > Application > Cookies and copy the 'session' cookie. A captured value looks like a base64-ish blob with two dots separating three segments (payload.timestamp.signature).Learn more
Flask session cookies are signed with HMAC-SHA1 using the app's
SECRET_KEY. The format isbase64(json_payload).base64(timestamp).hmac_signature. Without the secret key, an attacker cannot forge a valid signature. But if the secret key is weak or guessable, the cookie can be cracked and reforged with arbitrary contents.Inspect the payload first. Take the first segment (before the first dot), URL-safe base64 decode it, and you get the JSON. That is how you discover the field name
very_authand its current value (e.g.,guest):echo '<first_segment>' | base64 -d. Knowing the exact field name matters because the server checks a specific key, not just any field that says "admin".Step 2
Brute-force the secret key with flask-unsignObservationI noticed the server source code stores a list of cookie names and derives its SECRET_KEY from that same list, which suggested using flask-unsign with a targeted wordlist of those cookie names to crack the weak, guessable key rather than a generic password list.Install flask-unsign and run it against the session cookie with a wordlist. The secret key is 'snickerdoodle' - a cookie name that appears in the server's list of cookies.bashpip install flask-unsignbashflask-unsign --unsign --wordlist cookie-names.txt --cookie "<your_session_cookie_value>"Expected output
[*] Valid secret key found: snickerdoodle
What didn't work first
Tried: Running flask-unsign with a generic password wordlist like rockyou.txt instead of a cookie-names wordlist
rockyou.txt contains passwords, not cookie names, so it will not contain 'snickerdoodle' or any of the other cookie names the server lists. The server's source code explicitly picks the SECRET_KEY from its own cookie-name array, so only a wordlist sourced from that array will find it. Using rockyou.txt produces no match and wastes significant time on millions of irrelevant candidates.
Tried: Trying to decode the full cookie manually with base64 -d without using flask-unsign to verify the signature
Decoding the payload segment reveals the JSON structure (like the 'very_auth' field), but that does not give you the secret key. Without the secret key you cannot produce a valid HMAC signature for a forged payload, so the server will reject any manually crafted cookie with a signature mismatch error. flask-unsign is needed to both crack the key and re-sign the new payload.
Learn more
flask-unsign is a tool specifically designed for attacking Flask session cookies. It tries each word in a wordlist as the potential
SECRET_KEY, verifying whether it produces a valid HMAC signature for the given cookie. The wordlist here should be a list of cookie names (the challenge hints at this - the server uses a cookie name as its secret key).Where the wordlist comes from. View the challenge source (the linked Flask app, usually a
server.py) and find the array of valid cookie names presented on the login page. Copy the list line-for-line intocookie-names.txt, one per line. That is your wordlist; the secret key is one of those names verbatim. The key "snickerdoodle" is a type of cookie - the challenge theme is literal.Step 3
Forge an admin session cookieObservationI noticed that decoding the original session payload revealed a 'very_auth' field set to 'guest', and with the recovered secret key 'snickerdoodle' in hand, this suggested signing a new cookie with 'very_auth' set to 'admin' to gain elevated access.Once you have the secret key, use flask-unsign to sign a new session cookie with admin privileges. Replace your browser cookie with the forged value and refresh the page to see the flag.bashflask-unsign --sign --secret 'snickerdoodle' --cookie "{'very_auth':'admin'}"bash# Then set this value as your session cookie in the browserWhat didn't work first
Tried: Signing the cookie with the field name 'admin' set to true instead of using the exact key 'very_auth' with the value 'admin'
The server checks the specific key 'very_auth' in the session dict. Sending a cookie like {'admin': true} or {'is_admin': 1} does not match what the server reads, so the page still treats you as a guest. You must inspect the original decoded payload to learn the exact field name before forging.
Tried: Setting the forged cookie value in the request headers manually using curl instead of replacing it in the browser
This can work but a common mistake is forgetting to URL-encode the cookie value or wrapping it incorrectly with quotes, causing the server to see a malformed cookie and reject the session entirely. The safer path for this challenge is to paste the forged value directly in DevTools > Application > Cookies so the browser handles encoding automatically on the next page load.
Learn more
With the secret key known, you can sign any JSON payload and the server will accept it as authentic. The
very_authfield controls access level - setting it toadmingrants privileged access. This is why Flask's documentation strongly warns against using guessable values forSECRET_KEY: it should be at least 24 bytes of high-entropy random data.The correct fix is to generate a strong random key:
python3 -c "import secrets; print(secrets.token_hex(32))"and store it in an environment variable, never hardcoded in source.
Interactive tools
- Flask Session DecoderDecode Flask / itsdangerous session cookies. Splits payload, decompresses zlib, parses JSON, and verifies the HMAC signature when given the secret.
Flag
Reveal flag
picoCTF{pwn_4ll_th3_cook1E5_...}
Flask session cookies are HMAC-signed with the SECRET_KEY - a weak or guessable key lets anyone forge a valid session with arbitrary contents.