HackTheBox: Precious

·

5 min read

HackTheBox: Precious

Introduction

Precious is rated as an easy-difficulty Linux box on HackTheBox. There were a couple of small rabbit holes on this box, but the key to success with this machine is all about enumeration.

Enumeration

We run a full port scan but even after that, all we get back are 80 and 22

Our initial attempts to access the webserver on port 80 try redirecting us to precious.htb

  • Time to add to our /etc/hosts file.

The webserver takes a few minutes to load but when it does we see an interesting response header.

Unfortunately, we don't find any exploits for this version.

  • However, after playing around a bit more, we notice some interesting output to the console when a pdf is generated.

Looks like Pdfkit has a command injection vulnerability in this version. The vulnerability is tracked as CVE-2022-25765. You can find additional coverage of the underlying cause of the issue at the nist.gov website below.

Initial Foothold

What we're most excited about as pentesters looking at this application, are the exploits publicly available for 'pdfkit v0.8.6'

Worth noting that we were proxying through Burp to inspect the request, but the exploit just wasn't landing properly this way.

However, when we changed the host header to the hostname precious.htb it worked on the first try.

We catch a reverse shell, get onto the box using this Pdfkit exploit and find ourselves as the user 'ruby'

Lateral Movement

Recalling that it was using the Phusion Passenger framework, this directory and its contents seemed pretty interesting: /tmp/passenger.BccUeh2$ . Maybe we can find a config file with a hardcoded password or something else that'll help us move laterally from this service account.

The only thing we can read here is properties.json. This tells us a bit about the server (Nginx) and the server framework (Phusion Passenger), but nothing that advances our goals.

We had seen a service on 34101 that was only exposed to the localhost.

  • We forward it with Chisel but still can't seem to hit it from our atk machine.

    • Tried with netcat, browser, nmap, nothing is getting through correctly..
  • While trying to figure out what the process on port 34101 was, we were trying the usual ss -ano and ss -antp but they weren't able to give us a good reading on what the actual program was.

    • Using netstat -lpno we're able to see:

      • -l 'display listening server sockets'

      • -p 'display PID/Program name for sockets'

      • -n 'don't resolve names'

      • -o 'display timers'

  • Before digging too much deeper into this, we should see if it's even being run by another user or if we're just killing ourselves to get a shell as 'ruby' again..

    • Now that we have the PID of the service on port 34101 we can check who's running it with:

      • ps -lp 766

      • ps -list -pid <PID_NUM>

  • The command output shows Phusion is being run by UID 1001, which is the 'ruby' user. So we likely won't find our next move through the Phusion server.

After running automated tools, performing manual enumeration, and searching online for ANY local privilege escalation vector that might be related to Ruby, we eventually take a break and step away for a little while. This was key because we came back with a fresh mind and restarted with some privilege escalation basics.

This roadblock was an excellent lesson to never neglect the enumeration of ANY home directories you have access to.

  • Even though this is a service account, the idea seems like it would be a service account set up by a human. This human has creds to the Ruby Gems online repo which they are sharing with this service account.

  • Turns out Henry reused this password and we can now SSH in as him.

Privilege Escalation to Root

We do some of the normal enumeration first steps here but we also check for sudo -l now that we have a valid username/password.

Looks like we can run the ruby interpreter against this /opt/update_dependencies.rb file.

  • Inside the actual file, we can see it's calling YAML.load() on a file with a non-absolute path.

  • This means that wherever we invoke this script, it will look for the "dependencies.yml" file in the PWD.

YAML.load() is a method that can potentially be vulnerable to RCE via deserialization.

At this point, we can pass an arbitrary file to YAML.load(). We have a couple of payloads to try out(first one doesn't work because of the Ruby version).

  • At first, we just try running the id command to see if we can get code execution as root.

  • As explained in the elttam article linked above, the deserialization gadget chain is going to eventually error out, but it will still execute our commands first.

  • Here we can see it executing with sudo and running the 'id' command.

  • In order to turn this into a reverse shell; we upload an MSFVenom reverse shell to the victim box, then change our payload to invoke that instead of the id command.

  • After the reverse shell lands, we collect our loot and start our writeup.