ØxOPOSɆC - Don Joe [Crypto]

ØxOPOSɆC - Don Joe [Crypto]
Don Joe insists his site is as secure as can be! Can you prove that the best web dev of all time is wrong?"
URL: https://don-joes-blog.herokuapp.com/
There are two flags

Don Joe's Blog has a very simple interface and lists only 4 blog posts:

Clicking on the articles we can see that they're being fetched using the id query parameter:

Luckily I didn't even have to do any tests, OWASP Zap immediately let me know how to exploit this LFI vulnerability:

So, let's see what we can find on etc/passwd:

One flag down!


When we go to the m4st3rfully_h1dd3n directory we find the project's source code:

As instructed, let's login as supreme_user:

After logging in we see the same "hidden" home page, but now authenticated as supreme_user:

The session is maintained using a cookie called auth:

When we base64-decode the cookie (using CyberChef) we see the authenticated user data plus some encrypted data, which should be some sort of checksum:

Analysing the source code

Looking at the source code we can see that there is a user DB (users_db.py) with 2 users, supreme_user and admin:

{"username": "supreme_user", "password": "af351f443130f369c0cde982110a07bb8f88112ccfb0b9236eac1e2a23cb0541", "role": 0},
{"username": "admin", "password": "2ae3a0f2ef89bf388e7cdc7f5fc9f1b60e5542d0a6c2f6f1cf88190d0ab2b711", "role": 1}

Searching for flag-related methods we see the admin_flag() function, which is triggered by navigating to the admin route. In short, if the user is authenticated as admin the application renders the final flag, else it displays the "Forbidden" route page:

The is_admin function:

  1. checks for a valid session;
  2. checks that there's a user that matches the session;
  3. prints some debug info;
  4. returns true if the user role is 1, which from what we can see is only true for the admin user.

The get_session function checks the auth cookie and then returns the parsed data:

The parse_session function:

  1. splits the cookie into data and signature;
  2. base64-decodes both parts of the cookie;
  3. checks that the data matches the signature;
  4. returns all the fields on the decoded data as a dictionary.

Now for the signature checking, it seems like the data is appended to some random SECRET value and then hashed using SHA-256:

However, the SECRET is not easily brute-forceable since it contains between 8 and 15 random bytes:

Length Extension Attack

TL;DR: given a hash that is composed of a string with an unknown prefix, an attacker can append to the string and produce a new hash that still has the unknown prefix. [Source]

Knowing that this vulnerability affects SHA-256, we can create a script that:

  1. retrieves a valid auth cookie for the supreme_user by authenticating with the known credentials;

2. for all possible lengths of SECRET, uses hash_extender to create valid cookies with the admin authentication data (username and hashed password):

3. for each of the cookies, try to access the admin route and see if one of the cookies is a valid form of authentication:

4. Putting it all together we get a hit!