Side Quest - Day 4
In this challenge, we need to become root, so let’s start with the enumeration phase.
Enumeration
As we can see, we only have two open ports:
We go see the website and notice that we can download the three images that we see:
If we look carfully at the source code, we can see what looks like an SQLi:
SQLi
We try to reach the image with id=0
and we get this beautiful error from Flask
:
This means that we should have a Werkzeug
console at /console
:
This console is protected with a PIN but there is a technique to recover it. I won’t go into too much detail on how I generated it but you can read my write-up of a previous CTF here to have a better understanding.
So, let’s see if we can leverage our SQLi to get an LFI and be able to read interesting files on the server:
LFI
The payload id=0' union select all concat('file:///etc/passwd')-- -
allows us to download the /etc/passwd
file:
I now used this script to download all the necessary files to recover the pin.
Thanks to this I know that the user is mcskidy
, I have the machine ID, the node UUID
, the mod name
is flask.app
and the app name
is Flask
. The path of the app is given in the error (/home/mcskidy/.local/lib/python3.8/site-packages/flask/app.py
).
We just have to get the hexadecimal value of the node UUID
. Here we have 02:77:eb:08:09:ed
which is 2714067536365
in decimal. I now use my script to generate the PIN:
Note that I put the
cron.service
(available in thecgroup
file). But for some reason, sometimes it worked with it appended to the machine ID and sometimes without. So be aware of that.
RCE
I now head back to the console and get the access:
Now we can have RCE running commands like __import__('os').popen('whoami"').read()
but we can also use it to get a reverse shell:
We now have access to the server and can recover the user.txt
flag in our home directory:
As we know from the previous steps, the app is in our home directory so we can now have full access to the code:
We notice a .git
folder. We can search for previous interesting commits:
Let’s check the difference from the code we have and this one:
As we can see, we have a password that was changed. Let’s try to use it for our user:
Privilege Escalation
So the deleted password was the one for the user mcskidy
. Now we can check the /opt/check.sh
script to try getting a root shell:
As we can see, the /opt/check.sh
uses its own .bashrc
file and start the program from our home directory. As we saw on the sudo -l
command, our home directory is in the secure_path
. This means that when we run the script as the root
user, we will have our home directory in the path. So if we have our reverse shell in our home directory, it will be loaded.
But the source code of the check.sh
script has only absolute path for the different binaries. But if we look at the /opt/.bashrc
file, we can see something that isn’t present in the one of mkscidy
:
Because the #
is a comment in bash, this means that we only have to understand what comes before it. enable -n
means that it will disable the [
command. This [
is present in our check.sh
file. This means that the [
will not be interpreted as part of the if
statement. So we could try to have a reverse shell in a file called [
.
For more information about the
enable -n
you can check out this blog.
So we just have to create our reverse shell into our home directory and we have it ready to go:
And voilà, we have our last flag and the yeti’s key: