Flask Session Cookies Forge
March 2023 (475 Words, 3 Minutes)
Flask uses a secure URL-safe signed serializer called “itsdangerous” to encode client-side session cookies. To prevent tampering by the client, the Flask app utilizes a secret key to sign the session cookie.
Although the session cookie may appear to be a sequence of random characters, it is actually easy to decode with the appropriate key. In this blog, we will look at how flask application cookies can be modified to grant different authentication-level privileges.
Exploitation Phase:
Our web application successfully authenticates into any account and creates a cookie for the sign-on. The web application is made with a flask backend which means the cookies will be flask signed.
The flask session package tracks, stores, and validates the session cookies. When using sessions, the data is typically stored in the browser as a cookie, referred to as the session cookie. Unlike a regular cookie, Flask employs cryptographic signing to secure the session cookie. This implies that although the contents of the cookie can be seen, it can’t be altered without the secret key utilized to sign it. Hence, it’s advisable to use a lengthy and intricate string as the secret key. Upon setting the session cookie, all subsequent server requests authenticate the cookie’s validity by using the same secret key to decode it. If Flask is unable to decrypt the cookie, its contents are disregarded, and a new session cookie is issued to the browser. These cookies may seem similar to JWT tokens but are not JWT tokens. Here, our test web application creates a flask cookie during authentication to the server.
The token can be successfully decoded in jwt.io, as shown below, but cannot be edited the same way as normal JWT tokens. Changing the value in jwt.io and re-using the cookie will prompt a 500 error on the page.
Now, to get to the fun part, Our goal is to decode the cookie and change any values that might favour our authentication and grant us access to some juicy data, cause why not. In this engagement, i came across the flask_unsign tool that does the “magic” of decoding, bruteforcing and resigning. Pretty neat huh!!(scriptkiddie voice). One can install it simply using python pip package.
└─$ pip3 install flask_unsign
First things first, Check what data is embedded inside the flask cookie. We do this using the following Flask_unsign command:
└─$ python3 -m Flask_unsign --decode --cookie 'eyJpc0hhY2tlZCI6ZmFsc2V9.ZCauZA.Pwa3t9s4ER7Ct6NM9Uc_UPnMqLU'
As shown above, the tool decodes the value part , same as we observed in jwt.io.
{‘isHacked’: False}
Our goal now is to change the value above to True
But, If we proceed to signing the key, without the secret used to sign, the appliaction will deem the cookie as invalid and slurp us with another 500 error.
To prevent this, we are going to bruteforce for the key used to sign the cookie using the flask_unsign tool, again!. This can be achieved using the command below:
└─$ python3 -m flask_unsign --wordlist /usr/share/wordlists/rockyou.txt --unsign --cookie 'eyJpc0hhY2tlZCI6ZmFsc2V9.ZCauZA.Pwa3t9s4ER7Ct6NM9Uc_UPnMqLU' --no-literal-eval
The screenshot below shows the decoded secret as “secret”
we can now move ahead to sign a new cookie with value {‘isHacked’: True} using the secret key ‘secret’ using the command:
└─$ python3 -m flask_unsign --sign --cookie "{'isHacked': True}" --secret 'secret'
The screenshot below shows the new flask cookie with the magic value to get us into the application.
We can then go ahead and paste the cookie into our browser and reload the page to use the fresh cookie.
We can now see the secret “data” that we have worked hard to see below.
TAKEAWAYS
As unknown once said, If you don’t secure your Flask cookies, you might be giving away more than just crumbs.