内存马的错误参数获取,导致原有接口失效解决方案
字数 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();
}
}
问题重现
- 正常情况下,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函数实现精确清除:
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();
}
}
总结
- 内存马中调用
request.getParameter()会先实例化请求参数 - 这会导致某些框架(如Jersey)后续无法读取请求参数
- 解决方案是避免在内存马中使用会读取请求体的方法
- 可以使用URI、请求头等不涉及请求体读取的方式实现过滤功能
最佳实践建议
- 在开发内存马时,应充分测试对目标应用的影响
- 优先选择不影响原有业务逻辑的实现方式
- 对于需要检测请求参数的场景,考虑使用非侵入式方法
- 定期检查并清理不必要的内存马,避免积累导致系统不稳定