Bypass TryHackMe Lab
The network security team has implemented an Intrusion Detection System (IDS) using Suricata to protect the company’s CCTV web panel. My objective was to enumerate the target, trigger the required IDS rules, recover the password, and gain access to the CCTV web panel.
Reconnaissance & Enumeration
Before interacting with the target, I started with reconnaissance and enumeration.
- Reconnaissance is the process of gathering information about a target to understand its technologies, services, and potential attack surface.
- Enumeration is the next step, where I actively queried the exposed services to gather more detailed information.
Nmap Enumeration
The first thing I did was run an Nmap scan against every TCP port while enabling the default NSE scripts and version detection.
nmap -sCV -p- 10.113.152.91This scan checked all 65,535 TCP ports, identified which ports were open, detected the running services, and attempted to determine their versions.
root@ip-10-113-106-93:~# nmap -sCV -p- 10.113.152.91
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-07-16 15:45 UTC
Nmap scan report for ip-10-113-152-91.eu-central-1.compute.internal (10.113.152.91)
Host is up (0.00051s latency).
Not shown: 65532 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 56:13:f8:71:67:43:00:84:95:53:ae:80:84:89:1e:e8 (RSA)
| 256 5e:a1:59:3c:af:99:12:e5:f1:ff:dd:da:8c:41:b5:8e (ECDSA)
|_ 256 89:73:42:b9:27:73:dd:23:e1:b7:d5:73:03:61:8e:81 (ED25519)
80/tcp open http Apache httpd 2.4.41
|_http-title: 403 Forbidden
|_http-server-header: Apache/2.4.41 (Ubuntu)
443/tcp open ssl/http Apache httpd 2.4.41
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=cctv.thm/organizationName=cctv.thm/stateOrProvinceName=Tokyo/countryName=AU
| Not valid before: 2023-08-30T10:08:16
|_Not valid after: 2024-08-29T10:08:16
| tls-alpn:
|_ http/1.1
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: 403 Forbidden
Service Info: Host: default; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 124.43 secondsWhat I learned from the scan
- 22 SSH OpenSSH 8.2p1 (Ubuntu)
- 80 HTTP Apache 2.4.41 — Returns 403 Forbidden
- 443 HTTPS Apache 2.4.41 — SSL certificate for cctv.thm
One thing that immediately stood out was that both the HTTP and HTTPS services behaved differently.
- Accessing HTTP (port 80) always returned 403 Forbidden.
- The SSL certificate revealed the hostname cctv.thm, which suggested the web server was configured for virtual hosting.
That told me the application expected requests for cctv.thm, not simply the IP address.
Adding the Hostname
To make my browser and command-line tools send the correct Host header, I added the hostname to /etc/hosts.
echo "10.113.152.91 cctv.thm" | sudo tee -a /etc/hostsAfter doing this, I tested both HTTP and HTTPS.
http://cctv.thmreturned
403 Forbiddenwhile
https://cctv.thmloaded successfully after accepting the self-signed certificate.
I also inspected the HTTP headers.
curl -I https://cctv.thm -kThe response contained a PHPSESSID cookie, which immediately told me the web application was built with PHP.
I also checked for common files such asrobots.txt, but nothing interesting was exposed.
root@ip-10-113-106-93:~# curl -I https://cctv.thm -k
HTTP/1.1 200 OK
Date: Thu, 16 Jul 2026 16:32:19 GMT
Server: Apache/2.4.41 (Ubuntu)
Set-Cookie: PHPSESSID=hdl7mpv550c2h0fvhg82ndnrm3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
root@ip-10-113-106-93:~# curl -I http://cctv.thm
HTTP/1.1 403 Forbidden
Date: Thu, 16 Jul 2026 16:33:17 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=iso-8859-1
root@ip-10-113-106-93:~# curl -I https://cctv.thm/robots.txt -k
HTTP/1.1 404 Not Found
Date: Thu, 16 Jul 2026 16:33:56 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=iso-8859-1Inspecting the Website
After gaining access to the HTTPS site, I inspected the HTML source looking for comments, hidden endpoints, JavaScript files, or developer mistakes.
Although I did not immediately discover anything useful in the source code, I noted the referenced JavaScript files for later investigation.
Directory Enumeration
Next, I performed directory brute-forcing using FFUF.
ffuf -u https://cctv.thm/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
-k -mc 200,204,301,302,307,401,403This revealed a new directory:
/mailI then enumerated that directory as well.
ffuf -u https://cctv.thm/mail/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
-k -mc 200,204,301,302,307,401,403Inside /mail I found a file called dump.txt.
This turned out to be the most important discovery during enumeration because it contained an internal email explaining exactly how password recovery worked.
dump.txt
The email explained that Suricata IDS had been configured to detect five different network events.
Get Gamuchirai’s stories in your inbox
Join Medium for free to get updates from this writer.
Instead of recovering the password directly, I first had to intentionally trigger each IDS rule and then retrieve a flag from:
/fpassword.php?id=<number>Each flag represented part of the Stage I password.
Below is the email:
From: steve@cctv.thm
To: mark@cctv.thm
Subject: Important CredentialsHey Mark,I have completed all the formalities for securing our CCTV web panel (cctv.thm:443). I have installed Suricata to automatically detect any invalid connection and enabled two-layer protection for the web panel. I will SMS you the passwords but incase if you misplace them, there is no possibility for recovery. We can recover the password only if we send some specially crafted packets
- Make a UDP request to the machine with source port number 5000. Once done, you can fetch the flag through /fpassword.php?id=1
- Make a TCP request to fpassword.php?id=2 with user-agent set as "I am Steve Friend". Once done, you can fetch the flag through /fpassword.php?id=2
- Send a ping packet to the machine appearing as Mozilla browser (Hint: packet content with user agent set as Mozilla). Once done, you can fetch the flag through /fpassword.php?id=3
- Attempt to login to the FTP server with content containing the word "user" in it. Once done, you can fetch the flag from /fpassword.php?id=4
- Send TCP request to flagger.cgi endpoint with a host header containing more than 50 characters. Once done, you can fetch the flag from /fpassword.php?id=5After receiving all the flags, you can visit the MACHINE IP that will ask you for the password. The first password will be concatenated values of all five flags you have received above.For the second layer of security, I have enabled a wholly sandboxed login environment with no connection to the database and no possibility of command execution. The username is the computer's hostname, and the password is the same as the previous password. I will SMS you the details as well.
See ya soon
Steve
Dev Ops Engineer
Flag 1 — UDP Packet
The first requirement was to send a UDP packet using source port 5000.
I used Nmap because it allows me to specify the source port easily.
nmap -sU -g 5000 -p 1 10.113.152.91After triggering the IDS rule, I visited
https://cctv.thm/fpassword.php?id=1to retrieve the first flag.
Flag 2 — Custom User-Agent
The second IDS rule required a TCP request using the User-Agent
I am Steve FriendI used curl for this.
curl -k -A "I am Steve Friend" \
https://cctv.thm/fpassword.php?id=2Once the IDS detected the request, visiting the same page returned the second flag.
Flag 3 — ICMP Payload
The email mentioned a ping packet “appearing as Mozilla.”
Since ICMP packets do not contain HTTP User-Agent headers, I interpreted this as requiring the payload itself to contain the string Mozilla.
The payload must be supplied in hexadecimal
4d6f7a696c6c61I sent it using:
ping -p 4d6f7a696c6c61 cctv.thmAfterwards I retrieved the third flag.
Flag 4 — FTP Login
The fourth rule required an FTP login attempt containing the word user.
The important part here was not successfully logging into FTP, but simply triggering the IDS signature.
Once the attempt had been detected, I retrieved the fourth flag.
Flag 5 — Long Host Header
The final IDS rule required sending a request to
/flagger.cgiusing a Host header longer than 50 characters.
For example:
curl -i -s http://cctv.thm/flagger.cgi -H "Host: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"-khttps://cctv.thm/fpassword.php?id=5The HTTP response itself was irrelevant.
The important part was that Suricata detected the request.
Afterwards I successfully retrieved the fifth flag.
Flag value: THM{12319}
Stage I Password
Once I collected all five flags, I concatenated them in numerical order.
THM{10001}
THM{10125}
THM{13231}
THM{33120}
THM{12319}Result:
THM{10001}THM{10125}THM{13231}THM{33120}THM{12319}This became the password for the first authentication stage.
That combined string is the password for the first login layer described in the email. The second layer then uses:
- Username: the machine’s hostname
- Password: the concatenated string from the five retrieved values
Stage II — Getting the Username
The email mentioned that the username was the computer’s hostname. I recommend using Burp and also the Developer’s tool.
After submitting the Stage I password, I inspected the page source and noticed something suspicious.
<select name="commands">
<option value="date">Current Date ip-10-113-152-91</option>
</select>The application allowed selecting commands from a dropdown menu.
This immediately suggested that the value of each <option> was being passed to the server.
Using the browser’s Developer Tools, I duplicated the existing <option> element and changed its value.
For example:
<option value="hostname">Get Hostname</option>When I selected the new option, the server executed the command and returned the hostname.
I repeated the same process to answer the remaining question.
<option value="lsb_release -r -s">Get Release Number</option>This returned the Linux release version required by the room.
Final Flag
After logging into the CCTV web panel using:
- Username: Machine hostname
- Password: Concatenated Stage I password
I gained access to the CCTV dashboard and retrieved the final flag.
Overall, this room was a good demonstration of combining reconnaissance, web enumeration, directory fuzzing, HTTP analysis, and understanding how an IDS such as Suricata can detect specific network traffic. The final stage also highlighted why applications should never trust client-side input, since modifying HTML elements in the browser allowed additional commands to be sent to the server.








