XStream反序列化漏洞分析
XStream反序列化漏洞分析
把之前看的XStream反序列化漏洞分析过程做个笔记,从前期JAVA的代理模式动态代理基础知识到XStream解析流程都有记录。
代理模式
代理是设计模式中的一种,代理类为委托类提供消息预处理、消息转发、事后消息处理等功能,JAVA中代理分为三种角色:代理类、委托类、接口。
以上的定义和图片过于官方和范文化,不方便理解,这里举一个具体简单理解的实例。
用户在成都想要买电脑,成都电脑代理商和北京电脑总公司都可以买,其中的电脑代理商指的就是代理类,电脑总公司就是委托类,他两都具有卖电脑这个方法,而且成都代理商的卖电脑方法其实还是北京总公司的卖电脑方法,大致情况参考如下手动画图。
抛出以下两个问题思考:
一、为什么要通过代理商买电脑?(代理模式的意义)
- 去北京总公司买电脑成本太高(直接调用委托类的方法太复杂)
二、通过代理商买电脑的好处?(代理模式的优势)增强作用
- 代理商可控制价格(参数增强)
- 同样价格代理商还送赠品(返回值增强)
- 代理商买电脑车接车送(方法逻辑增强)
代理模式包括静态代理和动态代理
静态代理的实现:
接口:
委托类:
代理类:
测试类:
动态代理的实现
委托类:
代理类:
测试类:
动态代理调用方法时是通过代理类的invoke方法调用的
参考:
https://www.bilibili.com/video/BV1qv4y1o79t?p=366&vd_source=2ad59243ca70d5beaed54382e53e0c18
https://www.cnblogs.com/cC-Zhou/p/9525638.html
EventHandler
EventHandler类是实现了InvocationHandler的一个代理类,EventHandler的构造方法传入四个参数,重点是第一个target对象和第二个action字符串。
其invoke方法调用了invokeInternal方法
invokerInternal方法由通过反射调用了构造方法中传入的target对象的action方法。
效果就是当EventHandler作为代理类用于创建动态代理时,执行动态代理的方法时,传入EventHandler的target对象的action方法会被执行。
我们new一个EventHandler对象,并把target设置设置为ProcessBuilder对象,action设置为start,将其作为代理类新建一个动态代理程序proxy。
通过动态代理程序执行委托类的方法
XStream
XStream是一个简单的基于Java库,Java对象序列化到XML,反之亦然(即:可以轻易的将Java对象和xml文档相互转换)。
代码实现XStream 对象转换为xml:
XStream xml转换为对象:
生成payload
我们利用XStream的toXML方法,将我们构造的代理类为EventHandler的动态代理对象转化成xml形式
<dynamic-proxy><interface>HelloService</interface><handlerclass="java.beans.EventHandler"><targetclass="java.lang.ProcessBuilder"><command><string>calc</string></command><redirectErrorStream>false</redirectErrorStream></target><action>start</action></handler></dynamic-proxy>
将生成的payload利用XStream的fromXML转换成JAVA对象并调用对象中的某一个方法
整个利用过程如下:
XML—动态代理对象—利用动态代理调用委托类的方法—代理类的invoke—EventHandler的invoke—通过反射调用target的action方法—Processbuilder.start(“calc”)
以下为XStream官方发布的payload
https://x-stream.github.io/CVE-2013-7285.html
但我们生成的payload需要满足两点后才能利用成功,一是目标机器要安装我们指定的接口,二是目标服务端在使用fromXML方法将xml转化成JAVA对象后又调用了对象的任意方法,这样利用起来限制条件太多,我们利用以下payload就不需要满足以上两点,payload中的java.lang.Comparable接口是JAVA JDK中自带的所以目标机器一定会有此接口,且XStream在反序列化解<sorted-set>标签时,会调用java.lang.Comparable中的compare To方法,因此也不需要目标机器在转化后又调用对象的某一方法。
<sorted-set><dynamic-proxy><interface>java.lang.Comparable</interface><handlerclass="java.beans.EventHandler"><targetclass="java.lang.ProcessBuilder"><command><string>calc</string></command></target><action>start</action></handler></dynamic-proxy></sorted-set>
XStream流程分析
TreeUnmarshaller 树解组程序,调用mapper和Converter把XML转化成java对象,里面的start方法开始解组,convertAnother方法把class转化成java对象。
TreeMarshaller 树编组程序,调用mapper和Converter把java对象转化成XML,里面的start方法开始编组,convertAnother方法把java对象转化成XML。
以下为TreeUnmarshaller 树解组程序主要部分及各部分的一些重要方法,mapper主要是利用realClass方法将xml解析转化成class,convert将class选择相应的convert后转化成JAVA对象。
解析过程开始:TreeUnmarshaller的start方法
ReadClassType方法:若classAttribute值为空则返回标签节点的class
realClass在返回class之前会进行一步安全校验,判断返回的class是否在黑名单中,如果在黑名单中则报错。
获取到class之后利用lookupConverterForType找到对应的converter
Convert方法通过unmarshal方法将class转换成java实例对象
Ummarshal调用populateTreeMap
populateTreeMap调用putCurrentEntryIntoMap
这里调用readItem方法,并且将返回的Object对象放入target这个map中
ReadItem又获取下一个标签的class对象并将class对象转换成java对象
这次获取的标签为dynamic-proxy,因此返回的class为DynamicProxy
这里判断了一些标签内容是否为interface和handler,如果是interface就将获取的class放入interfaces这个列表,如果是handler就将代理对象赋值给handlerType
获取完class后,创建动态代理
生成EventHandler对象后将原先生成的动态代理替换
然后putCurrentEntryIntoMap方法执行完后,接着调用putAll方法
PutAll方法调用put方法
Put方法调用compare方法
compare方法又调用了compareTo方法
compareTo方法的介绍如下:
它是java.lang.Comparable的一个方法,所以相当于执行了委托类的任意方法,再后面就是动态代理机制了,调用EventHandler的invoke就可以弹出计算器了。
写在最后
今天降温了,天冷吃个火锅
版权归原作者 Judassss 所有, 如有侵权,请联系我们删除。