It is not that type of RAT!!
When reading the room description, you may conclude/assume you are looking for a Remote Access Trojan (RAT), but in actuality, it is a Remote Administration Tool (RAT). As a result, I more or less stumbled around this room for roughly 8 hours spread across 3 days (so you will notice that the IP address changes).
The room description does provide hints somewhat cryptically, but it is possible to get initial access without too much fuss. After that, you will need to spend a lot of time reviewing the various directories for hints and credentials.
You can access the free CMesS box from TryHackMe’s platform: https[:]//tryhackme.com/r/room/pyrat.
The box has only two open ports, SSH (port 22) and HTTP (port 8000), but neither will provide you with any helpful information or an initial access point.
Gaining initial access will require using Netcat, but the first low-level user you compromise will not grant you access to the first flag. However, using this account, you can find credentials for another user - ‘think’ (quite fitting), which will allow you to elevate your privileges to root.
Required Tools:
Penetration Testing OS - Kali or Parrot OS (or whichever security-focused OS you prefer)
LinPEAS.sh (optional): https[:]//github.com/peass-ng/PEASS-ng/tree/master/linPEAS
Netcat (quick guide on Hacking with Netcat - https[:]//www.hackingtutorials.org/networking/hacking-with-netcat-part-1-the-basics/)
ChatGPT (if you can automate a dictionary attack using Bash or Python scripting, even better).
As always, I start with a ‘quick and dirty’ Nmap scan of the target to discover open ports and potential vulnerable services.
Port 8000 running a SimpleHTTP/0.6 Python web server is a dead end; when you access the IP address and port, you get a hint - “Try a more basic connection!“
If you are doing this same box, follow the advice provided by the hint - fuzzing with the usual tools, dirbuster, gobuster, or FFUF, will not generate any valuable leads.
Nothing is more basic than Netcat—the ‘Swiss army knife of network tools.’ When I fire up Netcat, I am brought to a blank terminal with the keyword ‘open’. After manually guessing commands, I am able to get a ‘shell’ on the target machine.
Unfortunately, I could not make much headway using manual enumeration, so I decided it was time to execute LinPeas.sh. After researching and testing the potential vulnerabilities found, none of the usual suspects would grant access to the root account or first flag. The only two things of interest were another user account - ‘think’ of which the www-data account did not have read permissions and the possibility of an email with another clue in the /var/mail directory for the same user.
Upon accessing the mail, I found another hint - the administrator (root) downloaded a RAT tool from a GitHub page. So now we are possibly looking for Python scripts or a GitHub repo/directory.
After adjusting my search parameters, I found a hidden .git directory under the /opt/dev directory.
After reviewing the most common files in the git repo, I found credentials for the user ‘think‘ and immediately tried to access the machine using SSH.
Using the credentials found in the config file, I can log in via SSH `think@target_ip` and access the first flag under the /home/think/ directory.
We now have access to the machine with slightly higher permissions, and we rinse and repeat. Manual enumeration followed by LinPEAS enumeration; nothing stands out, and I revisit the git repo for additional clues. Brushing up on my Git commands, I decided to check the status of the local repo (Check out this page for a quick refresher on Git commands). Sure enough, there is an old version of the Pyrat file.
The code hints at a few conditional statements that execute depending on the command ‘data’ provided. This makes me wonder what would happen if I submitted ‘admin’ to the Netcat connection earlier. In addition, when I first got shell access to the machine, I ended up in the root home directory - /root, there is a good chance the updated Pyrat script will be running in this directory and provide privilege escalation.
We now have the following bits of information:
We can connect to an admin/root account using a basic Netcat/network socket connection.
We know the username - admin, and
The room description hints at fuzzing passwords (see below).
Exploring possible endpoints using a custom script, the user can discover a special endpoint and ingeniously expand their exploration by fuzzing passwords.
It’s now day three, and I've tried reviewing my Python network code snippets to create a quick script to fuzz the passwords. But to skip the long process of coding and testing a custom script, I tried using ChatGPT to generate the script with the following prompt based on the manual enumeration I performed earlier (see prior screenshot). Here is the initial prompt used:
Generate a Python script for a Try Hack Me target dictionary attack. The script will accept an argument pointing to a password file. It will loop through each password in the file and attempt to connect to the target using a network socket with a predefined IP address, port, and username. After establishing a connection with a network socket, the script will wait for the keyword 'open', submit the username 'admin,' wait for the 'Password' prompt, and submit a password. If the 'Password' prompt re-appears, the password fails, and the loop should exit and move on to the next password in the list. If the no 'Password' prompt appears, the password succeeded, and the script should print the password that worked.
Unfortunately, the generated script failed because it continuously waited for the prompt ‘open.’ Updating the script code with the following prompt generated a script that solved the problem.
Update the script. It should no longer wait for the 'open' prompt and should immediately send the 'admin' username.
The Python script is further below. Copy the code to a file, e.g., pyrat_fuzzer.py, change the execute permissions (chmod +x pyrat_fuzzer.py), and execute it on your attacker machine (python3 pyrat_fuzzer.py).
If you use the rockyou.txt password file, the script will quickly work on fuzzing the password and allow you to get access to the root account.
The mitigation measures for this machine are straightforward:
DO NOT leave an open port (and script) that can allow an unauthenticated user to gain shell access on a web server.
DO NOT store plaintext credential files in GitHub repos (both local or remote).
DO NOT use simple passwords for administrator accounts.
This box is rated easy, and I can understand why, even though it can be frustrating. The general rule of thumb is to be patient, enumerate, enumerate, enumerate, and go back to the description, hints, and possibly the location of your last clue.
The box presented an interesting escalation path: You need to move between two users and finally code a script to gain root access to the system.
Cover image: Generated with Canva AI
import sys
import socket
import time
def try_connect(ip, port, username, password):
try:
# Create a socket connection to the target
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((ip, port))
# Immediately send the username
print(f"Connection established. Sending username: {username}")
s.sendall(f"{username}\n".encode())
# Wait for the password prompt
response = s.recv(1024).decode()
if 'Password' in response:
# Send the password
print(f"Sending password: {password.strip()}")
s.sendall(f"{password}\n".encode())
# Wait for the next response
response = s.recv(1024).decode()
# Check if the password prompt reappears
if 'Password' in response:
print(f"Password {password.strip()} failed.")
return False
else:
print(f"Password {password.strip()} succeeded!")
return True
return False
except Exception as e:
print(f"Connection failed: {e}")
return False
def main():
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <password_file>")
sys.exit(1)
ip = 'TARGET_IP' # Replace with target IP
port = 1234 # Replace with target port
username = 'admin' # Replace with target username
password_file = sys.argv[1]
with open(password_file, 'r') as file:
for password in file:
success = try_connect(ip, port, username, password)
if success:
print(f"Successful password: {password.strip()}")
break
if __name__ == "__main__":
main()