ben-sb@home:~$

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:

donations website

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:

donations website

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&currency=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&currency=-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&currency=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: