JSP型内存马的原理学习与实现
字数 2088 2025-08-10 13:48:29
JSP型内存马原理与实现详解
前言
JSP型内存马是一种基于Tomcat容器的持久化后门技术,它通过操纵JSP的加载和执行流程来实现隐蔽驻留。本文将系统性地分析JSP型内存马的实现原理和技术细节。
JSP执行流程概述
理解JSP型内存马的前提是掌握Tomcat下JSP的执行过程:
- 用户请求一个JSP页面
- JSP容器将JSP页面转换为Servlet源码
- 将转换后的Java源码编译成.class字节码
- 加载编译后的.class并执行逻辑
- 将执行结果返回给用户端
JSP加载流程深入分析
1. 请求处理入口
请求首先经过一系列Filter,然后传递给JspServlet#service方法处理:
- 获取JSP请求的URL信息和调试模式日志打印
- 通过
preCompile方法判断是否对请求资源进行预编译 PRECOMPILE常量是jsp_precompile,只有在请求JSP页面带有jsp_precompile查询参数时才会预编译
2. JSP处理核心方法
调用serviceJspFile方法处理JSP请求:
-
调用
JspRuntimeContext#getWrapper获取请求JSP对应的wrapper- 首次访问返回null,会创建新的
JspServletWrapper对象 - 将新创建的wrapper添加到
JspServletWrapper类的jsps属性中 - 会先检查JSP资源是否存在,不存在则抛出异常
- 首次访问返回null,会创建新的
-
JspServletWrapper是Servlet的包装类,所有注册的JSP Servlet都存放在rctxt中
3. JSP编译过程
JspServletWrapper#service方法中的关键编译环节:
- 在满足
this.options.getDevelopment() || this.mustCompile条件时进入编译环节 - 默认使用
org.apache.jasper.compiler.JDTCompiler编译器 - 通过
isOutDated方法判断是否需要重新编译 - 删除已存在的.java和.class文件(首次访问时不存在)
- 调用
JDTCompiler#compile进行编译:generateJava方法生成请求资源的Java代码generateClass方法编译Java代码
- 编译完成后将
mustCompile属性置为false
4. JSP Servlet注册
调用JspServletWrapper#getServlet方法进行JSP Servlet注册:
-
判断
this.getReloadInternal() || this.theServlet == nulltheServlet用于判断Servlet是否存在(首次访问为null)destroy方法用于销毁Servlet
-
创建Servlet实例:
InstanceManager instanceManager = InstanceManagerFactory.getInstanceManager(this.config);
servlet = (Servlet)instanceManager.newInstance(this.ctxt.getFQCN(), this.ctxt.getJspLoader());
- 初始化JSP Servlet
- 将创建好的Servlet保存在
theServlet属性中 - 最后调用
servlet#service方法处理请求
JSP型内存马实现原理
要实现一个有效的JSP型内存马,必须满足以下条件:
- 持久化能力:能够在服务器重启后仍然存在
- 隐蔽性:不依赖磁盘上的JSP文件,避免被常规扫描发现
- 动态加载:能够动态注册并执行恶意代码
- 访问触发:通过正常请求路径触发执行
关键技术点
-
动态注册JSP Servlet:
- 通过操纵
JspRuntimeContext注册恶意Servlet - 绕过正常的JSP文件检查机制
- 通过操纵
-
内存驻留:
- 将恶意代码直接注入到内存中的Servlet实例
- 避免生成物理JSP文件
-
请求路由:
- 将特定路径映射到恶意Servlet
- 保持与正常JSP请求相同的处理流程
实现步骤
-
获取JSP运行时环境:
- 通过反射获取
JspRuntimeContext实例 - 获取当前应用的Servlet上下文
- 通过反射获取
-
创建恶意Servlet包装类:
- 继承或模拟
JspServletWrapper行为 - 实现自定义的编译和加载逻辑
- 继承或模拟
-
注册恶意Servlet:
- 将恶意wrapper添加到
jsps集合中 - 确保能够通过正常URL访问
- 将恶意wrapper添加到
-
实现恶意功能:
- 在Servlet的
service方法中植入后门逻辑 - 支持命令执行、文件操作等功能
- 在Servlet的
防御措施
-
运行时监控:
- 监控异常的Servlet注册行为
- 检查
JspRuntimeContext中的可疑wrapper
-
静态分析:
- 扫描内存中的Servlet实例
- 检查是否有未对应物理JSP文件的Servlet
-
安全加固:
- 限制JSP编译功能
- 禁用不必要的Servlet API
-
行为检测:
- 监控异常的JSP请求处理流程
- 检测绕过正常编译流程的行为
总结
JSP型内存马通过深入理解Tomcat的JSP处理机制,操纵JSP的编译和Servlet注册过程,实现了在内存中驻留恶意代码的能力。防御此类攻击需要从静态检测和动态监控两方面入手,重点关注JSP处理流程中的异常行为。