Bankrupting Bezos: Donations CTF Challenges
This post describes the Donations and Donations (but I fixed it) challenges by tahmid-23
in the web category of University of Maryland Capture The Flag 2024.
Donations
Starting off with the first challenge, when we visit the provided website we are met with:
The message
Welcome to donations. Can you get the most donations?
suggests the goal is to accumulate as much virtual currency as possible. After registering for an account and logging in, navigating to a donations page displays:
Donating 1 currency unit to Mr Bezos displays the message “thank you for your contribution”. Inspecting the network requests in Dev Tools reveals that a POST request is sent to https://donations-api.challs.umdctf.io/api/donate
with body to=lisanalgaib¤cy=1
. Checking my profile page indicates that my currency did indeed reduce by 1.
Seeing an opportunity to claw back Jeff’s profits from all the shit I’ve bought on Amazon, I thought to try sending the currency as a negative number. Copying the request as a fetch request and modifying the payload to to=lisanalgaib¤cy=-10000
works, and when visiting the profile page we are met with
Wow, you’re rich! Your reward is UMDCTF{BE20$_1s_7h3_T0N6U3_OF_Th3_uN5e3N}.
Donations (but I fixed it)
The second version of the challenge has the description “Bezos is not happy with what you did to his net worth”. It has the same interface as before, but when we try to donate negative currency to Jeff Bezos we are met with a 403 Forbidden
and the response
{
"detail": "only Amazon can steal your money"
}
Clearly Mr Bezos has wisened up after the hit to his profits. My next thoughts were to try some other form of manipulation of the currency parameter: I tried various different ideas like sending NaN
, numbers larger than Number.MAX_SAFE_INTEGER
and arithmetic expressions that would evaluate to negative numbers, all of which were met with either another 403 Forbidden
or a 500 Internal Server Error
.
My next thought was to try changing the to
parameter to donate to myself. However providing my username resulted in a 403 Forbidden
with the response
{
"detail": "you may only donate to Jeff Bezos"
}
The author must have added validation to ensure the to
parameter was set to lisanalgaib
(Jeff Bezos’s username). This immediately made me think of a parameter pollution attack: if we send the to
parameter twice the author might only validate the first one.
Modifying the payload to to=lisanalgaib&to=my_username¤cy=10000
gives us another 403 but this time the response is
{
"detail": "you're too poor"
}
Progress! We’ve passed the validation to prevent you sending money to yourself, however I don’t actually have 10k currency to send (each user only starts with 1000 currency). Reading through the client side JavaScript reveals that the website attempts to fetch the flag once the user has more than 5000 currency:
localStorage.getItem('username') === p.username && p.currency >= 5e3 && a();
So we just need to sign up for 5 new user accounts and use the parameter pollution technique to send all 1000 currency back to the main account. I didn’t bother to automate this process as creating 5 accounts only took a minute or so, but if a larger number of accounts were required then writing a script to register accounts, grab the session JWT, then transfer the currency would have been a good idea.
Once we have the required 5000 currency the flag is revealed as
UMDCTF{TeS7_your_CHAL1En93S 6UyS}
Epilogue
The source code for the challenges can be found here: