BreakingBankChallengeWrite-Up(Web)-HTBUniversityCTF2024
Omar Mohamed
Thanks for sharing!
بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ

Hello there! Today, I'm going to walk you through solving the Breaking Bank challenge from HTB University CTF 2024.
Before we get started, if you want to try the challenge, you can find it here.
Content
Let's dive in!
Challenge Overview

Initial Recon
First thing I did was check out the website. We got a login and register form:

Made my account and logged in. We have a cryptocurrency platform with Market Overview and a portfolio which my balance is set to zero:


We also got another 2 interesting tabs: friends and Transactions.
Source Code Review
The source code was quite big, so I took it in reverse - how can I get to the flag?
Searched for
flag.txt in VS code and found this:We see that we can get the flag if we drained
CLCR coin (set it to 0) of the user with this email: financial-controller@frontier-board.htbSo how can we do that?
Remember we have a transaction page, so simply we can transfer all the amount of this coin to another user, and we get it
In
/src/pages/Transaction.tsx, found this endpoint: /api/crypto/transactionNotice it needs a JWT token? Let's check our token in localStorage:

Passing it to jwt.io, we got:
Header:
Body:
We notice this file:
http://127.0.0.1:1337/.well-known/jwks.json
which gets us this:Quick Note: JWKS (JSON Web Key Sets) is a set of keys containing the public keys used to verify any JWT issued by an authorization server. Thejku(JWK Set URL) header parameter is used to retrieve these keys.
Let's keep it for later and understand the logic first
Verification Function Analysis
(where the good stuff begins)
searching in vscode for
verify, we got verifyToken function in /challenge/server/services/jwksService.jsThe functionis pretty basic but here are some parts which pop up:
here it checks if
jku header starts with http://127.0.0.1:1337/The
kid must match the KEY_ID on the server, which we can easily get from our own tokenNow for the interesting part:
it gets some data from the link in
jku header, which in our token was: http://127.0.0.1:1337/.well-known/jwks.jsonNext, the function retrieves the
jwk whose kid matches the server's, then passes it to the jwkToPem function to convert it into a PEM-formatted public key:The
jwkToPem function ensures the key is of type RSA, converts its components (n and e) to base64url, and creates a PEM public key using Node's crypto module.This step is important because we'll use a similar approach to craft our own key later.
now lets's summer up what we have so far:
- Goal: Transfer all
CLCRfromfinancial-controller@frontier-board.htbto get the flag. - JWT Validation: The server checks the
jkuURL and fetches a key (jwk) to verify tokens. - Plan: Host a fake key on a controlled server, make the server fetch from it, and forge a token
First Lets make our hosted fake key
I made the following script, Let's take it bit by bit
- Key Generation:
- Generates an RSA key pair (
privateKeyandpublicKey) for signing and verifying tokens. KEY_IDis a unique identifier for the key (you get it from your token)
- Generates an RSA key pair (
- JWKS (JSON Web Key Set):
- Converts the
publicKeyto a JWK (JSON Web Key) format. - Adds metadata (
alg,use,kid)
- Converts the
- JWT (JSON Web Token):
- Creates a token with a payload (
emailandiat). - Custom
headerincludes:kid: Matches the key ID (KEY_ID) (Make sure to put yours)jku: URL pointing to the fake JWKS file.
- Signs the token using the private key.
- Creates a token with a payload (
- Output:
- Logs the forged JWT and JWKS to use in the attack.
If you tried this... it will not work, know why?
Remeber the
it has to start with
http://127.0.0.1:1337/but how can we make it fetch from our server of it has to start with this???
Answer is open redirect
So a little of searching (Also these
// TODO commenets made it easier to spot the right stuff) we find analytics.js file with this insideThis is a straight up redirection
so that's how we are gonna make the server fetch our hosted key
You can use ngrok, but I hosted mine on my website:
https://h4ck.run/jwks.json
The final url will look like this:http://127.0.0.1:1337/api/analytics/redirect?url=https://h4ck.run/jwks.json/&ref=dummy
Notice the dummy
ref is required in order to redirectNote: This script generates its keys dynamically in each run, so make sure to use the right token with its right hosted key
Now since we finally got our token, lets try it out
Getting Access
Now with our forged token, let's check if it worked:

Nice! Our portfolio value isn't zero anymore, which means we got in!
Getting the Flag
Made another account and added it as a friend to transfer the coins to. But when trying to transfer...

Still need to bypass the OTP. Looking at
otpMiddleware.js:It's using
includes()!If you send a dummy otp and see the request in burp, you can see the otp is sent in an array

So simply make and array with all possible otps and you got it
["0001","0002","0003","0004","0005"..."9999"]
The command to generate it:
To copy it use:
Note: Put it in burp by deleting the existing array and putting yours. Don't put it directly in the input beacuse it will be handled as one string in this array, as you can see the otp was passed as a string


And here is our flag!
Flag:HTB{rugg3d_pu11ed_c0nqu3r3d_d14m0nd_h4nd5_789dfb9e1ce0f5ca7741ba640da6ce29}
Achievement
I'm proud to share that our team ranked in the top 200 in this CTF! Here's the certificate of achievement:

Key Takeaways
This challenge had a bit of everything:
- JWT and JWKS stuff
- Open redirect vulnerability
- OTP bypass using array tricks
Really enjoyed solving this one! Hope you liked the write-up. See you in the next one!
psst.. you can buy me a coffee here 👀. thank you!
Tags:

