HackTheBox Writeup: Obscurity

Obscurity was a medium rated Linux machine that required some fuzzing to find a hidden web directory containing a python file. This file was the source code for the web server and contained a vulnerability allowing RCE which lead to a reverse shell as www-data. We had read and execute permissions on an overconfident user's script that encrypted his password - this was cracked allowing SSH access as Robert. From here, Robert had sudo access to a python script which I found two ways of exploiting to gain root access. I added obscurity.htb to my /etc/hosts file and got started.

Enumeration

nmap scan:

Let's see what's going on with port 8080:

Scrolling through the page reveals some interesting things:

We are very kindly provided with the filename 'SuperSecureServer.py' and know that it's hidden in a secret directory somewhere so let's use wfuzz to find it:

Let's download the file:

Initial Foothold

My python skills aren't that great but I've learned that using 'exec' in a webapp is a no-no and so this part of the code caught my eye:

It seems that whatever you put as the web path gets executed. I tried putting in my usual python reverse shell but it didn't work. After a couple of hours filled with a lot of experimentation and cursing, I figured out that enclosing the reverse shell commands in single quotes as well as a new line did the trick. The request looked like this in Burp before URL encoding:

With a netcat listener, I got a shell as www-data:

User Pivot

While enumerating the system, I found interesting files in Robert's home directory:

Of course I checked 'passwordreminder.txt' first but found it was encrypted:

Check.txt:

Out.txt is encrypted as well:

It's pretty clear that 'SuperSecureCrypt.py' is used to encrypt his password so let's take a look at the encryption/decryption functions:

I'm still on the beginning stages of learning about cryptography but I can see that the encryption technique is quite basic. At this point we have check.txt, out.txt and the decrypt/encrypt function - we just need the key. I thought about this talk I saw at BSides SF and figured swapping things around could possibly output the key. I downloaded the script to my machine to play with and not leave breadcrumbs behind. Let's see what the script expects:

Giving it 'out.txt' as the input and the contents of 'check.txt' as the key should result in the real key being output so I tried that:

It worked:

Now let's get Robert's password:

The password works and we now have SSH access as Robert:

User flag:

Privilege Escalation

Robert has sudo access to run BetterSSH.py:

Route #1 - intended?

Let's see what happens when we try to run BetterSSH.py:

Hmm, let's look at some of the code:

It looks like /etc/shadow is being opened, written to a randomly named file in /tmp/SSH then this file is then deleted. Let's see what happens if we create the /tmp/SSH directory and run the script:

No more errors at least. With the BetterSSH script deleting the randomly named file very quickly, there's a race condition - if we can copy the file somewhere else before it's deleted, we should be able to read the contents of /etc/shadow. I made a new directory and used the watch command to copy anything in /tmp/SSH to /tmp/tmp2/ every 0.1 seconds:

In another SSH session, I ran the BetterSSH script twice to make sure I caught it:

There are now files in /tmp/tmp2:

We now have password hashes:

I saved the root hash to root.hash on my machine and cracked it:

This password works and let me su to root:

Root flag:

Route #2 - unintended?

It turns out that while Robert does not have write permissions on the BetterSSH.py file, he can rename the 'BetterSSH' directory so I renamed it to 'TMP' and created a new 'BetterSSH' directory:

In it, I created my own BetterSSH.py with reverse shell code as below:

I ran it with sudo privileges:

With netcat listening, I caught a root shell: