6

JDK7u21调用链分析

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzU5OTk1NDU5OQ%3D%3D&%3Bmid=2247484193&%3Bidx=1&%3Bsn=a21130acc8d36da61d52620c1dc68912
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

0×00.背景介绍

关于java反序列化漏洞,最为出名的大概应该是:15年的Apache Commons Collections 反序列化远程命令执行漏洞和 2016年Spring RMI反序列化漏洞 ,其中 15年的Apache Commons Collections 反序列化远程命令执行漏洞 影响范围包括:WebSphere、JBoss、Jenkins、WebLogic 和 OpenNMSd等。 近几年比较出名的: Jackson,FastJson

Java 十分受开发者喜爱的一点是其拥有完善的第三方类库,和满足各种需求的框架;但正因为很多第三方类库引用广泛,如果其中某些组件出现安全问题,那么受影响范围将极为广泛。本文我们将主要分析JDK7u21调用链。

0×01.准备阶段

之前的调用链基本都是围绕的Java第三方包中的一些内容,但是随着JDK7U21的出现,彻彻底底的说明了反序列化根本不需要使用第三方库的支持。 而且JDK7u21的利用过程十分精彩,使用HashSet,TemplatesImpl和AnnoationInvocationHandler,其中后两个调用链频繁的出现在Collections调用链中,也都是十分经典的调用链。

关于HashSet这个容器,实际上就是底层使用了Hash表来实现的,它不允许元素重复,但它不保证顺序,这是和List的最大区别。

这一篇文章中,小豹准备分析调试一下JDK7u21这个调用链。

这里面的代码是直接使用ysoserial项目生成,直接输出到jdk7u21.cer文件中,然后进行反序列化。

java -jar ysoserial.jar Jdk7u21 "open /Applications/Calculator.app" > jdk7u21.cer

3eqqIjJ.jpg!web

注意这里的JDK版本。

./java -version

java version "1.7.0_21"

Java(TM) SE Runtime Environment (build 1.7.0_21-b12)

Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

0×02.过程分析

当进行readObject操作的时候,发现它是一个HashSet,会直接调用HashSet的ReadObject。

byaEryq.jpg!web

在内部实现中使用了HashMap,这里在For循环中,会循环的进行反序列化,在ysoserial的payload中,实际上存储了2个对象,一个是恶意调用链TemplatesImpl,另一个是Proxy。所以这里的for循环会循环2次,每一次都put进HashMap中。 第一次反序列化是一个TemplatesImpl 然后put。

YrIn2qM.jpg!web

图中反序列化的e正是我们的TemplatesImpl,恶意代码存储在_bytecodes中。 然后进入put我们会发现,首先计算key的哈希,这个key就是我们上图中的e(TemplatesImpl),注意这个函数中还有个局部变量e,很容易混淆。 然后根据hash来计算在table中的索引。

BrYfA3a.jpg!web

由于现在第一次table中还没有数据,则e为空,不会进入到for循环,而是直接调用addEntry去添加元素。      

6zi6b2U.jpg!web

本次计算的hash索引都在上图中,后面会用到。然后put函数结束,回到第二层循环,这次反序列化的实际上是一个Proxy,这个Proxy用来代理TempLatesImpl,使用动态代理的时候会直接调用到Handler中的invoke函数。 回到第二层循环中

BRBjqeB.jpg!web

这里反序列化的结果实际上就是Proxy,payload中被强制转换成上图红线标注的类。然后进入put,来计算proxy的hash。这个proxy的handler是AnnoationInvocationHandler

FJV7Jrr.jpg!web

进入hash函数,发现是调用hashcode。

ueU732y.jpg!web

这里面的k就是上面传进来的Proxy,这里会触发动态代理机制,进入到handler中的invoke方法。

AvquAbR.jpg!web

原来是调用handler中的hashCodeImpl方法。

2E3Q3e3.jpg!web

在hashCodeImpl方法中,首先获得handler中memberValues的迭代器。这个memberValues就是我们构造的hashmap,key为“f5a5a608”他的hashcode是0,value是templatesImpl恶意调用链,也就是我们第一次put进去的对象。

uYRf2ai.jpg!web

由于这个hashmap只有一个元素,所以迭代器这里只会循环一次,就出去了。所以0和X亦或,还是X。最终返回的是templatesImpl恶意调用链的hashcode。注意这里就是精华之处了。hashCodeImpl函数结束完毕,会逐层返回到put中的hash函数

q2qUFjA.jpg!web

你会惊奇的发现hash值和我们前面第一次put时候的hash一模一样。这就造成了hashset第一个元素的hash和第二个proxy的hash一样,于是他们获得的索引值i也就一样。

BJ3QVvF.jpg!web

这里的i同样也是5。那现在和第一次执行put的时候完全情况就不一样了,第一次我们是由于table返回的e是空的,没有进入到循环中,直接进行add添加元素。这次i为5,正好e是TemplatesImpl对象。e不为空会进去到循环。

RnyMnmA.jpg!web

进入到循环之后,会调用key.equals函数。key的本质是proxy啊。会继续触发动态代理。
会去执行invoke,去调用equalsImpl方法。

Zv2Ifae.jpg!web

equalsImpl方法会触发我们的恶意代码

JZ3uInN.jpg!web

首先获取所有的methods。然后循环的invoke。第一次invoke的函数是var5。我们可以看到第一个就是newTransformer函数。剩下就是TemplatesImpl子调用链的过程了,详细可以参考其他文章(关于TemplatesImpl调用链本文暂不调试)。newTransformer函数就会导致bytecodes的加载。

RZZbyiv.jpg!web

这个调用链的思路和collections差别挺大的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK