Cookies picoCTF 2021 Solution

Published: April 2, 2026

Description

Who doesn't love cookies? Find the best cookie at this web challenge.

Remote

Navigate to the challenge URL and observe the cookie set by the server.

bash
# Visit the URL in your browser and check the cookies in DevTools (Application > Cookies)

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Observe the name cookie
    Observation
    I noticed the server sets a cookie named 'name' with a plain, unsigned integer value upon visiting the site, which suggested the server is using this integer directly as a database lookup key without any authentication or signing protecting it.
    When you visit the site, it sets a cookie named 'name' with an integer value (starting at 0). The server maps this integer to different items in its database. You need to find which integer value corresponds to the flag entry by iterating through values.
    Learn more

    HTTP cookies are key-value pairs stored in the browser and sent with every request to the server. The server uses the Set-Cookie response header to set them, and the browser sends them back in the Cookie request header. Here, the cookie value is a plain integer with no signing or encryption - making it trivially forgeable.

  2. Step 2
    Brute-force the cookie value
    Observation
    I noticed the integer cookie had no signature or session binding, which suggested that simply iterating through integer values with curl and grepping the response body for 'picoCTF{' would reveal the flag without any authentication bypass needed.
    Iterate the cookie value with curl and grep for the picoCTF prefix. 0-100 covers most CTF-scale databases; bump to 0-1000 if nothing hits.
    bash
    # Sweep 0-100, print only matches:
    bash
    for i in $(seq 0 100); do flag=$(curl -s -b "name=$i" http://<server>/check | grep -oE 'picoCTF\{[^}]*\}'); [ -n "$flag" ] && echo "id=$i $flag"; done
    bash
    # If nothing matches, widen the range:
    bash
    for i in $(seq 0 1000); do flag=$(curl -s -b "name=$i" http://<server>/check | grep -oE 'picoCTF\{[^}]*\}'); [ -n "$flag" ] && echo "id=$i $flag" && break; done

    Expected output

    id=18 picoCTF{3v3ry1_l0v3s_c00k135_...}
    What didn't work first

    Tried: Trying to manipulate the cookie name or value as a string (e.g. 'admin', 'flag', 'true') instead of iterating integers.

    The server ignores string values that do not parse as a valid integer index - the response body shows the same default page content with no error and no flag. The cookie is used as a numeric database row ID, so only integers map to real entries. Sequential enumeration starting from 0 is the correct approach.

    Tried: Sending requests without the cookie header at all, or checking the page response status code to detect the flag.

    Every request - with or without the cookie - returns HTTP 200, so status codes give no signal. Without the cookie the server returns the same default page on every hit. The only reliable signal is the presence of 'picoCTF{' in the response body, which is why grepping the output rather than checking the exit code is necessary.

    Learn more

    Why 0-100 first. Most CTF web apps seed their cookie database with a tiny ordered set of items - the flag entry typically lives in the first hundred IDs because the challenge is designed to be solved in seconds, not hours. Widen to 0-1000 only if the small sweep produces nothing.

    Detect success on the response, not the status code. A 200 response is not a success signal here - every integer returns 200. The signal is whether the page body contains the flag prefix. Piping through grep -oE 'picoCTF{[^}]*}' isolates the flag string and skips noisy IDs.

    This is an insecure direct object reference (IDOR)-style vulnerability combined with an unauthenticated enumeration attack. The server stores the flag at a specific ID in its cookie database and retrieves it based solely on the client-supplied cookie value, with no authentication check. The fix: never trust client-supplied identifiers alone for authorization; pair them with server-side session validation. For more on cookie-related bug shapes, see cookies and JWTs in CTF.

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{3v3ry1_l0v3s_c00k135_...}

The server maps integer cookie values to items in a database - brute-forcing the integer reveals which value corresponds to the flag entry.

Key takeaway

Insecure direct object references occur when a server uses a client-supplied identifier, such as a plain integer in a cookie, to look up a resource without verifying that the requester is authorized to access it. Because the client can freely set any cookie value, sequential enumeration trivially exposes every object in the store. The correct fix is server-side session binding: the server should associate each session with a specific user and reject any request for an object that session does not own, regardless of what identifier the client presents.

Related reading

Want more picoCTF 2021 writeups?

Tools used in this challenge

What to try next