Developer is a hard rated machine on HackTheBox created by TheCyberGeek. For the user part we will exploit a XSS vulnerability in a writeup submission form on a CTF platform. The application is vulnerable to tabnabbing which let’s us phish the admin’s password and discover another vhost in the django administration interface. Debugging is enabled in the sentry application on this vhost. Triggering a server error we are able to retrieve the secret to sign our own cookie leading to RCE and a reverse shell as it gets deserialized. We find some database credentials and crack a hash giving us access as the user karl. Karl may run a custom authenticator binary as root. Reversing it we are able to retrieve the password it needs and write our public ssh key to root’s authorized keys.
User
Nmap
As usual we start our enumeration off with a nmap scan against all ports, followed by a script and version detection scan against the open ones to get an initial overview of the attack surface.
All ports
1 |
|
Script and version
1 |
|
XSS => CSRF
There are only two ports open on the machine with http being a bigger attack surface so we will start there. The nmap scan already revealed the name of a vhost so we add it to our /etc/hosts
and open it in our browser. At a first glance it looks like a CTF platform.
Running a quick gobuster scan on the website it looks like everything containing the string admin
get’s redirected.
1 |
|
Clicking on the menu we can sign up, which we do since it might unlock additional functionality.
Being logged in there are three different machine categories and five challenge categories.
The machine categories lead nowhere but there are some challenges for everything but Web
.
Phished List
Downloading a forensics challenge we can take a quick look for the flag to check for more potentially vulnerable functioniality after submitting it. The zip file contains a xlsx which is just a zip itself so we open it aswell.
1 |
|
1 |
|
Checking for low hanging fruits we get the flag with a quick grep
command for a common flag scheme.
1 |
|
After submitting the flag we are now able to also submit a writeup for the challenge and are prompted with the url. We enter our own ip and stand up a ncat
listener to see if there is something checking the writeup.
Going to our profile we see that we now have a walkthrough submited. Checking the source of the page for the link we see that clicking on it opens a new tab with target="_blank"
. This makes it susceptible to tabnabbing since we can change the parent page of the tab.
After about a minute we get a hit on our listener with the user agent of firefox, which means it is probably checked using a browser.
1 |
|
To abuse the tabnabbing we have to put a javascript payload as writeup url which modifies the parent tab.
1 |
|
1 |
|
Now we need to figure out what we want to display back on the initial tab. The most promising for this would be the login page because the user might think he got logged out and just log in again to a fake page hosted by us. This way we might be able to steal his credentials and log in as him.
For this we download the login page and replace the relative resource links with absolute ones to not break any functionality.
1 |
|
index.html
1 |
|
Next we host the page with a python web server and also stand up a ncat
listener to retrieve the request made by the user.
1 |
|
1 |
|
Now we can send our javascript payload as walkthrough submission.
After about a minute later we get a hit on our python webserver followed by a hit on our ncat
listener with the credentials for the admin user admin:SuperSecurePassword@HTB2021
1 |
|
1 |
|
We can now sign in as admin and browse to the django administration.
Going over to sites there is an additional vhost which we also add to our /etc/hosts
.
Sentry cookie deserialization
Browsing to it reveals a sentry installation which also let’s us register a new user.
Creating a new user and logging in we have very low privileges. We can however list all members with their email addresses.
There is a user named jacob which is also the name of the admin on the django administration page.
Testing his email with the earlier found password we are able to log into sentry with the credentials: jacob@developer.htb:SuperSecurePassword@HTB2021
.
Looking around we are now able to create projects. Playing around with the functionality, it results in a server error trying to delete it and a stack trace because debugging mode is enabled in django.
This stacktrace contains alot of information which might be of use to us. Since it is a django application we should be able to obtain RCE if we can sign our own cookie containing a serialized pickle payload. We aren’t able to retrieve the django secret for this but this blogpost describing a very similar vulnerability in a sentry application outlines another possible way. Sentry also has a system.secret-key
which basically overrides the django secret-key. Looking through the stacktrace this key is indeed present along other information about the sentry installation.
1 |
|
For the script to work we just have to replace the cookie and secret with our own sentrysid
and system.secret-key
respectivly. For the payload we use a simple bash reverse shell in the reduce function which later gets deserialized and executed in the process.
1 |
|
We can now generate our own cookie and stand up a ncat
listener on the port we specified.
1 |
|
1 |
|
After exchanging our previous sentrysid
with the new cookie and refreshing the page we get a shell back, which we upgrade with python and fix the terminal size.
1 |
|
Looking around on the file system the database credentials for the sentry application are in /etc/sentry/sentry.conf.py
.
1 |
|
With this credentials we can now connect to the database with psql
and list all the tables.
1 |
|
1 |
|
1 |
|
The auth_user
table contains all the password hashes for the users, which we can retrieve with the next query.
1 |
|
1 |
|
Since karl is the admin and also a user on the machine we try to crack his password hash with hashcat first and are successful.
1 |
|
Now we can log in as karl and add the user flag to our collection.
1 |
|
Root
Rust reversing
Looking at sudo permissions karl is able to run the custom /root/.auth/authenticator
binary as the root user.
1 |
|
1 |
|
Testing it, it asks for a password and exits if the wrong one is entered.
1 |
|
To take a close look at it we copy it over to our machine and open it in ida free.
1 |
|
Looking at the decompiled output of the main function (F5) we see it calls another function.
Taking a look at this one we see it calls the crypto::aes::ctr
module with two arguments. According to the documentation the first argument here is the key and the second one the IV. These two values are defined above in the function and we can go to the definition by clicking on them.
Further down there is one main if statement which seems to compare the aes encrypted input with the expected encrypted password. We can also find the encrypted string defined above again composed of two variables.
With all the values needed we just need to enter them into cyberchef, swapping the endianness for all of them and switching the mode to CTR to decrypt the password.
1 |
|
Running the binary again it seems our password is correct and it prompts us for our ssh key.
1 |
|
We generate a new one, paste the public key and get told we are now able to authenticate as root.
1 |
|
1 |
|
1 |
|
Using the generate private key we are now indeed able to log in as the root user and grab the flag.
1 |
|