初识weblogic
最后更新时间:
XMLDecoder反序列化
前置知识:
XMLDecoder主要支持SAX和DOM解析标准XML,前者将数据解析为时间流,后者构建它的对象。
DOM在解析时会先构建成一棵树,并进行遍历解析,易受到性能问题的影响。而SAX解析则是线性时间的,XMLDecoder在解析时采用SAX解析规范。
SAX
基于事件驱动的设计模式。拆分即有事件源和事件处理器以及对应的注册方法将两者连接起来
SAX对象使用
SAXParser.parer()
作为事件源,ContentHandler
、ErrorHandler
、DTDHandler
、EntityResolver
作为事件处理器XMLDecoder反序列化流程解析
T3协议
Weblogic RMI与JAVA RMI不同之处
WebLogic RMI支持集群部署和负载均衡
WebLogic RMI的服务端会使用字节码生成(Hot Code Generation)功能生成代理对象
因此不再需要
Skeleton
骨架对象以及UnicastRemoteObjec
t对象WebLogic RMI客户端使用动态代理
也是使用字节码生成功能,因此不需要
Stub
对象
T3协议特点
- 服务端可以持续追踪监控客户端是否存活(心跳机制),通常心跳的间隔为60秒,服务端在超过240秒未收到心跳即判定与客户端的连接丢失。
- 通过建立一次连接可以将全部数据包传输完成,优化了数据包大小和网络消耗。
下面进行抓包分析,先在服务器端部署jar包,里面是一个简单的demo
1 |
|
这里注意部署目录默认时域服务器下的lib目录,也就是/u01/app/oracle/Domains/ExampleSilentWTDomain/lib/
客户端如下(需要配合wlthint3client.jar以支持t3协议)
1 |
|
这里利用wireshark进行抓包分析
可以看到之前也会有一个tcp建立连接的阶段,客户端与服务器端双方会发送各自的版本信息,我们基于此可以进行weblogic的版本探测利用。开头可以构造形式如
1 |
|
这里可以看出T3协议由协议头包裹,且数据包中包含多个序列化的对象。因此我们的利用原理就是构造恶意对象并封装到数据包中重新发送了,送上流程图
配置调试环境
利用工具 https://github.com/QAX-A-Team/WeblogicEnvironment
注意iptables设置 idea设置远程调试
CVE-2015-4582
POC:
1 |
|
这里存在一个问题就是刚开始发送版本探测包的时候并不能正常返回服务端版本信息,然而用wireshark抓包却可以抓到完整的版本信息。初步推测可能和操作系统版本有关
利用CC1进行反序列化利用最终在/tmp
目录下生成success文件
漏洞分析
序列化数据进入的函数入口在
weblogic.rjvm.InboundMsgAbbrev#readObject()
,可以看到里面调用了InboundMsgAbbrev.ServerChannelInputStream#readObject()
进入该内部类,其继承于
ObjectInputStream
类,并重写了resolveClass()
方法,但是可以看到,其中仍会调用父类的方法且未作过滤检验。该方法也是原生反序列化漏洞的触发点关于resolveClass方法
从类序列化描述符获取类的Class对象。从类描述中获取到了全限定类名,然后利用反射根据全限定类名来获取到对应的 Class 对象并且进行返回。所以这里也是最好做防御的地方,检查一下该类的序列化描述符中记录的类名是否在黑名单上,如果在黑名单上,直接抛出错误,不允许获取恶意的类的Class对象。这样以来,恶意类连生成Class对象的机会都没有
修复方案
打补丁的方式:在
resolveClass
方法中实现拦截web代理的方式:只转发HTTP请求,不会转发T3协议的请求
负载均衡方式:与WEB代理类似,只接受HTTP请求的转发
CVE-2016-0638
绕过了resolveClass中黑名单限制
1 |
|
利用类weblogic.jms.common.StreamMessageImpl
中的readExternal()
,该方法对输入流进行了二次反序列化
利用 https://github.com/5up3rc/weblogic_cmd
工具分析
com.supeream.Main#executeBlind()
获取参数,然后执行WebLogicOperation.blindExecute()
其中给命令赋值,并根据参数os来决定使用的系统命令,接下来进入
SerialDataGenerator.serialBlindDatas()
首先会在
SerialDataGenerator#blindExecutePayloadTransformerChain()
构建恶意反序列化对象,可以看到就是构建的CC1利用链之后进入
serialData()
,继续构造CC1链。之后进入BypassPayloadSelector.selectBypass()
这里可以看到我们熟悉的用来绕过黑名单的利用类streamMessageImpl,如果Main.TYPE参数未指明,那么默认就是streamMessageImpl。
同时,这里可以看到会先对payload对象进行一次序列化,并封装到streamMessageImpl的buffer属性数组当中
进一步,会再对streamMessageImpl对象进行一次序列化,形成最终的JAVA序列化数据
最终会在
T3ProtocolOperation#send()
中将JAVA序列化数据拼接如T3协议数据中,与前面漏洞的构造原理一致服务端部分分析
刚开始与之前的漏洞调用过程一致,也会进入
InboundMsgAbbrev.ServerChannelInputStream()
由于我这里没有用的补丁调试,所以看不出黑名单的拦截过程。但是最终会通过到
StreamMessageImpl#readExternal
,而不再走之前ServerChannelInputStream中readObject之后的路,后者设置了一系列黑名单拦截。而在StreamMessageImpl#readExternal()
中会进一步调用本身的readObject进行二次反序列化(也就是我们之前序列化时的buffer数组中的内容),最终触发CC1整体调用栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16- readObject:331, AnnotationInvocationHandler (sun.reflect.annotation)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
invokeReadObject:1004, ObjectStreamClass (java.io)
readSerialData:1891, ObjectInputStream (java.io)
readOrdinaryObject:1796, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
readObject:370, ObjectInputStream (java.io)
- readExternal:1419, StreamMessageImpl (weblogic.jms.common)
readExternalData:1835, ObjectInputStream (java.io)
readOrdinaryObject:1794, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
readObject:370, ObjectInputStream (java.io)
readObject:66, InboundMsgAbbrev (weblogic.rjvm)
CVE-2016-3510
与CVE-2016-0638原理一致,都是基于黑名单的绕过。这里用的是weblogic.corba.utils.MarshalledObject
类
我们还是先看exp,其因为TYPE改成了marshall,所以会将payload(也就是恶意AnnotationInvocationHandler对象)作为参数传入marshalledObject方法。
跟入可以看到序列化的恶意payload会被写入objBytes成员变量中
反序列化分析
weblogic.corba.utils.MarshalledObject这个类没有实现readObject或者readExternal函数,所以在反序列化的时候采用ObjectInputStream的默认流程。但这个流程会调用辅助类ObjectStreamClass的invokeReadResolve函数,后者会调用MarshalledObject的readResolve函数,查看readResolve我们会发现,readResolve中有readObject的调用,而其参数正来自其本身的objBytes变量
调用链如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20readObject:331, AnnotationInvocationHandler (sun.reflect.annotation)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
invokeReadObject:1004, ObjectStreamClass (java.io)
readSerialData:1891, ObjectInputStream (java.io)
readOrdinaryObject:1796, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
readObject:370, ObjectInputStream (java.io)
readResolve:58, MarshalledObject (weblogic.corba.utils)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
invokeReadResolve:1091, ObjectStreamClass (java.io)
readOrdinaryObject:1805, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
readObject:370, ObjectInputStream (java.io)
readObject:66, InboundMsgAbbrev (weblogic.rjvm)
参考链接
http://wjlshare.com/archives/1573
https://www.anquanke.com/post/id/226070#h2-15
https://y4er.com/posts/weblogic-cve-2016-0638/#exp%E5%88%86%E6%9E%90