Dreaming
Solve the riddle that dreams have woven. - by tokyo and b1d0ws
Last updated
Solve the riddle that dreams have woven. - by tokyo and b1d0ws
Last updated
The following post by 0xb0b is licensed under
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.
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.
We directly hit up Gobuster to enumerate the directories on the web server. There is just one thing we have. The directory app
.
By visiting the root of the page, we are greeted with the Apache2 default web page.
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.
There, we are able to include files via the parameter file.
We checked for LFI, but it was detected as such an approach and mitigated.
Using FuFF to fuzz for some possbile file inclusion payloads does not lead to a desired result.
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.
We dive deeper into the directories...
... and are able to spot some interesting .php
pages in the settings directory.
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.
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.
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
:
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.
Since we brute-force a password-only login form the following resource can be helpful:
After running the command, we only get hits. Everything seems a valid password. Dang.
We looked up the official GitHub repo. Maybe we are able to spot default credentials, but we did not find anything of interest
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.
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:
After executing the exploit, the shell is available at http://dreaming.thm:80/app/pluck-4.7.13/files/shell.phar
We are www-data
, but we cannot yet spot any flags.
For more control, a reverse shell is used. We make use of the nc mkfifo
reverse shell from revshells.com
.
We catch the reverse shell. After upgrading it, we move on.
For a quick enumeration LinPEAS is used.
We spot four users, of whom three are related to the flags.
There is a local MySQL instance running.
An we are able to spot some interesting files in root and /opt.
While enumerating the web folder, pass.php
stands out. It contains a password hash.
With the use of hashid to analyze the found hash, the possibility of it being an SHA-512 hash is there.
Looking for the correct mode. Mode 1700
is the choice to crack SHA-512 using hashcat.
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.
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.
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.
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.
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.
Since we have the credentials of user lucien
we will access the machine now via SSH to have an even more stable shell.
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.
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.
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.
Just for confirmation, we run the script in the home directory of death
. And it seems like it behaves like the version in /opt
.
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.
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.
We use the database library and inspect the tables. Only dreams are present, like the one in the script
And the input is the same as the output of the script. We are moving in the right direction.
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.
INSERT INTO dreams (dreamer, dream) VALUES ('0xb0b','$(cp /bin/bash /tmp/bash; chmod +xs /tmp/bash)');
The table should look like this now.
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
.
Next, we head to the home directory of the user and find his flag there.
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
.
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.
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.
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.
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
.
Recalling our enumeration for compromising the user death
:
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.
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.
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.
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.
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):
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.
From our LinPeas enumeration, we see that we are part of the lxd group.
Also, we see some processes run by lxd.
For our exploit to work, we have to build a lxd image first. The LXD Alpine Linux Image Builder can be found here:
git clone https://github.com/saghul/lxd-alpine-builder.git
After building the image, we should get a TAR file containing it.
We use our Python web server to retrieve the archive.
We import the Alpine image using lxc image import FILENAME.tar.gz --alias alpine
Afterwards, we confirm with lxc image list
that it has been successfully imported.
Before we move on, lxd has to be initialized, using the default values is completely sufficient.
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.
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.
Now with that misconfigured container, we can drop into a root shell. From there, we can break out.
We are root in the container and are able to navigate to the mount point /mnt/root
, our target.
We are able to interact with the file system and access the /etc/shadow
file.
We generate a simple password, for a new root user called r00t
, which will be added to the /etc/passwd
file.
Append the entry to the /etc/passwd
file.
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.