Road to OSCP: HTB Series: DEVOOPS Writeup

Louis Low
8 min readOct 26, 2020

In my road to OSCP certification, one of the common to-dos as many before have done in preparation for the exams was to take on the retired machines available in Hack in The Box (HTB) platform. This platform is a great platform for practicing and learning new penetration testing skills as well as taking on the challenge of “capturing the flag” on their machines.

In this HTB series, I will be sharing my write-ups on all the retired machines that I have and will attempt. If you are wondering, “How does he know which machine to do to prepare for OSCP?” Well, I am using TjNull list of OSCP-like boxes in HTB which can be found here

DevOops is one of the boxes that I had to research and learn more than what was taught. It really challenged me to try a little harder as it uses XEE injection as the injection technique to gain initial foothold, something I have never tried nor learnt. Privilege escalation will require us to enumerate manually and we will find that it is a human error on Git that gives us access as root.

Recon Phase

To begin with this box, we first carry out our basic Reconnaissance. For me, I used AutoRecon which is developed and scripted by Tib3rius. It is one of my fundamental scans I make before moving on to more manual enumeration for specific ports or applications. From the initial Nmap scan results done by AutoRecon:

Port 5000 is open and the service that is on it is Gunicorn 19.7.1. Gunicorn, or “Green Unicorn” is a Python Web Server Gateway Interface HTTP Server.

Information Gathering

Since the only Port that is available is port 5000, let’s try to browse the Web server at port 5000 on our browser:

Seems like just a site under construction. Let’s take a look at our other scan results from our AutoRecon Scanners. Our Gobuster scan results give us some interesting URL paths we can

There is a /feed and /upload path. Browsing to the /upload :

Here, the web page seems to allow us to upload a file and that this is a testing site. We see that it highlights XML elements and this might be a good indication that it is looking for a XML file upload. Let’s try testing the upload functionality on this webpage. First, we craft a XML file on our attacking machine:

After uploading the file and browsing to /uploads/help.xml :

Now that we know the upload functionality works! Now we need to do a bit of GoogleFU and we find that it may be possible to exploit Upload functionality of this website through a XXE (XML External Entity) Injection.

After reading the resource, TLDR: It is a vulnerability that allows attacker to interfere with an application’s process of XML data.

Going to this repository which has many different payloads, we grab one of the payload and edit our help.xml to try it:

After uploading help.xml , we browse to it again:

We see that we are able to read the /etc/passwdfile!

Exploitation

Using burp suite repeater, we can abuse this to see feed.py :

We find several useful information. We see that there is actually another url file path that we can browse to, which uses a POST method to request for the page. We also see that when we visit /newpost , the behind-the-scene function newpost() is called. What it does is:

  • It requests for data and then decodes it.
  • Then loads this decoded string using pickle
  • Which pickle then serialises objects to be saved as file and then loaded as program later on

But first, let’s try to visit /newpost :

However, we get an error with a message that the method we use is not allowed for the requested URL. In this case, this might be because we are using a GET request for this page which only allows POST request. Using Burp, we can modify the Request Method from GET to POST:

We get an Internal Server Error. However, this does not mean nothing happens on the server side. What newpost() seems to be doing is that it run the upload portion of our XML file and create a new post!

So now we will use urlsafe_base64encode because urlsafe basically remove all + and the character set and replaces it with a dash. Since we are unsure if urlsafe_base64decode will actually decode this properly if we use the normal base64 encode:

Here we encode the command that will give us reverse shell when executed. RUNME is the payload and the reduce(self) function will ensure that when we do a pickle.load() , it will call itself to clean up everything that is unserializable and calls this function to prevent the error.

After running this python script that encodes our RUNME, we then take that and paste it into our burp repeater:

Adding the Content-Type:text, then sending the request. Though it gives an Internal Server Error, if we have a listener set up, we will notice that we have obtained shell on the listener:

Then upgrading our shell:

Privilege Escalation

Information Gathering

When we first enumerate the home directory of roosa , we notice that there is a .ssh folder in the home directory of roosa and that inside this folder, it contains a SSH private key which we can use to login as roosa via SSH service

We can then use this key to SSH in as roosa , gaining a much more stable foothold. The reason we want to do establish a more stable foothold is that sometimes, when a vulnerability is exploited to gain shell, it cannot be repeated for varying reasons such as when the application crashes and hence making the vulnerability unavailable.

We then poke around and look for folders and files within the home directory of roosa . When we look into the deploy folder in roosa home directory and upon closer inspection:

We would notice a .git file, indicating that this folder is actually part of a local repository. When we have access to git folder, it is always a good practice to manually check the git logs for more information on the source code files that are in this situation.

Checking the git log, we see that the user ha accidentally committed with a proper key. Let’s have a look at that:

We notice that the RSA key that was committed in this folder was changed. As it is a revert, this deleted content might be a legitimate key to SSH in with for another user.

Taking that deleted content:

Then using this key to login as other users and we will see that this unknown key actually belongs to root!

We are in as root! Grabbing and taking root.txt as our flag:

Learning Points

From this particular machine, I learn to try much harder. I had great difficulty trying to understand how XEE Injection worked and I was not really strong in web vulnerabilities. However, as I kept trying, I found the chink in the armour and eventually gain a foothold. This vulnerability also highlights the need to protect web applications upload features because it gives the attacker an opportunity to inject or upload malicious file that will give shell. The privilege escalation path I took highlight how users in system are also a possible weak link in the system. Because of an accidental commit with the root SSH key (human error), and not removing that particular commit from the git log completely, it help give the opportunity to obtain the root private key which allowed me to SSH in as root.

Thank you for reading! And like always if you enjoy this write-ups, subscribe to my publications or follow me on twitter @lojomojo96 and hit me up with a DM! It will really encourage me to write and share even as I prepare for my OSCP Certification. Of course, if there are points to improve upon my own methodology, do let me know too!

--

--

Louis Low

Security Engineer by Day | Security Researcher by Night | Bug Bounty Hunting