Shop
- Challenge: Shop
- Category: Pwn
- Flag:
LYKNCTF{wr4p_wr4p_wr4p}
My initial read / first impressions
This challenge was a tiny shop program. It gives a menu, lets us buy items, and one of the items is the flag.
The important part was that the flag item was extremely expensive:
So obviously the intended path is not "earn enough money normally." This looked like one of those integer bug challenges where the shop math is the actual target.
The solve ended up being very simple: buy enough flags that the total price overflows.
The bug
The program calculates the total cost like this conceptually:
The problem is that total is a signed 32-bit integer. The program lets us choose a quantity, multiplies it by the item price, and does not properly check whether that multiplication overflowed.
The flag costs:
If we buy 60 of them, the real mathematical total is:
But signed 32-bit integers only go up to:
So the value overflows. In the binary, it wraps around into a negative number:
Now the check becomes basically useless. A negative total is definitely not greater than our balance, so the shop thinks we can afford it.
Exploitation
No fancy ROP, shellcode, or libc leak needed. We just buy 60 flags.
The interaction is:
Where:
That is enough to trigger the overflow and make the program print the flag.
You can also automate it with:
Why this works
The whole challenge comes down to trusting the result of an overflowing multiplication.
The intended total should be way too expensive:
But after signed 32-bit wrapping, the program sees:
So the control flow is:
buy flag item
-> quantity = 60
-> total cost overflows signed int
-> total becomes negative
-> total > balance check fails
-> purchase is accepted
-> flag is printed
So this was basically an integer overflow / signed wraparound shop bug. The program tried to protect the expensive flag with a price check, but the price check used the broken overflowed value.