Miku's Autograph
Background
I am so proud of the fact that I have Miku's autograph. Ha! You don't!

- Difficulty: Medium (I think it's an easy challenge, but it's really hard for me)
- This challenge doesn't have source code
Enumeration
Access the link, it leads me to the page that has a Magic Miku Login button. When I click on it, it returns a text: Access Denied: You are not miku_admin!.

Maybe this challenge is related to cookies, so I decides to check the cookies of this page, but nothing shows up:

Hmm, maybe I should check on the source of this page:

The page has a script that when I click on the Magic Miku Login button, it will fetch the content of the endpoint /get_token, then passes the data to magic_token variable and sends it to the endpoint /login. Finally, it will return the result to an innerHTML.
First, I will check on the endpoint /get_token to see what's in there:

This endpoint contains JSON data which has a your_token key with a JWT format value, the JWT changes whenever I reload the page.
A
JSON web token (JWT)is mainly composed ofheader,payload,signature. These three parts are separated bydots( . ). You can read more about it here
I will use jwt.io to parse this JWT:

This is a JWT with HS256 algorithm, and with the value of sub in the payload, we know that we are currently a miku_user. First, I will change the value of sub to miku_admin to see if I can get the flag with this new JWT ( Although we need to know the secret key so we can have a verify signature when changing a value, maybe the server won't check the signature so we can get the flag ).

I will use curl to POST data to the endpoint /login:
curl -X POST -d "magic_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtaWt1X2FkbWluIiwiZXhwIjoxNzM5ODYyNDQxfQ.7JyvQg5m83bZYb2LGu9AhTvUovWcEEZkuuQqVFbtUfU" https://miku.web.broncoctf.xyz/login

It says Invalid Magic Login!. Hmm, not easy like that, I guess? Next, I decides to remove the signature part of the JWT to see if I can bypass the server ( Remember, when removes the signature part, you shouldn't remove the dot because the dot maybe tricks the server that we send to it a JWT with full three parts ):
curl -X POST -d "magic_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtaWt1X2FkbWluIiwiZXhwIjoxNzM5ODYyNDQxfQ." https://miku.web.broncoctf.xyz/login

It still returns Invalid Magic Login!. Okay, now I will perform dictionary attack to find the secret key, I will use hashcat with the wordlist rockyou to find the secret key.
hashcat -a 0 -m 16500 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtaWt1X3VzZXIiLCJleHAiOjE3Mzk4NjQwNzl9.ydrqrbtADQ-0pzttleUQdXQFYlL1HNEkhkJKyz2gXkU" /usr/share/wordlists/rockyou.txt

And hashcat returns the exhausted status, which means no matching secret key was found. This is the most desperate moment for me, I spent hours and hours with different tools, different wordlists just to find the secret key, but nothing works. ( I'm so noob lol, partly because I don't have much experience with JWT ).
At last, I found a tool called jwt_tool. Reading through its documentation, this tool have an exploitation mode with -X switch. This mode has an attack method called a that is to set the value of alg in the header to none then removes the signature part.
Hmm, this sounds interesting, I will use the default JWT of the /get_token endpoint to test the exploit because when we send the default token to the /login endpoint, we will receive the Access Denied: You are not miku_admin! message, and if the exploit successes, it will also return the Access Denied: You are not miku_admin! message otherwise it will return the Invalid Magic Login! message.
python jwt_tool.py "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtaWt1X3VzZXIiLCJleHAiOjE3Mzk4NjgxMTJ9.38GFWNGYSf6LAwEVWW-xeWUNzD98o0GHs7CLTtkirf0" -X a

We will POST this JWT to the /login endpoint to see the result:

And yesss!! This is the result that we want!
Exploitation
Now, using this attack method, we need to change the value of sub to miku_admin, and we can also use this tool to do that with -I to update existing claims with new values, -pc switch defines the payload and -pv switch defines the new value that we want to change.
python jwt_tool.py "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtaWt1X3VzZXIiLCJleHAiOjE3Mzk4NjgxMTJ9.38GFWNGYSf6LAwEVWW-xeWUNzD98o0GHs7CLTtkirf0" -X a -I -pc sub -pv miku_admin

Let's see if we can get the flag with this exploit:

Finally, I feel so happy when I get the flag of this challenge, OMG!
- Flag:
bronco{miku_miku_beaaaaaaaaaaaaaaaaaam!}
Conclusion
What we've learned:
- JWT authentication bypass via alg header injection ( we can set the alg header to none value ).