WebLogic反序列化之CVE-2015-4852、CVE-2016-0638、CVE-2016-3510

本文详细介绍了WebLogic反序列化漏洞,包括CVE-2015-4852、CVE-2016-0638和CVE-2016-3510,重点分析了T3协议、数据流到Object的过程,以及这三个CVE的利用链。文章探讨了WebLogic RMI的特性,揭示了利用恶意序列化数据启动荷载Class的方法,展示了如何通过T3协议插入恶意序列化数据并触发漏洞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WebLogic反序列化之CVE-2015-4852、CVE-2016-0638、CVE-2016-3510

CVE-2015-4852CVE-2016-0638CVE-2016-3510这3个CVE常常被拿到一起来讲,因为后2个CVE都是以CVE-2015-4852利用链为基础建立的。

按照我对反序列化利用链的理解,包含2个部分:

  1. 承担恶意代码的荷载Class
  2. 启动荷载Class启动Class或者启动机制

CVE-2015-4852的荷载Class就是较为熟知的Apache CC利用链,关于CC利用链的分析文章很多,就不在这里写了。放一篇我关于CC1的文章ysoserial gadget Commons-Collections1保姆级分析,核心就是ChainedTransformerConstantTransformerInvokerTransformer

关于承担恶意代码的荷载Class就到此为止,而怎么启动荷载,就需要先了解WebLogicT3协议。因为WebLogic通过读取数据包里T3协议格式的序列化数据然后将其反序列化得到Object

T3协议是WebLogic RMI使用的协议,是JRMP的强化版。

T3协议

WebLogic RMI就是WebLogic对Java RMI的实现,在功能和实现方式上稍有不同。我们来细数一下WebLogic RMIJava RMI的不同之处。

  • WebLogic RMI支持集群部署和负载均衡。

因为WebLogic本身就是为分布式系统设计的,因此WebLogic RMI支持集群部署和负载均衡也不难理解了。

  • WebLogic RMI的服务端会使用字节码生成(Hot Code Generation)功能生成代理对象。

WebLogic的字节码生成功能会自动生成服务端的字节码到内存。不再生成Skeleton骨架对象,也不需要使用UnicastRemoteObject对象。

  • WebLogic RMI客户端使用动态代理。

WebLogic RMI客户端中,字节码生成功能会自动为客户端生成代理对象,因此Stub也不再需要。

  • WebLogic RMI主要使用T3协议(还有基于CORBAIIOP协议)进行客户端到服务端的数据传输。

T3传输协议是WebLogic的自有协议,它有如下特点:

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

关于T3协议我本来想找一下有没有详细的定义,但是百度Google都没有找到,直到看到SeeBug里有篇文章说因为WebLogic闭源的原因就没有T3协议规则这方面的资料。不过网上对应Poc利用部分的T3协议分析倒是有。

具体分析参考漏洞原理weblogic t3 协议利用与防御

  • 发现每个数据包里不止包含一个序列化魔术头。(0xac 0xed 0x00 0x05)
  • 每个序列化数据包前面都有相同的二进制串。(0xfe 0x01 0x00 0x00)
  • 每个数据包上面都包含了一个T3协议头。
  • 仔细看协议头部分,发现数据包的前4个字节正好对应着数据包长度
  • 以及我们也能发现包长度后面的01代表请求,02代表返回。

这些点说明了T3协议由协议头包裹,且数据包中包含多个序列化的对象。

现在知道了T3协议的格式,那么接下来有2种思路

  1. 替换数据包中多个序列化对象任意一个为恶意序列化数据

  2. weblogic发送的JAVA序列化数据的第一部分与恶意序列化数据进行拼接。

其实在我看来是一个意思,无非是选择替换第几个正常序列化部分

网上的payload都是直接替换第1个序列化对象,我参考的Poc是这个Weblogic_direct_T3_Rces

搞清楚怎么在T3协议数据流中加入恶意序列化数据后,接下来就可以说一说服务端是如何反序列化恶意数据并启动CC链。

从数据流到Object

Weblogic通过7001端口,获取到流量中T3协议的java反序列化数据。

通过调用栈,可以发现Weblogic最后通过ObjectInputStream读入序列化数据,并在readClassDesc(boolean unshared)方法中拿到类描述符来确定字节流中传递数据的类型,并交给对应的方法进行处理。

//ObjectInputStream.java
/**
 * Reads in and returns (possibly null) class descriptor.  Sets passHandle
 * to class descriptor's assigned handle.  If class descriptor cannot be
 * resolved to a class in the local VM, a ClassNotFoundException is
 * associated with the class descriptor's handle.
 */
private ObjectStreamClass readClassDesc(boolean unshared)
    throws IOException
{
   
   
    byte tc = bin.peekByte();
    ObjectStreamClass descriptor;
    switch (tc) {
   
   
        case TC_NULL:
            descriptor = (ObjectStreamClass) readNull();
            break;
        case TC_REFERENCE:
            descriptor = (ObjectStreamClass) readHandle(unshared);
            break;
        case TC_PROXYCLASSDESC:
            descriptor = readProxyDesc(unshared);
            break;
        case TC_CLASSDESC:
            descriptor = readNonProxyDesc(unshared); //进这里
            break;
        default:
            throw new StreamCorruptedException(
                String.format("invalid type code: %02X", tc));
    }
    if (descriptor != null) {
   
   
        validateDescriptor(descriptor);
    }
    return descriptor;
}

这里会走case TC_CLASSDES,在readNonProxyDesc()里通过readClassDescriptor()拿到描述符并作为参数传给resolveClass(readDesc)方法拿到相对应的Class对象,最后通过desc.initNonProxy()初始化。

//ObjectInputStream.java
/**
 * Reads in and returns class descriptor for a class that is not a dynamic
 * proxy class.  Sets passHandle to class descriptor's assigned handle.  If
 * class descriptor cannot be resolved to a class in the local VM, a
 * ClassNotFoundException is associated with the descriptor's handle.
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值