任意类加载环境下注入内存马
字数 1444 2025-08-29 22:41:24

任意类加载环境下注入内存马技术研究

1. 内存马注入基础原理

在JVM中,每个类都有其所属的类加载器。在Java内存马注入场景下,攻击者通常会:

  1. 制作一个恶意类
  2. 通过ClassLoader.defineClass方法注入到JVM中
  3. 通过特定方法注册到Web组件上以供访问

传统的内存马注入方式存在以下问题:

  • 依赖Thread.currentThread().getContextClassLoader(),这在非请求线程中会失败
  • 某些场景下context.getClass().getClassLoader()不可行

2. 类加载器选择问题

2.1 传统方法的局限性

常见的类加载器获取方式:

// 方式1:上下文类加载器
Thread.currentThread().getContextClassLoader()

// 方式2:context的类加载器
context.getClass().getClassLoader()

这些方法存在以下问题:

  1. 上下文类加载器依赖请求线程,在非请求线程中不可用
  2. 某些中间件环境下context.getClass().getClassLoader()无法正常工作

2.2 类加载器选择优化

研究发现,在Tomcat环境中,类加载遵循以下规则:

  1. 类名以org.apache.catalina.开头的由当前class的类加载器加载
  2. 其他类使用context.getLoader().getClassLoader()加载

关键代码片段(Tomcat5):

// org.apache.catalina.core.ApplicationFilterConfig#getFilter
if (filterClass.startsWith("org.apache.catalina.")) {
    cl = ApplicationFilterConfig.class.getClassLoader();
} else {
    cl = context.getLoader().getClassLoader();
}

3. Servlet规范中的类加载机制

研究发现Servlet规范(3.0+)中定义了ServletContext#getClassLoader方法,用于获取与应用相关联的ClassLoader。

Tomcat实现:

// org.apache.catalina.core.ApplicationContext
@Override
public ClassLoader getClassLoader() {
    return context.getLoader().getClassLoader();
}

其他中间件实现:

  • Undertow: io.undertow.servlet.spec.ServletContextImpl#getClassLoader
  • Jetty: org.eclipse.jetty.server.handler.ContextHandler#getClassLoader

4. 通用内存马注入方案

基于以上研究,提出了通用的内存马注入方案:

// 获取ServletContext
ServletContext servletContext = request.getServletContext();

// 获取应用类加载器
ClassLoader classLoader = servletContext.getClassLoader();

// 定义恶意类
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", 
    String.class, byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class<?> evilClass = (Class<?>) defineClass.invoke(classLoader, 
    className, classBytes, 0, classBytes.length);

5. 兼容性处理

由于ServletContext#getClassLoader是Servlet 3.0引入的,需要考虑以下兼容性处理:

  1. 对于Servlet 3.0+环境,直接使用ServletContext#getClassLoader
  2. 对于旧版本环境,回退到中间件特定的类加载器获取方式

6. 中间件适配实现

MemShellParty项目已实现多种中间件的适配:

  1. Tomcat系列
  2. Undertow
  3. Jetty
  4. WebLogic
  5. WebSphere
  6. JBoss/WildFly
  7. Resin
  8. GlassFish
  9. 等共16种中间件

具体实现可参考:MemShellParty GitHub仓库

7. 防御措施

针对此类内存马注入攻击,建议采取以下防御措施:

  1. 部署RASP(运行时应用自我保护)解决方案,如靖云甲RASP
  2. 启用动态类加载分析功能
  3. 实施恶意类扫描和清除机制
  4. 限制非信任源的类加载操作
  5. 监控异常的类定义行为

8. 总结

通过深入研究Servlet规范和各类中间件的类加载机制,可以构建出更加通用和可靠的内存马注入方案。关键点包括:

  1. 优先使用ServletContext#getClassLoader获取应用类加载器
  2. 针对不同中间件实现特定适配
  3. 考虑Servlet版本兼容性问题
  4. 在实战中注意异常处理和环境适配

这项研究使得内存马注入技术能够适应更多的实战漏洞场景,提高了攻击的成功率和稳定性。

任意类加载环境下注入内存马技术研究 1. 内存马注入基础原理 在JVM中,每个类都有其所属的类加载器。在Java内存马注入场景下,攻击者通常会: 制作一个恶意类 通过 ClassLoader.defineClass 方法注入到JVM中 通过特定方法注册到Web组件上以供访问 传统的内存马注入方式存在以下问题: 依赖 Thread.currentThread().getContextClassLoader() ,这在非请求线程中会失败 某些场景下 context.getClass().getClassLoader() 不可行 2. 类加载器选择问题 2.1 传统方法的局限性 常见的类加载器获取方式: 这些方法存在以下问题: 上下文类加载器依赖请求线程,在非请求线程中不可用 某些中间件环境下 context.getClass().getClassLoader() 无法正常工作 2.2 类加载器选择优化 研究发现,在Tomcat环境中,类加载遵循以下规则: 类名以 org.apache.catalina. 开头的由当前class的类加载器加载 其他类使用 context.getLoader().getClassLoader() 加载 关键代码片段(Tomcat5): 3. Servlet规范中的类加载机制 研究发现Servlet规范(3.0+)中定义了 ServletContext#getClassLoader 方法,用于获取与应用相关联的ClassLoader。 Tomcat实现: 其他中间件实现: Undertow: io.undertow.servlet.spec.ServletContextImpl#getClassLoader Jetty: org.eclipse.jetty.server.handler.ContextHandler#getClassLoader 4. 通用内存马注入方案 基于以上研究,提出了通用的内存马注入方案: 5. 兼容性处理 由于 ServletContext#getClassLoader 是Servlet 3.0引入的,需要考虑以下兼容性处理: 对于Servlet 3.0+环境,直接使用 ServletContext#getClassLoader 对于旧版本环境,回退到中间件特定的类加载器获取方式 6. 中间件适配实现 MemShellParty项目已实现多种中间件的适配: Tomcat系列 Undertow Jetty WebLogic WebSphere JBoss/WildFly Resin GlassFish 等共16种中间件 具体实现可参考: MemShellParty GitHub仓库 7. 防御措施 针对此类内存马注入攻击,建议采取以下防御措施: 部署RASP(运行时应用自我保护)解决方案,如靖云甲RASP 启用动态类加载分析功能 实施恶意类扫描和清除机制 限制非信任源的类加载操作 监控异常的类定义行为 8. 总结 通过深入研究Servlet规范和各类中间件的类加载机制,可以构建出更加通用和可靠的内存马注入方案。关键点包括: 优先使用 ServletContext#getClassLoader 获取应用类加载器 针对不同中间件实现特定适配 考虑Servlet版本兼容性问题 在实战中注意异常处理和环境适配 这项研究使得内存马注入技术能够适应更多的实战漏洞场景,提高了攻击的成功率和稳定性。