Shiro反序列化源码分析学习
字数 1499 2025-08-18 11:35:59

Shiro反序列化漏洞深入分析与利用教学

1. 漏洞概述

Shiro是一个Java安全框架,提供身份验证、授权、密码学和会话管理功能。Shiro550(CVE-2016-4437)和Shiro721(CVE-2019-12422)是两个著名的反序列化漏洞:

  • Shiro550:由于使用硬编码的AES加密密钥导致的反序列化漏洞
  • Shiro721:Padding Oracle攻击导致的身份验证绕过漏洞

2. 环境搭建

  1. 使用Vulhub搭建测试环境:
git clone https://github.com/vulhub/vulhub.git
cd vulhub/shiro/CVE-2016-4437
docker-compose up -d
  1. 获取运行中的JAR包:
docker ps  # 获取容器ID
docker cp <container_id>:/path/to/shirodemo-1.0-SNAPSHOT.jar .
  1. 使用IDEA分析:
  • 创建项目
  • 新建libs目录并放入JAR包
  • 右键libs目录选择"Add as Library"

3. 漏洞分析流程

3.1 路由分析

通过MANIFEST.MF文件找到入口类,分析UserController

@Controller
public class UserController {
    @PostMapping({"/doLogin"})
    public String doLoginPage(@RequestParam("username") String username, 
                            @RequestParam("password") String password,
                            @RequestParam(name = "rememberme", defaultValue = "") String rememberMe) {
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(username, password, rememberMe.equals("remember-me")));
            return "forward:/";
        } catch (AuthenticationException var6) {
            return "forward:/login";
        }
    }
    // 其他路由方法...
}

关键点:

  • rememberme参数控制是否启用"记住我"功能
  • UsernamePasswordToken构造方法处理认证信息

3.2 认证流程分析

  1. Subject创建
Subject subject = SecurityUtils.getSubject();
  1. 登录流程
subject.login(new UsernamePasswordToken(...));
  1. 深入login方法
  • 进入DelegatingSubject类的login方法
  • 调用securityManager.login(this, token)
  1. 认证过程
  • DefaultSecurityManager.authenticate()
  • AbstractAuthenticator.doAuthenticate()
  • AuthenticatingRealm.getAuthenticationInfo()

3.3 反序列化触发点

关键路径:

  1. DefaultSecurityManager.createSubject()
  2. DefaultSecurityManager.resolvePrincipals()
  3. DefaultSecurityManager.getRememberedIdentity()
  4. AbstractRememberMeManager.getRememberedPrincipals()

关键代码:

public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
    byte[] bytes = this.getRememberedSerializedIdentity(subjectContext);
    if (bytes != null && bytes.length > 0) {
        return this.convertBytesToPrincipals(bytes, subjectContext);
    }
}

3.4 漏洞核心

  1. 数据处理流程

    • 从Cookie获取rememberMe
    • Base64解码
    • AES解密(使用硬编码密钥)
    • 反序列化解密后的数据
  2. 硬编码密钥

public AbstractRememberMeManager() {
    this.serializer = new DefaultSerializer();
    this.cipherService = new AesCipherService();
    this.setCipherKey(DEFAULT_CIPHER_KEY_BYTES);  // 硬编码密钥
}
  1. 反序列化点
protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext context) {
    bytes = this.decrypt(bytes);  // AES解密
    return this.deserialize(bytes);  // 反序列化
}

4. 漏洞利用

4.1 利用工具

使用ShiroAttack2工具:

java -jar shiro_attack-4.7.0-SNAPSHOT-all.jar

4.2 利用步骤

  1. 检测Shiro框架
  2. 使用内置密钥检测
  3. 选择利用链(如CommonsBeanutils1)
  4. 构造恶意序列化对象
  5. 执行命令

4.3 Debug验证

  1. 启动应用并附加调试器:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=65500 -jar shirodemo-1.0-SNAPSHOT.jar
  1. 关键断点设置:
  • AbstractRememberMeManager.getRememberedPrincipals()
  • AbstractRememberMeManager.convertBytesToPrincipals()
  • AbstractRememberMeManager.decrypt()
  • AbstractRememberMeManager.deserialize()

5. 漏洞修复

  1. 升级到最新版本(≥1.2.5)
  2. 自定义加密密钥:
public class CustomRememberMeManager extends CookieRememberMeManager {
    public CustomRememberMeManager() {
        setCipherKey(Base64.decode("your_random_base64_encoded_key"));
    }
}
  1. 配置Shiro:
@Bean
public SecurityManager securityManager() {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRememberMeManager(new CustomRememberMeManager());
    return securityManager;
}

6. 总结

Shiro550漏洞的核心在于:

  1. 使用硬编码AES密钥(kPH+bIxk5D2deZiIxcaaaA==
  2. 对用户控制的rememberMe cookie值进行反序列化
  3. 缺乏对反序列化对象的白名单校验

通过分析这个漏洞,我们可以学习到:

  • Java反序列化漏洞的原理
  • Shiro框架的认证流程
  • 加密机制的安全实现
  • 漏洞挖掘和利用的思路
Shiro反序列化漏洞深入分析与利用教学 1. 漏洞概述 Shiro是一个Java安全框架,提供身份验证、授权、密码学和会话管理功能。Shiro550(CVE-2016-4437)和Shiro721(CVE-2019-12422)是两个著名的反序列化漏洞: Shiro550 :由于使用硬编码的AES加密密钥导致的反序列化漏洞 Shiro721 :Padding Oracle攻击导致的身份验证绕过漏洞 2. 环境搭建 使用Vulhub搭建测试环境: 获取运行中的JAR包: 使用IDEA分析: 创建项目 新建libs目录并放入JAR包 右键libs目录选择"Add as Library" 3. 漏洞分析流程 3.1 路由分析 通过 MANIFEST.MF 文件找到入口类,分析 UserController : 关键点: rememberme 参数控制是否启用"记住我"功能 UsernamePasswordToken 构造方法处理认证信息 3.2 认证流程分析 Subject创建 : 登录流程 : 深入 login 方法 : 进入 DelegatingSubject 类的 login 方法 调用 securityManager.login(this, token) 认证过程 : DefaultSecurityManager.authenticate() AbstractAuthenticator.doAuthenticate() AuthenticatingRealm.getAuthenticationInfo() 3.3 反序列化触发点 关键路径: DefaultSecurityManager.createSubject() DefaultSecurityManager.resolvePrincipals() DefaultSecurityManager.getRememberedIdentity() AbstractRememberMeManager.getRememberedPrincipals() 关键代码: 3.4 漏洞核心 数据处理流程 : 从Cookie获取 rememberMe 值 Base64解码 AES解密(使用硬编码密钥) 反序列化解密后的数据 硬编码密钥 : 反序列化点 : 4. 漏洞利用 4.1 利用工具 使用 ShiroAttack2 工具: 4.2 利用步骤 检测Shiro框架 使用内置密钥检测 选择利用链(如CommonsBeanutils1) 构造恶意序列化对象 执行命令 4.3 Debug验证 启动应用并附加调试器: 关键断点设置: AbstractRememberMeManager.getRememberedPrincipals() AbstractRememberMeManager.convertBytesToPrincipals() AbstractRememberMeManager.decrypt() AbstractRememberMeManager.deserialize() 5. 漏洞修复 升级到最新版本(≥1.2.5) 自定义加密密钥: 配置Shiro: 6. 总结 Shiro550漏洞的核心在于: 使用硬编码AES密钥( kPH+bIxk5D2deZiIxcaaaA== ) 对用户控制的rememberMe cookie值进行反序列化 缺乏对反序列化对象的白名单校验 通过分析这个漏洞,我们可以学习到: Java反序列化漏洞的原理 Shiro框架的认证流程 加密机制的安全实现 漏洞挖掘和利用的思路