-
-
[翻译]Java类型混淆,沙箱逃逸
-
发表于:
2018-6-4 11:29
5900
-
上周,甲骨文公司公布了他们的季度重要补丁更新(CPU)。其中7个漏洞通过ZDI计划提交,其中的一个让人想起2012年底和2013年初的java提交。这个漏洞,CVE-2018-2826 (ZDI-18-307),是一个因类型检查不足引起的沙箱逃逸漏洞,由xor19发现。一个拥有低执行权限的攻击者可以利用这个漏洞来绕过SecurityManager并提权。
漏洞
漏洞位于反射API(java.lang.invoke.MethodHandles::tryFinally(MethodHandle target, MethodHandle cleanup)方法的实现里。从这以后我会把该API称为MethodHandles::tryFinally()。该API返回一个方法句柄,这个句柄通过把目标方法包进一个try-finally块来改写它。这个cleanup方法句柄体现了final块的功能。任何在目标句柄执行期间抛出的异常都会被传递给cleanup句柄。
在MethodHandles::tryFinally()的实现里,不充分的类型检查发生了。对一个攻击者来说,在目标和cleanup方法句柄之间指派不匹配的Throwalbe对象是可能的,从而引起类型混淆。这样攻击者就可以把任何对象转化成任何类型。
一个例子
假设我们有下面两个类和方法。
攻击者构造了一个throwEx()的方法句柄和handleEx()作为cleanup.注意throwEx抛出一个Cast1类型的Throwable异常并且handleEx()处理Cast2类型的Throwalbe异常。当攻击者在一个漏洞版本的java调用新创建的方法句柄,它把Cast1类型的Throwable对象传递给了handleEx(),handleEx()处理Cast2类型的Throwable对象,并没有对传入类型有任何处理或者适当的类型检查。当handleEx()继续处理Throwable异常时,它把Lemon对象当做了Lime,这允许攻击者把Lemon转换成Lime,用Lemon类调用了Lime类的makeLimenade()方法。
利用
在漏洞利用里,攻击者尝试通过反射函数把Security Manager置为空来绕过它。首先,攻击者通过MethodHandles::publicLookup()方法得到一个setSecurityManager的方法句柄。然而,正常情况下setSecurityManager不能被MethodHandles::publicLookup()访问,所以攻击者定义了下面的代码并且利用类型混淆漏洞把Lookup对象转换成伪造的LookupMirror对象。
在handleEx()方法,攻击者把Lookup对象当作LookupMirror对象来操作。从下面相关的OpenJDK源代码可以看到,攻击者已经把Lookup对象的allowedModes属性改成了TRUSTED,从而允许攻击者得到任何方法的方法句柄,包括setSecurityManager()。
最终,攻击者使用可信的Lookup对象得到了setSecurityManager()的方法句柄并且把SecurityManager设置为空从而绕过SecurityManager产生的所有限制。
补丁
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!