一种另类的shiro检测方式
字数 1650 2025-08-10 08:29:04
Apache Shiro 反序列化漏洞检测技术深度解析
0x00 前言
Apache Shiro 是一个广泛使用的 Java 安全框架,其反序列化漏洞自2016年存在,但在近年攻防演练(HVV)中备受关注。本文将深入剖析 Shiro 的检测原理,并提出一种创新的检测方法,相比传统方式具有更高准确性和可靠性。
0x01 传统检测方法分析
1.1 常规检测方式
目前业界普遍采用的 Shiro 检测方法是在请求 Cookie 中添加 rememberMe=1,然后检查响应中是否出现 rememberMe=deleteMe。这种方法的原理基于 Shiro 对 rememberMe 机制的处理流程。
1.2 传统方法的局限性
传统检测存在以下问题:
- 依赖 DNSLOG 进行外联验证
- 使用 Commons Collections 链进行盲测时可能存在误判
- 无法覆盖所有可能的 gadget 利用场景
0x02 Shiro 处理机制深度分析
2.1 核心处理流程
Shiro 对 rememberMe 的处理主要在 AbstractRememberMeManager#getRememberedPrincipals 方法中:
public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
PrincipalCollection principals = null;
try {
byte[] bytes = this.getRememberedSerializedIdentity(subjectContext);
if (bytes != null && bytes.length > 0) {
principals = this.convertBytesToPrincipals(bytes, subjectContext);
}
} catch (RuntimeException var4) {
principals = this.onRememberedPrincipalFailure(var4, subjectContext);
}
return principals;
}
2.2 密钥错误时的处理流程
当密钥错误时,解密过程会抛出异常:
- 进入
AbstractRememberMeManager#decrypt方法 - 调用
cipherService.decrypt()失败 - 抛出异常被
getRememberedPrincipals捕获 - 执行
onRememberedPrincipalFailure方法 - 最终调用
forgetIdentity方法添加deleteMe标记
关键代码路径:
protected PrincipalCollection onRememberedPrincipalFailure(RuntimeException e, SubjectContext context) {
// 日志记录
this.forgetIdentity(context);
throw e;
}
private void forgetIdentity(HttpServletRequest request, HttpServletResponse response) {
getCookie().removeFrom(request, response);
}
2.3 反序列化失败的处理
即使密钥正确,如果反序列化对象不符合要求,也会导致异常:
convertBytesToPrincipals调用deserialize方法- 反序列化后尝试转换为
PrincipalCollection类型 - 如果类型不匹配,抛出
ClassCastException - 同样进入异常处理流程,添加
deleteMe标记
0x03 创新检测方法原理
3.1 检测思路
基于上述分析,可以设计一种更可靠的检测方法,需满足两个条件:
- 构造一个继承
PrincipalCollection的可序列化对象 - 确保密钥正确时不返回
deleteMe,错误时返回deleteMe
3.2 关键实现类
SimplePrincipalCollection 类完美符合要求:
- 实现了
Serializable接口 - 继承自
PrincipalCollection - 是 Shiro 内置类,兼容性有保障
0x04 检测工具实现
4.1 序列化对象构造
生成检测 payload 的 Java 代码:
SimplePrincipalCollection simplePrincipalCollection = new SimplePrincipalCollection();
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("payload"));
obj.writeObject(simplePrincipalCollection);
obj.close();
4.2 检测流程
- 将
SimplePrincipalCollection对象序列化 - 使用目标密钥进行 AES 加密
- 构造 rememberMe Cookie 发送请求
- 分析响应:
- 无
deleteMe:密钥正确 - 有
deleteMe:密钥错误
- 无
4.3 优势分析
相比传统方法,该技术具有:
- 不依赖外部 DNSLOG
- 不依赖特定 gadget 链
- 误报率更低
- 完全基于 Shiro 自身机制
0x05 防御建议
针对该检测方法,防御措施包括:
- 升级到最新 Shiro 版本
- 禁用 rememberMe 功能(如非必要)
- 使用自定义密钥而非默认密钥
- 实现 Web 应用防火墙规则过滤异常请求
0x06 总结
本文深入分析了 Shiro 反序列化漏洞的检测原理,提出了一种基于 SimplePrincipalCollection 的创新检测方法。该方法通过利用 Shiro 自身机制,实现了更准确、更可靠的密钥检测,为安全研究人员提供了新的技术思路。