Stonk
Challenge
A stock trading server. We had the server source (app.py, process.py) and the intern’s client (user.py). You can buy a stock, sell it back at the same price, or trade one stock for another. Requests go through a queue, and a trade is only honored when the stock you want is cheaper than the one you give up. Flags cost $9001, well above the starting balance.
The suspicious part is the backup. Every action snapshots your portfolio, and there is a throttle:
| |
If you make more than ten requests inside a ten second window, the server rolls you back to the backup:
| |
Approach
A trade deducts your stock when it is first posted to the TRADEPOST, and only adds the new stock once the trade actually processes. The backup restore happens before the trade gets pulled from the tradepost. That ordering is the bug.
So if a trade is in flight when the throttle trips, the rollback restores your old balance and portfolio, then the pending trade still completes and hands you the traded-for stock. You keep the gains and pay nothing for them. Buy and sell increment the request counter, but the exchange does not, so the sequence has to cross the threshold on buy/sell and let the trade ride along.
Aidan and I traced the ordering together. The plan that came out of it: pad with cheap buy/sell pairs to approach the limit, buy one expensive stock, trip the throttle with one more sell, then trade the expensive stock for itself so the rollback fires while that trade is posted. Repeat, sell off the kept stock, and the balance climbs past $9001.
Solution
| |
The scraper runs asynchronously, so the rollback and the trade do not always land in the right order. Looping hits the happy path soon enough. Once the balance cleared $9001, option 5 on the menu bought the flag:

Flag
csawctf{R_Yu0_7h3_w0lf_0f_w4ll_57r337}