027#: HTB - Precious

There is a heatwave outside, as if I needed another excuse to stay in and hack. This room had me a bit stumped at first. I had glossed over the privilege escalation path, tried a bunch of stuff, and eventually got back on track after a little struggling. Overall a fun room though. Let’s get this started with an nmap scan.

So far, it is pretty straightforward. I got a gobuster scan running while I began pulling up their site in my browser.


Gobuster kept failing and the site doesn’t want to load. I did notice it is trying to resolve the IP to precious.htb, so I added that to my hosts file.

After making that change, the site successfully loads. If we target the domain name with gobuster it runs but fails to discover anything.


I ran gobuster with a different wordlist while poking around the site and its source code. Then, I pulled the site up in Burpsuite and intercepted the response. After noticing Phusion Passenger (R) 6.0.15, I searched for vulns but didn’t find anything.

The website says it’s going to convert a web page to a PDF for us and allows us to specify a target. This is interesting, so I started playing around by starting a netcat listener and then having it hit my machine.
That didn’t give me much, but I’m curious what it would do with a file. I replaced my netcat listener with a python web server and had it pull the nmap file I made for this room. This time it converted the document to PDF.

I’m hitting a wall here so I decided to explore more with burpsuite. I reviewed the response to a successful transaction on the site and found mention of pdfkit v0.8.6.

I looked that up in searchsploit and found a RCE exploit available for a slightly later version. After playing with the syntax a bit, I was able to get reverse shell.



I stabilized my shell then began exploring our new ruby user’s access. They don’t appear to have sudo rights or read privilege to the henry account we can see. I began inspecting the files our user does have access to.
Found some interesting tmp files but nothing I could use. I checked out /tmp/passenger.XY2Y48e where was a file that says it contains a password, but we don’t seem to have rights. I transferred linpeas to the target and started going over the results. Looked over scheduled tasks.

I continued to work my way down the linpeas results, checking some config files that were discovered. Eventually, I got to the section “Searching root files in home dirs”.
It shows a config file at /home/ruby/.bundle/config. I had already checked ruby’s home folder, but .bundle didn’t jump out to me at the time. Seeing the config file inside had me curious though and sure enough, it looks like we may have a password for that henry user we discovered earlier.


Let’s try to ssh as henry using what we found.

We are in! Time to explore what we can access again. Checking sudo rights is always a good place to start, and it looks like henry can run a ruby script as root. I checked to see if I can write to the script, but I only have access to read and execute. I read the contents of /opt/update_dependencies.rb but I’m not sure what to do with it yet.

I did a test run of the sudo command to see what happens.

It says that it couldn’t find dependencies.yml, so I tried making a test file in the /opt/ directory to see what would happen. Turns out I don’t have write permissions to opt though. At this point, I realized I hadn’t grabbed the user flag yet.

I decided to run linpeas as henry to see what else we can find. As I got the the cron jobs again I decided to check if I had rights to edit /usr/sbin/anacron, but to my surprise it wasn’t there. I am not familiar with the test command or the –x switch used, so I checked the man page for test. I thought maybe it would execute the file but it doesn’t.
I’m feeling a little lost but I still haven’t checked out whatever is on 127.0.0.1:41109. I used SSH port forwarding to try to access this port from my machine.

I couldn’t hit the port from my browser so I explored it more with nmap. I am still at a loss though and I am thinking I need to revisit the sudo rights for henry.
Reading over the contents of /opt/update_dependencies.rb, I realized that it is looking for dependencies.yml file in the relative path. Before I was trying to write to /opt/ without any luck. I made a file to test and ran the ruby script again.

We got it to successfully read the string but beyond that I’m still stuck. At this point I decided to start answering the task questions to help get me on track.

Hilariously, the task questions end where I already have been stuck at, giving me nothing to work from. I am clearly missing something obvious. The script is ruby so I try just putting the GTFObins priv escalation command into dependencies.yml and tried running it again.
I spent more time reading the ruby script, then started googling rubygems and found that it have version 3.2.5 installed.

Checking searchsploit, I don’t think this is it. I ended up setting this down for the night and came back to it the next evening. I spent more time analyzing the ruby script, but I still feel really stuck.
At this point I started just researching how to pass system commands with YAML. I tried to open a bash shell using the command below inside dependencies.yml.

This didn’t give me root shell, but it didn’t throw an error either. I tried replacing it with a couple reverse shells that didn’t work. I moved on to googling different parts of the script and I eventually stumbled across mention of RCE through YAML.load.
Going down that rabbit hole, I found a proof of concept in this article by Staaldraad. I copied the PoC payload and changed the command from “id” to “cat /root/root.txt” before running our sudo command again.


It may be hard to see the flag here, but if you read the article you will see that our command’s output is first, then the errors from the script as expected.
This room was pretty fun. Got stuck a few times but we ended up getting there.