协商部分
WebLogic 中的RMI通信是使用 T3 协议来传输序列化数据的,可以看成是原生 RMI 使用的 JRMP 协议的定制版。T3 协议的数据包分为请求头和请求体两部分,请求头形如:
HL 头标识后面发起的 T3 协议头长度;AS 头用来标识 T3 反序列化时用的 stack 的容量。
响应形如:
注意请求响应都以\n\n
结尾,且响应包中包含 WebLogic 的版本号。
协议头部
请求主体分为 7 个部分,第 1 部分为协议头,它的前 19 字节(前面 HL 的值)包含一些重要字段。
cmd | 请求类型 |
---|---|
QOS | ? |
flag | 标识位 |
responseId | 标识 TCP 流不同请求的顺序,从 -1 开始,作用类似 TCP 的 SYN |
invokeableId | 服务端将根据这个字段的值去查找响应的处理程序 |
abbrevOffset | abbrev 这个数据结构在本次请求中相对于开始部分的偏移 |
T3 Abbrev
MsgAbbrevs 结构体,这个数据结构我不能很好的描述它,因为 T3 协议并没有全部实现 java 反序列化协议,而是自己由魔改了一部分。比如 readClassDescriptor 的 class 部分,T3 协议在 abbrevs 中读取。
这里将会跳转到 abbrevOffset 标识的部分并开始读取数据。代码如下:
首先读取 msgAbbrev 的数量。然后再读取 length ,如果 length大于本次 T3 请求中存放 abbrev 的容量,则读取对象,否则读取值。而本次 T3 请求的 abbrev 的容量,就是由前面协议协商的 AS 标识的值,默认为 255。
TODO T3 Context
剩下的 6 个部分是 Java 的序列化数据,以ac ed 00 05
开头。那么对 WebLogic 实施反序列化攻击可以有两个思路:将某个序列化部分替换成 payload ,或者在第 1部分后面拼接 payload。