zoukankan      html  css  js  c++  java
  • 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挖掘。思路如下:

  • 相关阅读:
    浙大数据结构课后习题 练习二 7-2 Reversing Linked List (25 分)
    浙大数据结构课后习题 练习二 7-2 一元多项式的乘法与加法运算 (20 分)
    浙大数据结构课后习题 练习一 7-1 Maximum Subsequence Sum (25 分)
    浙大数据结构课后习题 练习一 7-1 最大子列和问题 (20 分)
    PAT Basic 1019 数字黑洞 (20 分)
    PAT Basic 1017 A除以B (20 分)
    PAT Basic 1013 数素数 (20 分)
    PAT Basic 1007 素数对猜想 (20 分)
    PAT Basic 1003 我要通过! (20 分)
    自动化运维——HelloWorld(一)
  • 原文地址:https://www.cnblogs.com/alert123/p/5124637.html
Copyright © 2011-2022 走看看