pay2win – Web
Do you have enough money to buy the flag?
This challenge was pretty tricky to understand at the beginning. I solved it with a quick and simple workaround that allowed me to solve the challenge without fully understand it. Once I got the flag I understood the whole story. So as with all the stories, we need to begin from the start.
We’re given with a website in where we can buy two products: ‘cheap’ (13.37 USD) and ‘flag’ (31337.42 USD). We, of course, want to buy the ‘cheap’ one because we don’t want to spend our money on some leet flag with the answer to life, the universe and blah blah. So — the ‘cheap’ it is.
In order to buy the product we need to supply a valid credit card number, there are bunch of examples of valid credit cards online.
Lets try one of them and see what we get.
Woo-hoo! We finally bought the ‘cheap’ product and fulfilled our dream.
Kidding. Lets move on and see what will we get when trying to buy the ‘flag’.
“failed”? Oh no. The server says that we exceeded the credit card limit. The first thing to come in my mind was to brute force the server with valid CC numbers, but I figured out very fast that this isn’t the right way to the solution. At this time I noticed something interesting about the URLs of the pages: there’s a GET parameter named ‘data’ that some parts of it are the same on every request. Until now I thought it’s always a new hash. I grabbed pencil and paper and started to figure out the patterns and the mutual parts. Okay, okay, I admit – opened VS Code and made a simple table. The mutual parts highlighted using Photoshop.
As you can see, every hash is combined from 3 parts. The beginning of each type is mutual and so is the end. I thought that certain combination is required to get the flag. But how I mix the parts to the correct hash so as to get the ‘flag’ content. Now it’s about trial and error. Or not.
After two manual tries I gave up because automation is always better and here comes the workaround I mentioned before. I created a list with instance of every colored part and added one example of white part from each page. I then created from this list another list with all possible permutations of 3 parts, i.e all the possible combinatios (990 combinations) and tried all of them using
urllib2.urlopen() ’til I found ’33C3′ in the response.
I know. It isn’t the most efficient way to do this but it was short and quick.
hash_parts = ['28df361f896eb3c3706cda0474915040',
all_permutations = 
for hash in itertools.permutations(hash_parts, 3):
for hash in all_permutations:
if '33C3' in urllib2.urlopen("http://18.104.22.168:5000/payment/callback?data=%s" % hash).read():
# found: 5765679f0870f4309b1a3c83588024d7c146a4104cf9d2c847aae22e7d77d379272d81aff52de2a54f75c9736d3b8e0641e7995bb92506da1ac7f8da5a628e19ae39825a916d8a2f
# found: 5765679f0870f4309b1a3c83588024d7c146a4104cf9d2c847aae22e7d77d379272d81aff52de2a52f7ef761e2bbe791
# found: 5765679f0870f4309b1a3c83588024d7c146a4104cf9d2c86e9cc7ab82a57f004f75c9736d3b8e0641e7995bb92506da1ac7f8da5a628e19ae39825a916d8a2f
It took the script 2 minutes to run and then it came up with 3 possible hashes, lets try one of them to see if we indeed got the flag:
YES! We got the flag! I took a deep breath and analysed the matched hashes to find out what is the right pattern. I came out with two possible patterns:
5765679f0870f4309b1a3c83588024d7c146a4104cf9d2c8 + X + 2f7ef761e2bbe791
5765679f0870f4309b1a3c83588024d7c146a4104cf9d2c8 + X + 4f75c9736d3b8e0641e7995bb92506da1ac7f8da5a628e19ae39825a916d8a2f
Where X is one of the white parts of ‘flag’ product (purchase page/success).
The logic behind is as followed: Seems like the blue part is for ‘success’ and the light-blue part is for ‘failed’. The yellow part is likely for ‘product page’. If you take every hash of ‘flag’ product (product page / purchase failed) and replace its first part (light-blue / yellow) with the blue part (‘success’) you come up with a valid hash that brings the flag.
That’s it. the flag is:
I’ll be happy to read in the comments how the challenge was for you.