TryHackMe Dreaming Walkthrough: Initial Enumeration

I started with an Nmap scan to determine which services were exposed by the target.
nmap -sC -sV -p- <TARGET_IP>
The attack surface was fairly small, with the important services being SSH and HTTP.
22/tcp SSH
80/tcp HTTP
Browsing directly to the web server did not reveal much initially, so the next step was directory enumeration.
gobuster dir -u http://<TARGET_IP>/ -w /usr/share/wordlists/dirb/common.txt
Enumeration revealed an interesting directory:
/app/
Exploring the application eventually revealed an installation of Pluck CMS 4.7.13.
Finding an exact product and version number is always worth investigating because it gives us something specific to research rather than blindly testing the server.
Finding the Pluck CMS Vulnerability
Researching Pluck CMS 4.7.13 revealed a known authenticated file-upload vulnerability that can lead to remote code execution.
Searchsploit can also be used to look for available information:
searchsploit pluck 4.7.13
The vulnerability affecting this version of Pluck CMS is associated with CVE-2020-29607.
The important lesson here is not simply finding an exploit. Enumeration gave us the exact CMS and version, which allowed us to narrow the attack considerably.
After gaining access to the Pluck administration functionality, the vulnerable upload mechanism provides a way to execute PHP on the server and establish the initial foothold.
At this point, the challenge moves away from web exploitation and becomes a Linux privilege-escalation exercise.
python3 exploit.py <server_ip> <server_port> <pass> <cms_path>
Enumerating the Linux Host
After gaining access to the machine, I started enumeration again.
Some basic commands are useful for establishing where we are and what privileges we currently have.
whoami
id
pwd
ls -la
I also started looking through directories containing custom applications, scripts, and configuration files.
One particularly interesting location was:
/opt
Inside were Python scripts that deserved further investigation.
Among the interesting files were:
getDreams.py
test.py
Examining the scripts revealed information that should not have been exposed to the web-server account.
The test.py script contained authentication information associated with the Pluck application.
This is an important lesson from Dreaming: credentials do not always live in traditional configuration files.
Developers sometimes leave passwords, API keys, database credentials, and test accounts directly inside scripts.
The information discovered here provided the next step in the room and allowed movement from the web-server context to the Linux user lucien.
Enumerating the Lucien Account
After gaining access as Lucien, I started enumeration again.
One of the first things worth checking when compromising a user account is shell history.
cat ~/.bash_history
Shell history can contain a surprising amount of useful information.
Users occasionally enter passwords directly into commands, connect to databases from the terminal, or leave behind commands that reveal how applications are configured.
In this case, Lucien’s history provided information for accessing MySQL.
Now the database became another part of the attack surface.
Enumerating MySQL
Using the discovered credentials, I connected to MySQL.
mysql -u lucien -p
Once connected, I enumerated the available databases.
SHOW DATABASES;
One database stood out:
library
I selected it:
USE library;
Then enumerated the available tables:
SHOW TABLES;
The important table was:
dreams
The contents could then be examined with:
SELECT dreamer, dream FROM dreams;
The table contains columns named:
dreamer
dream
Each row simply contains data associated with a dreamer and their dream.
Conceptually, the results look something like:
Alice Flying through the sky
Bob Exploring ancient ruins
There is nothing executable about those database rows by themselves.
The interesting part is what another application does with that data.
Understanding getDreams.py
The next important file was getDreams.py.
The script retrieves the dreamer and dream values from the MySQL database and processes them.
Conceptually, the database operation resembles:
SELECT dreamer, dream FROM dreams;
The problem appears when information retrieved from the database is eventually incorporated into an operating-system command.
That creates a dangerous trust relationship:
MySQL Database
|
v
getDreams.py
|
v
Shell Command
|
v
Operating System
The database itself is not executing commands.
Instead, getDreams.py trusts information retrieved from the database and later allows that information to influence something executed by the operating system.
If an attacker can modify the database contents, that becomes significantly more interesting.
Manipulating the Dreams Table
Lucien has the ability to modify information inside the dreams table.
A new database entry can be created using the normal SQL structure:
INSERT INTO dreams (dreamer, dream)
VALUES ('test', '<CONTROLLED_DATA>');
By itself, inserting information into a database is not a privilege-escalation vulnerability.
The problem is that getDreams.py later retrieves that controlled information and uses it unsafely.
The next question is therefore:
Who can execute getDreams.py?
Checking Lucien’s sudo permissions provides the answer.
sudo -l
Lucien is permitted to execute the getDreams.py script as another user: death.
Now the vulnerability becomes much more serious.
The attack path looks like this:
Lucien
|
v
Controls MySQL Data
|
v
getDreams.py Reads the Data
|
v
Data Reaches a Shell Command
|
v
Script Executes as Death
The permitted script can be executed in the Death user’s context with:
sudo -u death /usr/bin/python3 /home/death/getDreams.py
Because controlled database information eventually reaches the shell, the combination of database access and sudo permissions creates the next privilege-escalation opportunity.
This allows us to move from lucien to death.
Enumerating the Death Account
Once again, gaining access to another account means starting enumeration over.
Different users may have access to completely different files, scripts, directories, credentials, and services.
From the Death account, another Python script becomes particularly interesting.
The next target involves the morpheus account and a script named:
restore.py
Looking through the script shows that it imports Python’s shutil module.
For example:
import shutil
Importing shutil is completely normal.
The vulnerability is not the import itself.
The problem is the permissions assigned to the Python library being imported.
Python Library Hijacking
Python searches for modules when an import statement is encountered.
If a more privileged script imports a Python module that a lower-privileged user can modify, that user may be able to influence what code gets executed.
In Dreaming, the Death user has the ability to modify the Python library used by the more privileged restore.py process.
The relationship looks like this:
restore.py
|
v
import shutil
|
v
Writable Python Library
|
v
Code Executes in the Context of restore.py
This creates a classic Python library hijacking opportunity.
The important security issue is the file permission.
A privileged process should never import executable Python code that can be modified by a less-privileged account.
Once the writable library is identified and the execution behavior of restore.py is understood, the imported module can be used to influence execution in the Morpheus context.
That provides the final privilege transition required for the room.
The Complete Dreaming Attack Path
One of the things I liked about this room is that no single vulnerability provides the entire compromise.
Instead, Dreaming is built around chaining several weaknesses together.
The overall attack path looks like this:
Web Enumeration
|
v
Pluck CMS 4.7.13
|
v
File Upload / Code Execution
|
v
Web Server Access
|
v
Exposed Credentials
|
v
Lucien
|
v
MySQL Credentials
|
v
Writable Dreams Data
|
v
getDreams.py Command Injection
|
v
Sudo Permission
|
v
Death
|
v
Writable Python Library
|
v
Python Library Hijacking
|
v
Morpheus
This is what makes the TryHackMe Dreaming Walkthrough particularly useful for learning privilege escalation.
Each mistake creates just enough access to discover the next one.
What Dreaming Teaches
The biggest lesson from Dreaming is simple:
Enumeration starts over every time your privileges change.
Getting the first shell does not mean enumeration is finished.
Changing from the web-server account to Lucien does not mean enumeration is finished.
Changing from Lucien to Death does not mean enumeration is finished either.
Every new account may expose:
- Different files
- Different credentials
- Different sudo permissions
- Different scripts
- Different database access
- Different writable directories
- Different scheduled processes
- Different trust relationships
Dreaming rewards repeatedly asking the same question:
What can this user access that the previous user could not?
That mindset is much more useful than immediately searching for a privilege-escalation exploit.
Defensive Takeaways
Dreaming also contains several good defensive lessons.
Keep Web Applications Updated
The initial access begins with an outdated version of Pluck CMS.
Known vulnerable software should be patched or upgraded, especially when it is directly exposed through a web server.
Don’t Store Credentials in Scripts
Passwords and database credentials should not be embedded directly inside Python scripts.
Secrets should be stored using an appropriate credential-management system and protected with restrictive permissions.
Watch Shell History
Credentials entered directly on the command line may remain inside shell history.
Administrators and developers should avoid placing passwords directly into commands whenever possible.
Treat Database Content as Untrusted Input
Information coming from a database should not automatically be considered safe.
If users can modify database records, that data is still attacker-controlled input.
Passing database information into shell commands without proper validation can therefore create command-injection vulnerabilities.
Review Sudo Permissions
Sudo rules should follow the principle of least privilege.
Allowing one user to execute a custom script as another user can create an unexpected escalation path if that script processes attacker-controlled information.
Protect Python Libraries
Privileged Python scripts should never import modules that less-privileged users can modify.
Writable libraries can turn an otherwise harmless import statement into a privilege-escalation vulnerability.
Final Thoughts
The TryHackMe Dreaming Walkthrough demonstrates how several relatively small security mistakes can be chained into a complete compromise.
Pluck CMS provides the initial foothold, but the more interesting parts of the room happen afterward.
Exposed credentials lead to Lucien. MySQL provides attacker-controlled data. getDreams.py introduces command injection. Sudo provides the transition to Death, and insecure Python library permissions create the final path to Morpheus.
More importantly, Dreaming reinforces one of the most valuable habits in penetration testing:
Enumerate. Gain access. Enumerate again.
Understanding why each privilege transition works is far more useful than simply copying the commands required to complete the room.
No flags have been included in this walkthrough.
If you enjoyed this room, check out my other TryHackMe walkthroughs on RootNotebook for more web exploitation, Linux privilege escalation, and enumeration challenges.
You can also visit the official TryHackMe Dreaming room to work through the challenge yourself.
For additional information about the web vulnerability used during the initial foothold, the National Vulnerability Database entry for CVE-2020-29607 provides additional technical details.
