• Java反序列化漏洞研究


    Java反序列化漏洞研究

    1. 漏洞原理

      java序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。当反序列化的输入来源于程序外部,可以被用户控制,恶意用户便可以构造恶意的字节流,经反序列化之后得到精心构造的恶意对象。

      也就是说一些java应用的数据在网络中传输,我们把里面的序列化数据抠出来,替换成我们的payload,应用程序接收之后把payload进行反序列化,构造的恶意功能(如命令执行)就被执行了。

      实际过程中直接忽略PCA的存在,hacker先于PCB完成一些前期的交互。

      那么问题来了,如何构造能执行任意命令的payload?需要依赖于什么条件? 哪些应用会在网络中传输序列化的数据?这些数据有什么特征?

      1. 序列化与反序列化原理

      上述代码说明了反序列化的过程,Java中通过writeObject()函数对对象进行序列化,将有结构的数据转换成为无结构的二进制串。 通过readObject()函数将二进制串反序列化还原成对象。

      执行到12行时生成了一个String类型的对象。

      执行到16行已经将序列化数据写入到object.db中了,前面的四个字节AC ED 00 05开头,后面会经常用到。

      执行到24行,完成反序列化过程,将对象还原,此时对象id不同,其他均相同。

      1. 构造执行任意命令的payload

      下面的代码能快速的体验payload是如何构造的。

      程序1的RunInvo类,构造了一个MAP,再用它构造AnnotationInvocationHandler对象,将这个对象序列化到payload.bin中。

      程序2读取payload.bin中的数据,通过readObject()进行反序列化,代码得到执行,弹出计算器,如下图所示。

      代码执行关键点:AnnotationInvocationHandler,TransformedMap.decorate,InvokerTransformer

      从序列化数据传入readObject()开始解释为什么要依赖于这几个关键点。

      首先在序列化和反序列化的过程中,每个类都有自己的readObject与writeObject对应,很多类自己重写了自己的readObject与writeObject函数,String类有自己的readObject方式,AnnotationInvocationHandler也有自己的readObject方式。而AnnotationInvocationHandler的readObject实现调用了setValue()函数,这一特性将会被TransformedMap.decorate用到。

      TransformedMap的decorate(Map map, Transformer keyTransformer, Transformer valueTransformer)函数,会将Map {key:value}按后面两个传入的函数参数来进行转换,当key或者value改变时(调用setValue),decorate就会被触发,而Transformer可以是一个调用链ChainedTransformer。这个调用链是通过InvokerTransformer精心构造的。

      InvokerTransformer函数只需要传入方法名,参数类型,参数即可调用任意函数。通过这个函数构造调用链能够执行Runtime.exec()。而InvokerTransformer存在于Apache Commons Collections的库中,因此目标应用中需要有这个库,函数才能得到执行。

      Payload的构造与触发流程如下图所示

      几个关键函数原型可参考http://www.slideshare.net/codewhitesec/exploiting-deserialization-vulnerabilities-in-java-54707478

      只有InvokerTransformer依赖于Apache Commons Collections库,其他函数都是通用的java库,所以payload执行的依赖条件只需目标java应用包含了Apache Commons Collections库即可。

    2. jboss下的利用

      jboss的问题存在于/invoker/JMXInvokerServlet ,利用比较简单直接发送payload即可

       

      POC代码如下

      执行结果

       

      其特征即为AC ED 00 05(序列化的标识)

    3. Jenkins下的利用

      Jenkins有远程接口调用的地方存在jenkins-cli.jar对远程命令的下发处。

      通过抓包分析出交互流程如下

      1)客户端向服务器请求端口列表

      2)服务器返回一些端口列表

      3)客户端与X-Jenkins-CLI-Port端口建立连接

      4)客户端与服务器协商连接类型,X-Jenkins-CLI-Port为非安全模式,X-Jenkins-CLI2-Port为安全模式,数据用密文传输,默认使用X-Jenkins-CLI2-Port。 这里POC程序需要修改为CLI模式

      5)服务器返回welcome,与base64编码的序列化对象

      6)客户端发送这个对象,在服务端执行,这里就是利用点,将payload用base64编码,替换掉原来的base64序列化对象

      7)客户端发送后续的一些附加数据(可抓包获得后面的数据)

      因此POC需要构造前面的交互,获取cli端口(服务器随机生成的),选择Protocol:CLI-connect模式(明文传输),然后发送<===[JENKINS REMOTING CAPACITY]===> + base64(payload) + append数据。

      简单的弹计算器POC效果

      其特征为rO0AB(AC ED 00 05的base64值)

    4. 检测特征&其他应用漏洞挖掘方法

      Java的序列化数据在报文中的特征比较明显,开头一定会带上AC ED 00 05。但是有些报文是加密传输的,对于复杂的加密无法直接从报文提取特征。但是对用base64这种简单的编码也是能提取出特征的。

      Base64加密的可能情况(base64将3字节转换为4字节3×8bit=4×16bit):

      AC ED 00 05在开头,按3,1分组ACED00=>rO0A,05xxxx=>BXXX 结果rO0ABxxx 特征:rO0AB

      AC ED 00 05在中间,按2,2分组xxACED=>xxzt, 0005xx=>AAxx, 结果xxztAAxx 特征:ztAA

      AC ED 00 05在中间,按1,3分组xxxxAC=>xxxs, ED0005=>7QAF 结果xxxs7QAF 特征:s7QAF

      目前大部分情况ACED0005在开头,特征为rO0AB。 也有可能序列化对象与其他字段混合在一起再进行base64加密,所以理论来说后面两种情况也是有可能的,只是概率较低。

       

      对于有流量的厂商可以监控数据中是否包含AC ED 00 05,或者rO0AB等特征。如果发现序列化特征可以进行攻击防护,或者0day挖掘。思路如下:

  • 相关阅读:
    java:maven(maven-ssm(聚合,分包开发))
    java:Maven(Maven_ssm)
    java:Mybatis框架3(二级缓存,延时和积极加载,SSI(Ibatis)集成,SSM集成)
    java:LeakFilling (Mybatis)
    java:Mybatis框架2(基于mapper接口的开发,多种查询,复合类型查询,resultMap定义,多表联查,sql片段)
    java:Mybatis框架1(基本配置,log4j,Junit4(单元测试))
    java:Springmvc框架3(Validator)
    java:Springmvc框架2(Ajax,Json,Interceptor,Upload,Exception)
    WebLogic XMLDecoder反序列化漏洞复现
    Struts2-052 漏洞复现
  • 原文地址:https://www.cnblogs.com/alert123/p/5124637.html
Copyright © 2020-2023  润新知