1.序列化与反序列化:

序列化与反序列化对于 Java 程序员来说,应该不算陌生了,序列化与反序列化简单来说就是 Java 对象与数据之间的相互转化。

那么对于完全面向对象的 Java 语言来说为什么要有序列化机制?

实质上,序列化机制并不只局限于 Java 语言,序列化的本质是内存对象到数据流的一种转换,我们知道内存中的东西不具备持久性,但有些场景却需要将对象持久化保存或传输。例如缓存系统中存储了用户的 Session,如果缓存系统直接下线,带系统重启后用户就需要重新登陆,为了使缓存系统内存中的 Session 对象一直有效,就需要有一种机制将对象从内存中保存入磁盘,并且待系统重启后还能将 Session 对象恢复到内存中,这个过程就是对象序列化与反序列化的过程,从而避免了用户会话的有效性受系统故障的影响。

此外,在 Java 工程中,序列化还广泛应用于 JMX,RMI,网络传输(协议包对象)等场景,可以说序列化机制赋予了内存对象持久化的机会,就像虚拟机镜像(VMware Take a snapshot),也可以将序列化机制看作是内存对象的一种镜像机制。

在 Java 中,只要一个类实现了 java.io.Serializable 接口,那么它就可以通过 ObjectInputStreamObejctOutputStream 序列化,如下我们模拟了 Session 对象持久化存储与从磁盘加载的过程:

结合注释,这段测试代码应该不难理解,我们可以看到 Java 对象序列化就依赖于 ObejctOutputStreamwriteObject 方法,而反序列化是由 ObjectInputStreamreadObject 方法实现的,下图是作者画的一个序列化示意图:

2.反序列化漏洞成因

2015 年年底,由公共依赖库 Apache Common Collections 引起的 Java 任意命令执行漏洞的严重安全问题,使得 Java 反序列化漏洞逐渐进入了安全研究人员的视野(在此之前存在,但并未被重视),而任意命令执行的成因正是前文反序列化操作的 ObejctInputStream 类的 readObject 方法触发的。

Java 序列化机制虽然有默认序列化机制,但也支持用户自定义的序列化与反序列化策略。例如对象的一些成员变量没必要序列化保存或传输,就可以不序列化,或者也可以对一些敏感字段进行处理等自定义对象序列化的行为,而自定义序列化规则的方式就是重写 writeObejctreadObject。当对象重写了 writeObejctreadObject方法时,Java 序列化与反序列化就会调用用户自定义的逻辑了,下图示例我们对 Session 对象重写了序列化处理函数:

OK,到目前为止一切都在程序员的掌控之中!何来的漏洞之说?

呵呵,意外往往就发生在不经意之间,如果反序列化过程中提供了命令执行的机会,那么任意命令执行漏洞就产生了,如下我们在 Session 对象的 readObject 函数中增加了执行命令的代码:

此时,黑客只需要将 Session 对象的 sessionId 构造成想要执行的命令字符串,即可实现远程命令执行的功能,如下成功打开系统 calc.exe 进程:

好了,我们再来梳理一下上例中漏洞存在的条件与利用思路:

条件:

首先 Session 对象重写了反序列化函数 readObject,并且 readObject 方法存在执行命令的机会。

漏洞利用:

正常的反序列化流程会重新生成一个正常 Session 对象,而恶意的序列化数据抓住了反序列化的漏洞执行命令的机会,精心构造了序列化对象,使得数据流反序列化的过程中恶意命令得以执行。

看到这里,作为程序员的你肯定哈哈大笑!对象的反序列化函数谁会这样写?

当然本示例只是为了以最直观的方式演示反序列漏洞产生原因,就直接提供了一个 HelloWorld 级别的漏洞示例.

实际上,近两年 Java Apache-CommonsCollections 造成的序列化漏洞与 Spring 框架的反序列化漏洞(spring-tx.jar)的成因与原理都与上例相似,只是漏洞利用的构成比较复杂而已。

3.Java Apache-CommonsCollections RCE 漏洞解析

该漏洞曝光于 2015 年年底,被誉为当年“最被低估了的漏洞”,利用思路一经爆出,各大 Java web 厂商纷纷躺枪,受此影响的 Web 服务器有:WebLogic、WebSphere、JBoss、Jenkins、OpenNMS等。

介于该漏洞曝光距今已经有两年之久,并且网上也有对此分析的很透彻的文章,本文就来讲一下这个可以通过精心构造触发命令执行的漏洞的要点。该漏洞的主要问题就出现在 org.apache.commons.collections.Transformer 接口上,在 Apache-CommonsCollections 包中,有一个 InvokerTransformer 类实现了 Transformer 接口,并且 InvokerTransformer 这个类也很恰巧,InvokerTransformertransform 方法提供了一个可以通过 Java 反射机制,调用任意 Java 方法的机会:

相信很多漏洞利用者对 invoke 非常敏感,意味着提供了方法调用的机会,再结合方法名与参数都能通过 InvokerTransformer 构造函数来控制,因此该类一定是漏洞挖掘者反复徘徊的地方。那该怎么利用?

InvokerTransformer 结合 ChainedTransformer 就能构造一个 Java 类加载函数调用链,POC 的作者是如下构造的:

这样构造的原因在于 ChainedTransformertransform 函数会依次调用数组中 InvokerTransformertransform 函数,构成一个函数调用链,下图是调试状态下,ChainedTransformertransform 方法的变量状态:

可以看到,通过 ChainedTransformer.transform 的构造相当于反射调用了 Runtime.getRuntime().exec(),触发了命令的执行。

OK,那么问题来了,谁去触发调用 ChainedTransformer.transform 函数呢?

漏洞利用者找到了包中 TransformedMap.checkSetValue() 方法:

这样一来,POC 就可以通过构造一个 TransformedMap 对象,然后再想办法触发 checkSetValue 函数即可,而 TransformedMapApache-CommonsCollections 这个集合库中可以通过 TransformedMap.decorate 修饰器方法来修饰一个 Map 对象,而 Map 对象在反序列化是只需调用 MapEntiry.setValue 就能触发 checkSetValue 函数,进而进一步触发第一步构造的 ChainedTransformer.transform方法,从而实现漏洞利用的目的。

以上就是 Apache-CommonsCollections RCE 漏洞的利用思路,该漏洞的实质是 Apache-CommonsCollections 为利用者提供了一系列可以构造行命令机会。

但是聪明的你一定会问,上面的漏洞触发条件并不是在反序列化函数 readObject 中实现的,怎么能在反序列化中触发 POC 的执行?

好问题!思路是这样的,可以找到一个这样的对象:

1.该类自定义重写了 readObejct 反序列化函数。

2.readObecjt 方法中调用了 Map 的 checkSetValue 函数,并且该 Map 对象还可以通过构造函数构造。

呵呵,我知道,你又开始笑!的确条件比较苛刻,也难怪该漏洞在 2015 年初没有被重视起来,但是老外还就给你在 JDK 中找到了一个满足条件的的对象--sun.reflect.annotation.AnnotationInvocationHandler。好了,废话不多说,来看一下的 AnnotationInvocationHandler 的反序列化函数满不满足触发要求:

因为 setValue 函数会调用 checkSetValue

从而在 sun.reflect.annotation.AnnotationInvocationHandler 对象反序列化时,就满足了 ChainedTransformerTransformerMap构造的 POC 触发的条件,最后我们给出完整的构造 Apache CommonCollections 反序列化漏洞利用POC的代码(来自网络):

小伙伴们看到这里可能一头雾水了,作者这里借用斗象科技在分析该漏洞时画的一幅漏洞POC构造触发流程图,再来梳理一下漏洞利用的思路:

因此 POC 的流程为:TransformedMap->AnnotationInvocationHandler.readObject()->setValue()->checkSetValue() 最后由反序列化 readObject 时触发执行。

的确,该漏洞的触发方法与构造思路非常精妙,不得不佩服这位写出 POC 的老外。

4.如何防范:

首先,开发者要有安全意识,应该清楚项目使用到的组件是否有漏洞存在,虽然说 Apache-CommonsCollections RCE 漏洞曝光将近两年了,但使用存在漏洞的 3.2.2 之前版本的 web 服务框架依然存在,Apache James 3.0.0 版本的 CVE-2017-12628 漏洞就是还在使用 commons-collections-3.2.1.jar 造成的。

不过安全意识,很多开发者不是没有,而是没有接触过,作者在一个使用 struts 框架的团队待过,他们写出的代码真的是 Web 漏洞一箩筐啊。

可以禁用 JVM 执行外部命令(Runtime.exec),因为 Runtime.exec 对于大多数 Java 正常应用来说是不会用到的,但是确是黑客控制Web服务后运行命令的重要方法,因此该手段是 Java Web 防护常用的且有效的手段,如果从攻击者角度看这种防护效果,那就是攻击工具 webshell 只能文件相关操作,无法执行命令。可以通过扩展 SecurityManager 来禁用 Runtime.exec,当触发运行时还可加入报警逻辑,启动应急响应:

5.反序列化漏洞的其他思考:

作者认为反序列化漏洞的利用应该更为广泛,思路不应该仅仅局限于远程命令执行漏洞的利用,也存在着系统数据篡改污染的危险,造成系统业务安全问题。

例如序列化对象在系统中承担了账单、金额、认证、鉴权等职责,如果可以被反序列化利用,后果也非常严重。

这样的威胁不亚于命令执行的威胁,并且事后难于排查,因为是内存攻击,载荷不落地。

所以,反序列化对于业务安全的威胁也是我们一个值得深思的问题。

Java 安全之反序列化漏洞相关推荐

  1. java amf3_Java AMF3 反序列化漏洞分析

    写在前面的话 AMF(Action Message Format)是一种二进制序列化格式,之前主要是Flash应用程序在使用这种格式.近期,Code White发现有多个Java AMF库中存在 目前 ...

  2. JBoss 4.x 5.x 6.xJBossMQ JMS 反序列化漏洞

    文章目录 Jboss反序列化漏洞利用CVE-2017-12149/CVE-2017-7504 基础知识 漏洞原理 影响版本 复现思路 复现-CVE-2017-12149 1.特征检测 2.反弹shel ...

  3. 反序列化工具_JBOSS反序列化漏洞

    10月13日 简简单单的复现一个漏洞0x00 起因 因为当初说要把vulhub上面的漏洞都复现一遍,然后今天看内网的书又头疼,python也学不下去,打开vulhub,然后随便一滚鼠标滑轮,刚刚好遇见 ...

  4. java反序列化漏洞的一些gadget

    目录 0x00 URLDNS 0x01 Commons Collections 0x02 RMI的codebase任意代码执行 0x03 JNDI 0x04 LDAP 0x05 JDK7u21 首先说 ...

  5. java 反序列化漏洞 利用思路简介

    目录 序列化的过程 readObject方法 反射链 完成反序列漏洞实践 结论 之前听别人讲解反序列化的漏洞听的晕乎乎的,刚脆就趁着周末研究一下反序列化漏洞,并且搭建实战环境实际操作了一把,明白了之后 ...

  6. java rmi反序列化漏洞 简介

    目录 一.RMI简介 二.RMI示例 三.漏洞复现 四.漏洞分析 1.为什么这里的badAttributeValueExpException对象是通过反射构造,而不是直接声明? 2.为什么不直接将ba ...

  7. java 反序列化漏洞简介

    目录 一.Java的序列化与反序列化 二.对java序列化的理解 三.反序列化的漏洞原理概述 四.关于反射链 一.Java的序列化与反序列化 在这里我们直接自己定义一个类,然后对这个类的对象(一个实例 ...

  8. java httpinvoker漏洞_Java反序列化漏洞学习

    序列化是Java提供的一种对象持久化保存的技术.常规对象在程序结束后会被回收,如果想把对象持久保存方便下次使用,需要序列化和反序列化. 序列化有两个前提: 类必须实现java.io.serializa ...

  9. java反序列化漏洞 tomcat_CVE-2020-9484 Apache Tomcat反序列化漏洞浅析

    本文是i春秋论坛作家「Ybwh」表哥原创的一篇技术文章,浅析CVE-2020-9484 Apache Tomcat反序列化漏洞. 01漏洞概述 这次是因为错误配置和org.apache.catalin ...

最新文章

  1. 比 GPT-3 更擅长理解用户意图,OpenAI发布 InstructGPT
  2. JavaScript中hoisting(悬置/置顶解析/预解析) 实例解释,全局对象,隐含的全局概念...
  3. DL之DNN优化技术:自定义MultiLayerNetExtend算法(BN层使用/不使用+权重初始值不同)对Mnist数据集训练评估学习过程
  4. git 远程分支创建与推送
  5. shell判断文件是否存在[转]
  6. java重置_JAVA復制數組和重置數組大小
  7. BZOJ 1026 windy数 (数位DP)
  8. Java 数组实现堆栈操作
  9. go获取项目内所有proto_gRPC学习之三:初试GO版gRPC开发
  10. ajax 微信code获取_计算机毕业设计中微信小程序实现微信登录(Java后台)
  11. 现代 C++ 救不了程序员!
  12. PHP数组的访问方法有几种,PHP数组的几种遍历方法
  13. java远程执行bat命令
  14. 计算机网络之网络安全基础
  15. Linux第二章:5.Xshell安装教程、使用Xshell6进行Linux远程登录
  16. mysql数据库知识
  17. 如何应对阿里、美团、Oracle等大厂的面试刁难?
  18. Linux学习笔记(1)--Linux的发展史
  19. 共射极单管放大器的Multisim仿真实验
  20. 判断手机是安卓还是苹果

热门文章

  1. 黑塞矩阵和雅可比矩阵理解
  2. 我是程序员,我在深圳卖肉夹馍
  3. 【Redis常见命令】 —— 关于Redis的一点儿知识
  4. 《变形金刚4》玩植入玩过头 红牛、舒化奶……啥都有
  5. springcloud高可用服务器集群搭建
  6. autojs-快手极速版
  7. PayPal case系统
  8. 第78句 2020年地球日:霍金留给世界的遗言比以往任何时候都更有意义
  9. 性能测试中你是否遇见过频繁fgc的问题呢?
  10. CSS动画实现跳动小红心