Main menu

Star InactiveStar InactiveStar InactiveStar InactiveStar Inactive
 

 

After the fiasco back in Level 0, management has decided to fortify the Secret Safe into an unbreakable solution (kind of like Unbreakable Linux). The resulting product is Secret Vault, which is so secure that it requires human intervention to add new secrets.
A beta version has launched with some interesting secrets (including the password to access Level 4); you can check it out at https://level03-1.stripe-ctf.com/user-ksboyymbik. As usual, you can fetch the code for the level (and some sample data) via git clone https://level03-1.stripe-ctf.com/user-ksboyymbik/level03-code, or you can read the code below.

Ah, fortify the safe. Here took a little more effort, but relied on good ol' SQLi. Check out lines 86-99:

     query = """SELECT id, password_hash, salt FROM users
               WHERE username = '{0}' LIMIT 1""".format(username)
    cursor.execute(query)

    res = cursor.fetchone()
    if not res:
        return "There's no such user {0}!\n".format(username)
    user_id, password_hash, salt = res

    calculated_hash = hashlib.sha256(password + salt)
    if calculated_hash.hexdigest() != password_hash:
        return "That's not the password for {0}!\n".format(username)

    flask.session['user_id'] = user_id

Again, not a whole lot of parameter sanitisation. Since we can control what $username and password is, and further in the code we define what the user ID is from the SQL query, we can just tell the database to respond with whatever we wanted, maybe A UserID, the hash and salt of our choosing by using a UNION:

' UNION ALL SELECT 2, "3e4e4a24cbb115d3a5d07005d248beca2b0e623d7973cb04526855abe0315868", "jason"'

At this point, the database is going to return 2 for "id", the hash for "password_hash" and jason for "salt". Since we also control what the password will be, and we know the HASH is SHA256 we can calculate and populate as required.