内存马的错误参数获取,导致原有接口失效解决方案
字数 1186 2025-08-22 18:37:22

内存马错误参数获取导致接口失效问题分析与解决方案

问题概述

在Java Listener类型内存马中,当使用request.getParameter(String name)方法获取请求参数来判断恶意请求时,会导致某些框架(如Jersey)无法正常接收参数,从而使原有接口失效。

环境示例

正常环境

  • SpringBoot MVC + Jersey RESTApi
  • 示例接口代码:
@Path("/")
public class JerseyMultiValueMapController {
    @POST
    @Path("/demo")
    @Consumes("application/x-www-form-urlencoded")
    public Response demo(MultivaluedMap<String, String> formData) {
        formData.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value));
        String result = "Processed data";
        return Response.ok(result).build();
    }
}

问题重现

  1. 正常情况下,Jersey框架使用MultivaluedMap可以正常接收参数
  2. 注入Listener类型内存马后(使用北辰的GodzillaMemoryShellProject)
  3. 内存马中使用了request.getParameter()方法
  4. 注入后,同样的请求无法接收到请求参数

技术原理分析

根本原因

  1. request.getParameter()和Jersey框架实例化参数时都会从CoyoteInputStream数据流读取数据
  2. 关键点:CoyoteInputStream只能被读取一次
  3. 当内存马先调用getParameter()时:
    • 先读取了CoyoteInputStream中的数据
    • 导致Jersey框架实例化请求参数时无法再读取到数据

关键代码路径

  1. request.getParameter调用链:

    • 定位到org.apache.catalina.connector.Request#readPostBodyFully
    • 使用的this.getStream()CoyoteInputStream
  2. Jersey框架读取路径:

    • 定位到org.glassfish.jersey.message.internal.ReaderWriter#readFromAsString
    • 同样使用CoyoteInputStream

解决方案

替代方案

避免在内存马中使用request.getParameter()方法获取参数,改用其他方式:

  1. 使用URI进行过滤处理
  2. 使用User-Agent等请求头信息
  3. 其他不涉及读取请求体的方式

内存马检测与清除

  1. 使用内存马检测工具(如zzhorc的tomcat_memshell_scanner)
  2. 修改deleteListener函数实现精确清除:
public synchronized void deleteListener(HttpServletRequest request, String listenerName) {
    try {
        List<Object> arrayList_listeners = getListenerList(request);
        for (int i = 0; i < arrayList_listeners.size();) {
            if (arrayList_listeners.get(i).getClass().getName().equals(listenerName)){
                arrayList_listeners.remove(i);
                continue;
            }
            i++;
        }
    } catch (Exception e){
        e.printStackTrace();
    }
}

总结

  1. 内存马中调用request.getParameter()会先实例化请求参数
  2. 这会导致某些框架(如Jersey)后续无法读取请求参数
  3. 解决方案是避免在内存马中使用会读取请求体的方法
  4. 可以使用URI、请求头等不涉及请求体读取的方式实现过滤功能

最佳实践建议

  1. 在开发内存马时,应充分测试对目标应用的影响
  2. 优先选择不影响原有业务逻辑的实现方式
  3. 对于需要检测请求参数的场景,考虑使用非侵入式方法
  4. 定期检查并清理不必要的内存马,避免积累导致系统不稳定
内存马错误参数获取导致接口失效问题分析与解决方案 问题概述 在Java Listener类型内存马中,当使用 request.getParameter(String name) 方法获取请求参数来判断恶意请求时,会导致某些框架(如Jersey)无法正常接收参数,从而使原有接口失效。 环境示例 正常环境 SpringBoot MVC + Jersey RESTApi 示例接口代码: 问题重现 正常情况下,Jersey框架使用 MultivaluedMap 可以正常接收参数 注入Listener类型内存马后(使用北辰的GodzillaMemoryShellProject) 内存马中使用了 request.getParameter() 方法 注入后,同样的请求无法接收到请求参数 技术原理分析 根本原因 request.getParameter() 和Jersey框架实例化参数时都会从 CoyoteInputStream 数据流读取数据 关键点: CoyoteInputStream 只能被读取一次 当内存马先调用 getParameter() 时: 先读取了 CoyoteInputStream 中的数据 导致Jersey框架实例化请求参数时无法再读取到数据 关键代码路径 request.getParameter 调用链: 定位到 org.apache.catalina.connector.Request#readPostBodyFully 使用的 this.getStream() 是 CoyoteInputStream Jersey框架读取路径: 定位到 org.glassfish.jersey.message.internal.ReaderWriter#readFromAsString 同样使用 CoyoteInputStream 解决方案 替代方案 避免在内存马中使用 request.getParameter() 方法获取参数,改用其他方式: 使用URI进行过滤处理 使用User-Agent等请求头信息 其他不涉及读取请求体的方式 内存马检测与清除 使用内存马检测工具(如zzhorc的tomcat_ memshell_ scanner) 修改 deleteListener 函数实现精确清除: 总结 内存马中调用 request.getParameter() 会先实例化请求参数 这会导致某些框架(如Jersey)后续无法读取请求参数 解决方案是避免在内存马中使用会读取请求体的方法 可以使用URI、请求头等不涉及请求体读取的方式实现过滤功能 最佳实践建议 在开发内存马时,应充分测试对目标应用的影响 优先选择不影响原有业务逻辑的实现方式 对于需要检测请求参数的场景,考虑使用非侵入式方法 定期检查并清理不必要的内存马,避免积累导致系统不稳定