Java语言是最为流行的面向对象编程语言之一, Java运行时环境(JRE)拥有着非常大的用户群,其安全问题十分重要。近年来,由JRE漏洞引发的JVM逃逸攻击事件不断增多,对个人计算机安全造成了极大的威胁。研究JRE安全机制、JRE漏洞及其挖掘、JVM逃逸攻防技术逐渐成为软件安全领域的热门研究方向。
针对Java层API与原生层API, JRE安全机制分别包括JRE沙箱与JVM 类型安全机制。本文针对JRE沙箱组件及其工作原理进行剖析,总结其脆弱点;分析调研JVM安全机制,提出其脆弱点在于Java原生层漏洞,为JRE漏洞挖掘工作提供理论基础。
对于JRE漏洞,本文进行漏洞分类研究,提取Java API设计缺陷、Java原生层漏洞两种JRE漏洞类型的典型漏洞进行分析,总结漏洞特征,为漏洞挖掘工作建立漏洞模型。
根据JRE漏洞分析中建立的漏洞模型,本文采用源代码审计的方法开展Java API设计缺陷类型的漏洞挖掘工作,发现了数个Oracle JRE、OpenJDK和Apple JRE 的 Java API 设计缺陷问题。在 Java原生层漏洞挖掘工作中,出于Java原生层漏洞的特殊性,本文基于程序分析领域的符号执行技术提出一种寄存器符号化监控方法,选取开源符号执行平台S2E作为漏洞挖掘工具,并且基于其实现了针对JRE原生层漏洞挖掘的辅助插件 SymJava 和 SymRegMonitor,基于 OpenJDK 和 Oracle JRE逆向代码进行源代码白盒审计并构建了用于进行漏洞挖掘的 Java 测试用例,最后对36个调用Java原生层API的Java测试用例进行实际测试发现了共计6 个 JRE原生层安全隐患,其中2 个可被攻击者恶意利用,并给出漏洞分析和 PoC。
针对 JVM 逃逸攻防问题,本文分别从攻击和防御角度,提出 JVM逃逸攻击的5 个关键元素,针对每个元素进行攻防技术研究,并通过绕过杀毒软件静态检测的实验证明了本文提出的 JVM 逃逸攻击技术。最后,本文从多角度给出JVM逃逸攻击的防御策略。
目录
5 JVM 逃逸的利用与防范
5.1 JVM 逃逸利用研究
5.1.1 字符串混淆
5.1.2 利用反射机制
5 JVM 逃逸的利用与防范
第一章中文本已经申明JRE漏洞的危害性,并且提到利用JVM逃逸发起的攻击事件于近年来逐渐增多。用户遭受JVM逃逸攻击的一般流程为:用户访问含有恶意 Java Applet 的 URL-—浏览器解析“applet”标签的内容, class 文件被下载到本地--调用本地JVM加载执行Applet--JRE漏洞触发,恶意代码成功执行,JVM 逃逸成功。然而,随着互联网用户安全意识的提高,或者政府、企业、各类机构安全规范的不断完善,相当数量的计算机都会安装杀毒软件,因此JVM逃逸攻击的流程会多一个环节:Java Applet class文件被下载到本地之后,需要经过杀毒软件的扫描,若扫描通过,才可调用本地JVM加载并执行该Applet。总结起来,本章研究的 JVM 逃逸攻击的流程基于以下5个步骤:
1. 用户访问恶意 URL;
2. 浏览器解析"applet”标签内容,所请求的class文件下载到本地;
3. 杀毒软件扫描下载的class 文件
4, 若第3步扫描通过,则调用本地JVM加载执行Applet;若不通过,杀毒软件报警并自动隔离或删除 class 文件;
5,恶意代码成功执行, JVM逃逸成功。
基于上述5 个步骤,一次成功的 JVM逃逸攻击包含5 个要素:用户、浏览器、杀毒软件、本地JRE、 exploit代码(漏洞利用代码),无论攻击者还是防御者,都要从上述5个要素作为切入点,思考攻击手段或者防御策略。本章5.1小节介绍本文对JVM逃逸利用的研究, 5.2小节则介绍JVM逃逸攻击的防范。
5.1 JVM 逃逸利用研究
JVM 逃逸攻击需考虑两种情况:第一种是利用 Oday JRE 漏洞发起攻击:第二种是利用1day JRE 漏洞发起攻击。Oday漏洞是指被攻击者掌握而软件厂商毫不知情且没有修复的漏洞,这类漏洞危害极大,难以做到有效的防御,不过攻击门槛较高,攻击者往往需要通过精湛的漏洞挖掘技术去挖掘Oday漏洞。而1day漏洞是指已经公开细节的漏洞,且在最新软件版本中已经修复了这类漏洞。然而,如果用户不及时更新JRE软件版本,还是会有遭受1day漏洞攻击的潜在威胁。知名杀毒软件厂商卡巴斯基在2013年10月的一份技术报告【37】中曾经指出,超过半数的用户仍在使用旧版本(也就是存在1day 漏洞的版本)的JRE的攻击门槛被大大降低。在此种情形之下,用户、浏览器、杀毒软件、本地JRE,exploit代码5要素中,起到关键性防御作用的就是杀毒软件。
目前主流的几款杀毒软件基本都是基于静态检测的思路,也就是当 class 文件或者 jar 文件下载到本地时,杀毒软件会进行一次静态扫描,检测文件中是否含有已知exploit代码的特征信息。Java源码编译为class文件后,其字符串变量、方法名、类名、包名都会以 UTF-8 字符串的形式保存在 class文件中。用十六进制编辑器打开class文件可以清楚地看到这些字符串,如图5-2所示。
经过对几款主流杀毒软件的测试发现,杀毒软件的静态检测机制主要是针对exploit程度中的特征字符串。如漏洞CVE-2012-4681中包含Java API设计缺陷的类名称“sun.awt.SunToolkit”,或者如漏洞 CVE-2012-5076 中调用的缺陷类名称“ManagedObjectManagerFactory”及其方法"getMethod”。这种静态检测机制存在不安全因素,可以通过 exploit 代码混淆技术绕过。关于此方面的研究将在5.1.1, 5.1.2,5.1.3 小节中展开。
在JVM逃逸攻击中,除去杀毒软件要素,用户的安全意识也起到了决定性作用。一次成功的攻击往往伴随着对用户行为的诱骗,如伪造诱惑、恐吓性质的邮件,诱骗用户点击恶意 URL。关于此方面的研究将在5.1.6 小节中展开。此外,针对JRE 7的安全策略和软件特性, 5.1.4和5.1.5小节也作了一定研究。
5.1.1 字符串混淆
针对杀毒软件的特征字符串检查,只需将字符串混淆即可绕过,常见的混淆方法有十六进制转换、base64 混淆、异或混淆等等。在实际测试中发现,部分杀毒软件还是会查杀十六进制混淆过的class文件。使用自定义key的异或加密方法简单有效,而且可以绕过多数基于静态检查的主流杀毒软件。实现异或加密的方法如表5-1 所示。
把字符串“sun.awt.SunToolkit”进行异或加密的代码如表5-2 所示。执行这段代码的Java控制台输出如图5-3所示。
若要得到原来的字符串,只需要再对混淆后的字符串执行一次 encrypt 操作即可。注意图5-3中的字符串,第一行与第二行之间有一个换行符“r”,第二行的结尾有个制表符“tab”,第二行和第三行之间有一个换行符“n”。参考第三章中列举出的 CVE-2012-4681 利用代码,可以进行字符串加密改写,改写后的代码如图5-4 所示。
5.1.2 利用反射机制
在杀毒软件绕过的测试实验中发现,对于某些杀毒软件,只作字符串变量混淆是不够的,杀毒软件仍然会发出警报。例如CVE-2013-1493,其漏洞触发代码为:"coo.filter(sbi,dbi)"。其中cco是ColorConvertOp类的一个对象,其filter方法触发了漏洞。在测试中发现,完全不经过任何混淆的exploit class会被杀毒软件查杀,而注释掉如上代码再编译、运行、测试就发现不会被查杀,所以杀毒软件静态检测的关键就在于检测filter这个方法,也就是通过解析 class文件格式,在方法定义区域中查找“filter”关键字。本研究发现,针对这种检测方法名称、类名称或者包名称的静态检测手段,可以用反射加字符串混淆的方式绕过。使用反射 API 加字符串混淆的 exploit 关键代码如图5-4 所示。图中红色标记的反射API "forName"、 "getMethod"、"invoke”分别可以实现任意类对象获取、任意方法对象获取、激活方法对象执行的功能。