对shiro 550和721的漏洞原理学习
字数 1647 2025-08-10 13:48:19

Apache Shiro 反序列化漏洞深入分析(CVE-2016-4437 Shiro-550 & CVE-2019-12422 Shiro-721)

1. Shiro-550 漏洞分析

1.1 漏洞原理

Shiro-550(CVE-2016-4437)是一个反序列化漏洞,其核心问题在于:

  1. 硬编码密钥:Shiro框架使用了硬编码的AES加密密钥(kPH+bIxk5D2deZiIxcaaaA==
  2. 不安全的RememberMe功能:Shiro接受Cookie中的rememberMe参数,进行以下危险操作:
    • Base64解码
    • AES解密(使用硬编码密钥)
    • 反序列化解密后的数据

1.2 漏洞触发流程

  1. 攻击者构造恶意序列化对象
  2. 使用硬编码密钥进行AES加密
  3. 将加密结果进行Base64编码
  4. 放入Cookie的rememberMe字段发送给服务器
  5. 服务器端处理流程:
    AbstractRememberMeManager#getRememberedPrincipals
       CookieRememberMeManager#getRememberedSerializedIdentity (Base64解码)
       convertBytesToPrincipals (AES解密 + 反序列化)
    

1.3 关键代码分析

// 硬编码密钥位置
public abstract class AbstractRememberMeManager implements RememberMeManager {
    private static final byte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");
    // ...
}

// 漏洞触发点
public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
    byte[] bytes = getRememberedSerializedIdentity(subjectContext); // 获取并Base64解码
    if (bytes != null && bytes.length > 0) {
        try {
            return convertBytesToPrincipals(bytes); // 解密+反序列化
        } catch (Exception e) {
            // ...
        }
    }
    return null;
}

1.4 影响版本

Apache Shiro 1.x < 1.2.5

1.5 利用限制与绕过

  1. 反序列化限制

    • Shiro重写了ObjectInputStream.resolveClass方法,使用ClassUtils.forName而非Class.forName
    • 导致非Java自身数组类无法加载(如CommonsCollections6中的Transformer数组)
  2. 绕过方法

    • 方法1:使用TemplatesImpl#newTransformer绕过
      // 利用链关键节点
      TemplatesImpl#newTransformer  getTransletInstance  ...  Runtime.exec
      
    • 方法2:使用TrAXFilter.class + Templates.class组合
    • 方法3:在没有CC组件时使用CB链
    • 方法4:通过JRMP协议绕过
      • 在VPS搭建JRMP服务端
      • 本地搭建JRMP客户端接收返回数据
      • 使用脚本进行Shiro加密处理

1.6 POC示例

// 生成恶意payload示例
public class ShiroPOC {
    public static void main(String[] args) throws Exception {
        byte[] payloads = new CommonsCollections6().getPayload("calc");
        AesCipherService aes = new AesCipherService();
        byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource ciphertext = aes.encrypt(payloads, key);
        System.out.println(ciphertext.toString()); // 输出加密后的rememberMe值
    }
}

1.7 修复方案

  1. Shiro 1.2.5版本修复:
    • 系统启动时生成新密钥
    • 允许用户手动配置cipherKey
    • 注意:如果用户设置的密钥泄漏或太简单,仍可能被攻击

2. Shiro-721 漏洞分析

2.1 漏洞原理

Shiro-721(CVE-2019-12422)是一个Padding Oracle攻击漏洞:

  1. 加密模式问题:RememberMe默认使用AES-128-CBC模式加密
  2. Padding Oracle漏洞:攻击者可以通过观察服务器的响应差异,逐步解密或加密任意数据

2.2 影响版本

Apache Shiro < 1.4.2

2.3 利用条件

  1. 获取一个有效的rememberMe值(合法用户的登录凭证)
  2. 服务器对Padding错误有可区分的响应

2.4 攻击步骤

  1. 获取合法rememberMe Cookie
  2. 使用Padding Oracle攻击工具:
    java -jar PaddingOracleAttack-1.0-SNAPSHOT.jar http://target.com
    
  3. 构造恶意反序列化payload
  4. 通过Padding Oracle攻击加密payload
  5. 替换rememberMe值发送给服务器

2.5 修复方案

  1. 升级到Shiro 1.4.2及以上版本
  2. 使用更安全的加密模式(如AES-GCM)

3. 防御建议

  1. 及时升级:使用Shiro最新版本
  2. 密钥管理
    • 不要使用默认密钥
    • 定期轮换密钥
    • 使用强随机生成的密钥
  3. 禁用RememberMe:如非必要,禁用此功能
  4. 输入过滤:对Cookie值进行严格校验
  5. 反序列化防护
    • 使用白名单控制可反序列化的类
    • 使用安全的ObjectInputStream实现

4. 工具推荐

  1. Shiro-550利用工具
    • ysoserial
    • shiro-exploit
  2. Shiro-721利用工具
    • PaddingOracleAttack
    • longofo师傅的项目

5. 总结

Shiro反序列化漏洞展示了框架安全设计的常见问题:

  • 硬编码凭证
  • 不安全的默认配置
  • 危险的功能实现

理解这些漏洞原理不仅有助于防御,也能提升安全开发意识。在实际开发中,应当遵循最小权限原则和安全默认值原则,避免类似漏洞的出现。

Apache Shiro 反序列化漏洞深入分析(CVE-2016-4437 Shiro-550 & CVE-2019-12422 Shiro-721) 1. Shiro-550 漏洞分析 1.1 漏洞原理 Shiro-550(CVE-2016-4437)是一个反序列化漏洞,其核心问题在于: 硬编码密钥 :Shiro框架使用了硬编码的AES加密密钥( kPH+bIxk5D2deZiIxcaaaA== ) 不安全的RememberMe功能 :Shiro接受Cookie中的rememberMe参数,进行以下危险操作: Base64解码 AES解密(使用硬编码密钥) 反序列化解密后的数据 1.2 漏洞触发流程 攻击者构造恶意序列化对象 使用硬编码密钥进行AES加密 将加密结果进行Base64编码 放入Cookie的rememberMe字段发送给服务器 服务器端处理流程: 1.3 关键代码分析 1.4 影响版本 Apache Shiro 1.x < 1.2.5 1.5 利用限制与绕过 反序列化限制 : Shiro重写了 ObjectInputStream.resolveClass 方法,使用 ClassUtils.forName 而非 Class.forName 导致非Java自身数组类无法加载(如CommonsCollections6中的Transformer数组) 绕过方法 : 方法1 :使用 TemplatesImpl#newTransformer 绕过 方法2 :使用TrAXFilter.class + Templates.class组合 方法3 :在没有CC组件时使用CB链 方法4 :通过JRMP协议绕过 在VPS搭建JRMP服务端 本地搭建JRMP客户端接收返回数据 使用脚本进行Shiro加密处理 1.6 POC示例 1.7 修复方案 Shiro 1.2.5版本修复: 系统启动时生成新密钥 允许用户手动配置cipherKey 注意 :如果用户设置的密钥泄漏或太简单,仍可能被攻击 2. Shiro-721 漏洞分析 2.1 漏洞原理 Shiro-721(CVE-2019-12422)是一个Padding Oracle攻击漏洞: 加密模式问题 :RememberMe默认使用AES-128-CBC模式加密 Padding Oracle漏洞 :攻击者可以通过观察服务器的响应差异,逐步解密或加密任意数据 2.2 影响版本 Apache Shiro < 1.4.2 2.3 利用条件 获取一个有效的rememberMe值(合法用户的登录凭证) 服务器对Padding错误有可区分的响应 2.4 攻击步骤 获取合法rememberMe Cookie 使用Padding Oracle攻击工具: 构造恶意反序列化payload 通过Padding Oracle攻击加密payload 替换rememberMe值发送给服务器 2.5 修复方案 升级到Shiro 1.4.2及以上版本 使用更安全的加密模式(如AES-GCM) 3. 防御建议 及时升级 :使用Shiro最新版本 密钥管理 : 不要使用默认密钥 定期轮换密钥 使用强随机生成的密钥 禁用RememberMe :如非必要,禁用此功能 输入过滤 :对Cookie值进行严格校验 反序列化防护 : 使用白名单控制可反序列化的类 使用安全的ObjectInputStream实现 4. 工具推荐 Shiro-550利用工具 : ysoserial shiro-exploit Shiro-721利用工具 : PaddingOracleAttack longofo师傅的项目 5. 总结 Shiro反序列化漏洞展示了框架安全设计的常见问题: 硬编码凭证 不安全的默认配置 危险的功能实现 理解这些漏洞原理不仅有助于防御,也能提升安全开发意识。在实际开发中,应当遵循最小权限原则和安全默认值原则,避免类似漏洞的出现。