2013年7月,安全组织Security Explorations发现了Java 7u25中的一个安全漏洞,通过这个漏洞攻击者可以完全摆脱Java沙箱。Oracle在更新的7u40中包含了一个补丁,但是据Security Explorations 在今年早些时候声称,这个补丁仅仅在理念上对其进行了修正,对代码稍加修改之后,依然可以利用这个漏洞。另外,随后的研究表明这个漏洞甚至比最初报道的更加严重。在这个问题公开之后,Oracle发布了一个补丁,作为8u77的一部分。

这个漏洞可以在新的反射库中找到,该库从Java 7以后均可以使用,更具体来讲,是在使用新的MethodHandle类动态访问和调用方法的时候。它与不同ClassLoader加载类的方式有关。要理解这个问题,需要一些基本的知识,这些知识涉及到Java ClassLoader的工作方式, 因为类加载是在Java中大家了解最少的领域之一,所以在阐述这个问题本身之前,我们会首先概述一下这个理念。

Java ClassLoader

Java能够在运行时从各种来源动态加载代码。这种功能是通过一系列名为ClassLoader的特殊类来实现的。标准的Java实现会提供多个ClassLoader来加载类,它们能够从文件系统、URL或压缩文件等位置加载类,不过Java也为开发人员提供了创建自定义ClassLoader的能力,以应对个性化的需求。与ClassLoader交互的常见方式是调用其loadClass(String)方法,这个方法会接受类的名称,如果能够找到的话,就会返回相关的Class对象,如果找不到的话,就会抛出ClassNotFoundException异常。在Java应用中的每个类都是通过某个ClassLoader按照这种方式加载的。

通过设置父ClassLoader,这些不同的ClassLoader能够互相连接起来,形成一个层级的结构。如果没有设置父ClassLoader的话,那么父ClassLoader默认将会设置为加载该ClassLoader的那个类加载器(ClassLoader本身也是类,因此也需要通过某个ClassLoader来进行加载)。如果提供了父ClassLoader的话,那么ClassLoader的默认行为就是将加载所请求类的任务委托给它的父加载器,只有父加载器(或祖父加载器)无法加载这个类的时候,这个ClassLoader本身才会试图加载所请求的类。但是,自定义加载器的创建者并非强制性要求遵循这种默认行为,他们完全可以选择实现不同的行为。

当Java应用启动的时候,如下的ClassLoader将会按照顺序发挥作用:

  1. Bootstrap ClassLoader:JVM本身的一部分,因此在每个JVM中,它的实现都是特有的。这个ClassLoader没有父ClassLoader,它用于加载java.lang包下的核心类。
  2. Extension ClassLoader:负责加载扩展库中的类,在每个Java安装环境下可能会有所差别。Extension ClassLoader将会加载java.ext.dirs变量所指定路径下的所有内容。
  3. Application ClassLoader:负责加载应用程序的主类以及所有位于应用类路径下的类。
  4. Custom ClassLoader:应用程序中使用的所有其他的ClassLoader。它是可选的,根据应用的情况不同,它可能并不存在。

在运行时,使用自定义的ClassLoader动态加载类为很多的应用创造了可能性,否则的话,有些功能可能是无法实现的,不过,遗憾的是,它也造成了很多的安全问题,尤其是在类仿造(class impersonation)方面。理论上,开发人员可以创建一个自定义的ClassLoader,让它来加载原始类java.lang.Object的一个模拟实现,并在应用程序中使用这个自定义的对象。这可能会在两个方面引发安全问题:这个自定义的对象能够访问java.lang包下所有包范围内可见的类内容;其次,这个自定义的Object会被JVM作为标准的Object对象,因此会将其作为由Java实现的可信任的类。

为了保护Java以应对这些安全问题,Java类要通过三个属性来进行识别:类名、包以及ClassLoader的引用。如果两个不同的类具有相同的类名和包名,但是由不同的ClassLoader所加载的话,Java会认为它们是不相等的,在它们两者之间进行赋值的话,将会导致ClassCastException异常。这样的话,就能保护环境免受类仿造的攻击。

部分修复以及由此导致的漏洞

Security Explorations最早报告了这个漏洞,并将其归类为CVE-2013-5838,这个漏洞可以描述为,当通过Method Handle调用方法时,对于被调用方法的那个类,它的ClassLoader并没有进行检查,这意味着攻击者可以按照上文所述的方法进行类的仿造。

展现原始漏洞的代码样例,目标类的ClassLoader并没有进行检查;来源:Security Explorations

Oracle在2013年9月提供了一个修正,作为Java 7u40的一部分,包含了类可见性的检查,它会对比预期类型和传入类型的ClassLoader,对比方式如下:

  • 如果两个ClassLoader相同的话,那么按照定义这两个类型是完全兼容的;
  • 如果其中一个ClassLoader是另一个ClassLoader的父加载器,那么它认为这两个类是通过正常的ClassLoader层级结构加载的,因此将其视为相等是安全的。

在第二项检查中,Security Explorations发现exploit稍加修改就可能继续有效。首先,用于仿造类的自定义ClassLoader将目标ClassLoader设置为它的父类加载器,这可以通过API以参数的方式进行设置:

URLClassLoader lookup_CL = URLClassLoader.newInstance(urlArray, member_CL);

通过该机制将自定义的ClassLoader作为等级结构的一部分,来源:Security Explorations

然后,鉴于ClassLoader的默认行为是将加载类的任务委托给它的父加载器,攻击者就需要确保父ClassLoader无法加载到这个类,这样他们自定义的ClassLoader就能发挥作用了。借助Java以网络方法加载类的过程,这种攻击模式得到了印证:如果这个类通过URL位置的方式来进行定义的话,父ClassLoader将会试图连接相关的服务器并获取这个类的代码,此时,预先构建好的HTTP服务器可以返回404 NOT FOUND错误,让父ClassLoader加载这个类出现失败,因此就会将控制权转移给自定义的ClassLoader。

通过自定义的HTTP服务器,强制父ClassLoader加载类失败之后的代码流,来源:Security Explorations

当这个缺陷2016年3月重新爆出时,当时最新的可用版本是8u74,这个版本被证明是有漏洞的,Oracle在8u77中为其提供了修正。但是,在8u77的发布说明中,这个漏洞依然描述为“会影响桌面设备上,Web浏览器中所运行的JavaSE[并且]不会影响到Java部署环境,比如典型的服务器或独立部署的桌面应用”,但是事实证明,它还是会影响服务器配置以及Google App Engine的Java环境。

修正:2016年4月29日

本文错误地认为这个漏洞在8u77、8u91和8u92版本中依然存在,实际上,在8u77中它已经得到了修正。在8u77的发布说明中将其描述为对CVE-2016-0636的修正,具体描述是这样的“未指明的漏洞[...]借助Hotspot子组件中未知的感染内容”并且没有包含对本文中所提及的CVE-2013-5838的明确引用。但是,Security Explorations指出 CVE-2016-0636是针对Issue 69的一个CVE编号,而Issue 69是他们自己代指最初CVE-2013-5838的一种方式。(在本文英文原文的评论区,讨论了该问题解决的相关过程,感兴趣的读者可以访问原文查看。——译者注)

查看英文原文:Vulnerability in Java Reflection Library Fixed after 30 Months

http://www.infoq.com/cn/news/2016/05/java-reflection-vulnerability?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=news_link&utm_content=link_text

Java反射库中的安全漏洞在30个月后终于修复了(转)的更多相关文章

  1. JAVA链表中迭代器的实现

    注:本文代码出自<java数据结构和算法>一书. PS:本文中类的名字定义存在问题,Link9应改为Link.LinkList9应该为LinkList.由于在同包下存在该名称,所以在后面接 ...

  2. Java开发中的eclispe常用快捷键&全部快捷键

    Java开发中的eclispe常用快捷键&全部快捷键 Ctrl+1 快速修复(经典快捷键)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ ...

  3. ref:关于JAVA中一些安全漏洞示例说明及如何规避方法代码示例总结分享

    ref:http://www.xwood.net/_site_domain_/_root/5870/5874/t_c268166.html 标签:安全,漏洞,健壮,java,SQL注入,SS及CSRF ...

  4. java代码审计中的一些常见漏洞及其特征函数

    文章来源:https://xz.aliyun.com/t/1633 最近在先知上看到之前有篇关于java代码审计的文章总结的蛮好,记录以下特征函数,方便查阅,同时自己也会将在平时代码审计过程中积累的函 ...

  5. Java语言中的面向对象特性总结

    Java语言中的面向对象特性 (总结得不错) [课前思考]  1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类?  2. 面向对象编程的特性有哪三个?它们各自又有哪些特性?  3. 你知 ...

  6. Linux上从Java程序中调用C函数

    原则上来说,"100%纯Java"的解决方法是最好的,但有些情况下必须使用本地方法.特别是在以下三种情况: 需要访问Java平台无法访问的系统特性和设备: 通过基准测试,发现Jav ...

  7. Java线程中yield与join方法的区别

    长期以来,多线程问题颇为受到面试官的青睐.虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用.之前,我讨论了一个w ...

  8. 如何在Java 8中愉快地处理日期和时间

    Java 8新增了LocalDate和LocalTime接口,为什么要搞一套全新的处理日期和时间的API?因为旧的java.util.Date实在是太难用了. java.util.Date月份从0开始 ...

  9. 找出Java进程中大量消耗CPU

    原文:https://github.com/oldratlee/useful-shells useful-shells 把平时有用的手动操作做成脚本,这样可以便捷的使用. show-busy-java ...

随机推荐

  1. 飞翔(LIS变形)

    飞翔 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 鹰最骄傲的就是翱翔,但是鹰们互相都很嫉妒别的鹰比自己飞的快,更嫉妒其他的鹰比自己飞行的有技巧.于是,他们决定举办一场 ...

  2. winform之2---messagebox用法

    MessageBox.Show();可谓是winform开发中用的次数最多的东东啦.先贴一张msdn的图解 msdn好像没有更新哎,只提供了这几种方法,并且参数名称和最新的有差别,但实际上messag ...

  3. ACM 做题过程中的一些小技巧。

    ACM做题过程中的一些小技巧. 1.一般用C语言节约空间,要用C++库函数或STL时才用C++; cout.cin和printf.scanf最好不要混用. 2.有时候int型不够用,可以用long l ...

  4. oracle 11gR2默认密码修改

    很久以前装了Oracle,今天终于下决心要学一学了,结果一上午的时间就贡献给如何连接数据库上了 忘记了安装时设置的用户名和密码怎么办?查了下网上的资料,终于解决了! 方法一: 首先进入sqlplus: ...

  5. STLport在vc6中的集成

    STLport的下载 http://sourceforge.net/projects/stlport/ STLport的编译 * 试验环境 : win7x64sp1 + vc6sp6* 打开控制台窗口 ...

  6. Qt学习之路(49): 通用算法

    今天开始的部分是关于Qt提供的一些通用算法.这部分内容来自C++ GUI Programming with Qt 4, 2nd Edition.   <QtAlgorithms>提供了一系 ...

  7. C++界面库

    刚开始用C++做界面的时候,根本不知道怎么用简陋的MFC控件做出比较美观的界面,后来就开始逐渐接触到BCG  Xtreme ToolkitPro v15.0.1,Skin++,等界面库,以及一些网友自 ...

  8. Tuxedo入门学习

    中间件介绍: 介于客户机和server之间的夹层,突破了传统的c/s架构,为构建大规模,高性能,分布式c/s应用程序提供了通信,事物,安全,容错等基础服务,屏蔽了底层应用细节,应用程序不必从底层开发, ...

  9. poj3819 Coverage (求直线与圆的交占直线的百分比 )

    题意:给你一条直线和若干个圆,求圆与直线相交的长度占整条直线的比例 解题思路:通过定比分点的方法求出圆与直线的交占圆的比例. 第一步:(确定投影的方向是x轴还是y轴) (1)当直线的line.s(x, ...

  10. Java8 Lamdba表达式 001

    在一个已经存在的编程语言里非常少有对现有的生态系统起重大影响的新特性.Lambda表达式对于Java语言就是这样的意义的存在.简单来说,Lambda表达式提供了便利的方式去创建一个匿名的功能.提供了一 ...