​Java 反序列化漏洞始末(2)

释放双眼,带上耳机,听听看~!

点击上方“凌天实验室”,“星标或置顶公众号”

漏洞、技术还是其他,我都想第一时间和你分享

接上篇:
Java 反序列化漏洞始末(1)

jdk7u21

jdk7u21 gadget 可以算的上是非常骚的一个反序列化 payload,浑身都是骚点。

相比 Apache commons collections 系列的 payload 分析起来要稍稍烧脑一点。

不管序不序列化的,先让他弹个计算器再说。

参考了 gist 和一些大佬的分析文章可以得知,漏洞触发的地方在 TemplatesImpl.getOutputProperties(); 方法。

https://gist.github.com/frohoff/24af7913611f8406eaf3

/src.zip!/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java:380

最终是在这里被触发的,所以现在是要让他在反序列化时自动去调用 getOutputProperties() 。


EXP

↑↑↑(以上为部分,全部源代码文件请后台回复“源代码”)

我把 ysoserial 里的 payload 生成代码给提取了出来,看看他是如何构造的 payload。

如何构造payload

主要看 createTemplatesImpl 方法。

其中这一段,是使用 javassist 动态的添加的恶意 java 代码,在初始化后执行。


并且设定了类名为 ysoserial.Pwner + System.nanoTime()

最后通过反射把类的字节码塞进了 TemplatesImpl 的 _bytecodes 属性里。

至此 payload 生成部分结束。

这个奇怪的字符串暂且不管是干嘛的,值得关注的是它的 hashCode 为 0。

其实不止这一个字符串 hashCode 为 0。

经过测试,我发现 空字符串和 \u0000 的 hashCode 都为 0。

网上也有一些其他例子,在这里都适用,只要是 hashCode 为 0 就行

参考:

https://stackoverflow.com/questions/18746394/can-a-non-empty-string-have-a-hashcode-of-zero

后面除了创建了一个动态代理还有,一个装有键 = f5a5a608 值 = TemplatesImpl恶意对象的 HashMap 和装有 TemplatesImpl

恶意对象和 Templates 动态代理对象的 LinkedHashSet,

至此得出最终被序列化的恶意对象 LinkedHashSet。


复    现

分    析

LinkedHashSet 继承自 HashSet,readObject 在父类里。

它会把反序列化回来的对象,添加到 map 里(HashSet 本质上是一个 HashMap)

添加的顺序是,先添加 templates 再添加 proxy。

在第二次添加,也就是添加 proxy 的时候,此时 map 里已经有了一个 templates 。


它会和上一个 Entry 的 Key (templates) 进行比较,判断这两个对象是否相等,如果相等则新的替换老的值,然后返回老的值。


而问题正好就出在了 key.equals(k) 这个地方。

要想执行到这里,必须满足如下条件

e.hash == hash 为真

(k = e.key) == key 为假

e.hash 其实就是 templates 对象经过计算后的 hash 暂且假设为 10086

hash 是当前代理对象的 hash,这里要看一下它是怎么计算代理对象的 hash 的

在 hashMap 计算对象 hash 在当前对象的 hashCode 的基础上做了一些异或运算,所以还是要去调用对象的 hashCode 方法的。

因为此时的 key 是一个 proxy 代理,要调用它的方法先进 invoke 接口。即(sun.reflect.annotation.AnnotationInvocationHandler#invoke)

在 invoke 方法中它判断了如果方法名为 hashCode 就去调用 hashCodeImpl() 方法


看起来挺恶心,其实简化一下理解就是,遍历 memberValues 这个 map 对象,然后做这样一个运算


memberValues 这个对象其实是我在实例化 AnnotationInvocationHandler 对象时传过去的 hashMap。

这个 hashMap 它的键被我设定为了 f5a5a608 值是 templates 对象。

所以它在这里的 hashCode 运算表达式就变成了

0 ^ memberValueHashCode(templates);

等价于

memberValueHashCode(templates);

又等价于

templates.hashCode()

可以拿这个 demo 做个试验,经过测试会发现计算后的 hashCode 和 expVal 对象的 hashCode 是相等的

其实说白了此时的情况就是拿 templates 对象和自身的 hashCode 做比较,结果当然为 true。

第二个条件 (k = e.key) == key 想都不用想,拿 proxy 和 templates 比肯定为 false。

所以程序自然走到了  key.equals(k) 这一步,既 proxy.equals( templates )

那因为调用的是代理对象的方法,自然要再走一遍 invoke 接口。

invoke 接口中又会去调用 equalsImpl 方法。

其中在注释部分取出了 templates 的两个无参方法,并且使用了反射执行。

TemplatesImpl 中 getOutputProperties 方法调用过程如下。

最终在此处实例化对象并触发了恶意代码



凌天
实验室

凌天实验室,是安百科技旗下针对应用安全领域进行攻防研究的专业技术团队,其核心成员来自原乌云创始团队及社区知名白帽子,团队专业性强、技术层次高且富有实战经验。实验室成立于2016年,发展至今团队成员已达35人,在应用安全领域深耕不辍,向网络安全行业顶尖水平攻防技术团队的方向夯实迈进。



“阅读原文”我们一起穿越安百信息安全资讯平台~

本文源自微信公众号:凌天实验室

人已赞赏
安全工具

国庆福利||CVE-2019-0708-EXP-Windows-Version

2019-10-14 14:04:50

安全工具

渗透技巧——从github下载文件的多种方法

2019-10-14 14:04:55

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索