文章总结: 该文档分析了ApacheCamel框架中的远程代码执行漏洞CVE-2026-40453,指出受影响版本中多个HeaderFilterStrategy实现因大小写敏感过滤与内部大小写不敏感存储不匹配,导致攻击者可通过变体header绕过过滤,利用camel-exec等组件执行恶意命令或任意文件写入。文档提供了基于Ubuntu24的环境搭建脚本和Docker复现步骤,并说明修复方案是在策略类构造函数中添加setLowerCase(true)确保统一小写过滤。 综合评分: 85 文章分类: 漏洞分析,漏洞预警,应急响应,WEB安全,应用安全
Apache Camel 远程代码执行漏洞 | CVE-2026-40453复现&研究
原创
404号浪漫 404号浪漫
404号浪漫
2026年5月4日 22:07 北京
在小说阅读器读本章
去阅读
点击蓝字,关注我们
0x0 背景介绍
Apache Camel是一个开源的集成框架,基于已知的企业集成模式实现。
受影响版本中,JmsHeaderFilterStrategy、ClassicJmsHeaderStrategy、SjmsHeaderFilterStrategy、CoAPHeaderFilterStrategy和GooglePubsubHeaderFilterStrategy这5个非HTTP HeaderFilterStrategy实现使用大小写敏感的String.startsWith进行header过滤,而Camel Exchange内部以大小写不敏感map存储header。攻击者可通过JMS等协议注入大小写变体的Camel内部header(如’CAmelExecCommandExecutable’),绕过过滤后被camel-exec、camel-file等下游组件以标准大小写处理,导致远程代码执行或任意文件写入。
修复版本中通过在这5个策略类的构造函数中添加setLowerCase(true),使header名称在过滤前先转换为小写,确保大小写变体均可被正确过滤。
漏洞详情
| | | — | | |
| 漏洞类型 | 影响版本 | 利用复杂度 | CVE编号 | | — | — | — | — | | 代码执行 | Apache Camel Google PubSub >= 4.14.6 Apache Camel CoAP >= 4.14.6 Apache Camel JMS >= 4.14.6 | 低 | CVE-2026-40453 |
攻击效果:
- 执行恶意命令,导致RCE。
0x1 环境搭建(Ubuntu24)
- 为了复现环境整的,而非标准生产环境
#!/bin/bash# CVE-2026-40453 漏洞环境搭建脚本# 若任何命令失败则立即退出set -eecho "[*] 阶段1/4:检查并安装基础依赖..."if ! command -v docker &> /dev/null; then echo "[+] Docker 未安装,正在尝试安装..." # 这里仅演示安装docker.io,实际生产环境建议使用官方源 sudo apt update && sudo apt install -y docker.iofisudo systemctl enable --now docker 2>/dev/null || true# 检查 Docker Compose 插件(现代标准)if ! docker compose version &> /dev/null; then echo "[!] 警告:Docker Compose 插件未安装。请安装 docker-compose-plugin 或使用 'docker-compose' 命令。" echo " 本脚本将尝试使用 'docker-compose' 命令(如果已安装)。"fiecho "[*] 阶段2/4:创建工作目录并生成项目文件..."WORKDIR="$HOME/cve-2026-40453"mkdir -p "$WORKDIR/camel-app/src/main/java/org/vuln" && cd "$WORKDIR"echo "[+] 进入工作目录: $PWD"# 阶段2.1:生成 docker-compose.ymlecho "[*] 正在生成 docker-compose.yml..."cat > docker-compose.yml <<'EOF'version: '3.8'services: activemq: image: apache/activemq-classic:6.1.6 container_name: activemq ports: - "61616:61616" # JMS - "8161:8161" environment: ACTIVEMQ_ADMIN_LOGIN: admin ACTIVEMQ_ADMIN_PASSWORD: admin camel-app: build: ./camel-app container_name: camel-app depends_on: - activemq environment: ACTIVEMQ_BROKER_URL: tcp://activemq:61616 # 简单用 sleep 防止 ActiveMQ 未完全就绪,生产可加 healthcheck entrypoint: ["/bin/sh", "-c", "sleep 15 && java -jar /app/app.jar"]EOF# 阶段2.2:生成 Dockerfileecho "[*] 正在生成 camel-app/Dockerfile..."cat > camel-app/Dockerfile <<'EOF'# 编译阶段FROM maven:3.9-eclipse-temurin-17 AS builderWORKDIR /srcCOPY pom.xml .COPY src ./srcRUN mvn package -DskipTests -q# 运行阶段FROM eclipse-temurin:17-jreWORKDIR /appCOPY --from=builder /src/target/*.jar app.jarEXPOSE 8080CMD ["java", "-jar", "app.jar"]EOF# 阶段2.3:生成 pom.xmlecho "[*] 正在生成 camel-app/pom.xml..."cat > camel-app/pom.xml <<'EOF'<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.5</version> <relativePath/> </parent> <groupId>org.vuln</groupId> <artifactId>camel-cve-2026-40453</artifactId> <version>1.0.0</version> <properties> <java.version>17</java.version> <camel.version>4.14.5</camel.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-spring-boot-bom</artifactId> <version>${camel.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-jms-starter</artifactId> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-exec-starter</artifactId> </dependency> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-client</artifactId> <version>6.1.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>EOF# 阶段2.4:生成 Java 源码echo "[*] 正在生成 camel-app/src/main/java/org/vuln/Application.java..."mkdir -p camel-app/src/main/java/org/vulncat > camel-app/src/main/java/org/vuln/Application.java <<'EOF'package org.vuln;import org.apache.activemq.ActiveMQConnectionFactory;import org.apache.camel.builder.RouteBuilder;import org.apache.camel.component.jms.JmsComponent;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.core.env.Environment;@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public JmsComponent jms(Environment env) { String brokerUrl = env.getProperty("ACTIVEMQ_BROKER_URL", "tcp://localhost:61616"); ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl); JmsComponent jms = new JmsComponent(); jms.setConnectionFactory(cf); return jms; } @Bean public RouteBuilder vulnerableRoutes() { return new RouteBuilder() { @Override public void configure() { // 场景 A:JMS -> exec (使用 vuln.exec 队列) from("jms:queue:vuln.exec") //.to("exec:bash"); .to("exec:whoami") .log(">>> whoami output: ${body}"); // 场景 B:JMS -> file 任意文件写入 (队列 vuln.file) from("jms:queue:vuln.file") .to("file:/tmp/outbox?autoCreate=true"); // 场景 C:JMS -> exec (使用 incoming 队列,作为另一种演示) from("jms:queue:incoming") .to("exec:bash"); } }; }}EOFecho "[*] 阶段3/4:启动 Docker 容器环境..."echo "[+] 正在拉取镜像并构建应用..."# 停止并清理旧容器docker compose down -v 2>/dev/null || true# 启动服务docker compose up -decho ""echo "=============================================="echo " CVE-2026-40453 漏洞环境部署完成!"echo " - ActiveMQ 控制台: http://localhost:8161"echo " 用户名: admin"echo " 密码: admin"echo " - Camel 应用容器已后台运行"echo " - 漏洞触发点: 向 ActiveMQ 的 'incoming' 队列发送消息将触发 exec:bash"echo ""echo " - 查看日志: docker logs camel-app"echo " - 进入容器: docker exec -it camel-app /bin/bash"echo "=============================================="
#
#
0x2 漏洞复现
多说一句话,后续尽可能的将复现Pacp共享出来,便于大家做拦截验证
2.1-手动验证
- 一共是三个,但是本质相同
2.1.1 场景 A:JMS ->camel-exec 命令执行
这一类场景最适合做“最短利用链”验证。先搭一个最容易暴露问题的跨边界链路: 外部生产者只能往消息队列里塞消息头,而路由内部再把消息交给 exec:。
建议环境
1. 中间件: ActiveMQ Classic 或任意支持 JMS 属性的 Broker。2. 路由形态: • 消费端: from("jms:queue:vuln.exec") •危险下游: to("exec:whoami") 或 Windows 下 to("exec:cmd.exe")3. 依赖模块: •camel-jms •camel-exec •对应 JMS 驱动
最小化示例路由
from("jms:queue:vuln.exec").to("exec:whoami");
如果希望从 Web 侧,可以再加一个 HTTP 入口,把请求头原样转发进 JMS:
345678rest("/demo").post("/exec").to("direct:bridge");
from("direct:bridge").to("jms:queue:vuln.exec");。
Windows 下可替换为:
cAmelExecCommandExecutable=cmd.execAmelExecCommandArgs=/c whoami
2.1.2 场景 B:JMS -> camel-file 任意文件写入
很多系统不会直接接 exec:,却很常见地把 MQ 中的消息落到文件系统。此时攻击者未必需要拿 RCE,只要能劫持输出文件名或路径,就已经越过了原本的安全边界。
建议环境
1. 路由形态: •消费端: from("jms:queue:vuln.file") •危险下游: to("file:./outbox?autoCreate=true")
2.依赖模块: •camel-jms •camel-file
最小化示例路由
from("jms:queue:vuln.file").to("file:./outbox?autoCreate=true");
2.2-复现流量特征 (PCAP)
本次复现PCAP:
https://github.com/Kai-One001/PCAP-For-Cybersecurity.rule/blob/main/2026/CVE-2026-40453-Apache-Camel.pcap
#
- 命令接口
- 文件写入
- 命令接口
#
0x3 漏洞原理分析
3.0-[架构定位] 先把受影响模块放同一条消息链
只有先把每个模块在链条中的职责摆清楚,后面看代码时才不会迷失在大量组件实现里。
| | | — | | |
| 层级 | 核心文件 | 角色 | 在漏洞链中的职责 |
| — | — | — | — |
| 入口过滤层 | components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsHeaderFilterStrategy.java | JMS 默认头过滤策略 | 负责阻止外部消息把 Camel 内部头带入路由 |
| 入口过滤层 | core/camel-support/src/main/java/org/apache/camel/support/DefaultHeaderFilterStrategy.java | 通用过滤基类 | 真正执行前缀、正则、集合匹配;漏洞缺陷就在这里暴露 |
| 链路桥接层 | components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsBinding.java | JMS <-> Camel 头桥接器 | 先调用过滤器,再把未拦截的外部头写入 Camel 消息头 |
| 消息存储层 | core/camel-support/src/main/java/org/apache/camel/support/DefaultMessage.java | 默认消息实现 | 使用大小写不敏感头图保存 Header,导致伪装头与规范头合流 |
| 消息存储层 | core/camel-util/src/main/java/org/apache/camel/util/CaseInsensitiveMap.java | 大小写不敏感 Map | 为下游“按规范头名读取”提供基础能力 |
| 危险头消费层 | components/camel-exec/src/main/java/org/apache/camel/component/exec/impl/DefaultExecBinding.java | 命令参数绑定 | 从消息头读取 CamelExec* 参数并组装执行命令 |
| 危险头消费层 | components/camel-exec/src/main/java/org/apache/camel/component/exec/ExecProducer.java | 命令执行器入口 | 将组装后的命令真正送入执行器 |
| 危险头消费层 | components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileProducer.java | 文件写入生产者 | 从消息头读取 CamelFile* 参数并决定最终落盘路径 |
3.1-[核心入口]先看 HeaderFilterStrategy
原本根据漏洞信息时,第一反应应该是去翻camel-exec,这次先不,这次是先追问一个更基础的问题: 攻击者明明只能控制“外部消息头”,这些头为什么有机会在路由内部被当成CamelExecCommandExecutable这样的框架级内部头使用?
先找到外部 Header 进入 Camel 体系时的第一道边界。顺着JMS consumer的逻辑往下看,定位到 JmsBinding.extractHeadersFromJms()。这个函数是关键,因为它一边枚举JMS属性,一边决定哪些头该被拦下,哪些头可以进入Camel消息对象。
// components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsBinding.javawhilewhile (names.hasMoreElements()) { String name = names.nextElement().toString(); Object value = JmsMessageHelper.getProperty(jmsMessage, name); if (headerFilterStrategy != null && headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) { continue; }
String key = jmsKeyFormatStrategy.decodeKey(name); map.put(key, value);}
- 预期安全边界,本来应该是“外部消息头先过过滤器,Camel内部保留头不能进入业务 Exchange”。
- 可真正实现里,过滤是否命中完全取决于
HeaderFilterStrategy,而一旦没有命中,头就会被map.put(key, value)塞进Camel的消息头图。 - 换句话说,这里就是“最后一道失守前的边界闸门”。
接着往上追过滤器的具体实现,可以看到 JMS 默认使用的是JmsHeaderFilterStrategy:
// components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsHeaderFilterStrategy.javapublic JmsHeaderFilterStrategy(boolean includeAllJMSXProperties) { setOutFilterStartsWith(DefaultHeaderFilterStrategy.CAMEL_FILTER_STARTS_WITH); setInFilterStartsWith(DefaultHeaderFilterStrategy.CAMEL_FILTER_STARTS_WITH); if (!includeAllJMSXProperties) { initialize(); }}
- 这里传入的
CAMEL_FILTER_STARTS_WITH实际上就是框架试图保护内部头空间的规则: 凡是以Camel/camel开头的头,都应该被视为内部头,不让外部带进来。
3.2-[逻辑缺陷] 预期要“拦 Camel 头”,实际却只拦了两种大小写
顺着JmsHeaderFilterStrategy往下追,停在DefaultHeaderFilterStrategy.doFiltering()。看这里的原因很简单: 入口策略把规则交给了公共基类,真正决定是否放行
// core/camel-support/src/main/java/org/apache/camel/support/DefaultHeaderFilterStrategy.javaprivate boolean doFiltering(Direction direction, String headerName, Object headerValue, Exchange exchange) { // ... if (startsWith != null) { if (tryHeaderMatch(headerName, startsWith)) { return filterOnMatch; } if (lowerCase) { lower = headerName.toLowerCase(); if (tryHeaderMatch(lower, startsWith)) { return filterOnMatch; } } } // ...}
private boolean tryHeaderMatch(String headerName, String[] startsWith) { for (String s : startsWith) { boolean match = headerName.startsWith(s); if (match) { return true; } } return false;}
- startsWith这一支并没有做统一规范化后再比较,而是直接把原始
headerName拿来和"Camel"、"camel"做前缀匹配。 - 它真正能拦住的,是完全以
Camel开头或者完全以camel开头的两类头。
这就是设计预期与实现现实之间差异:
•预期边界: 任何 Camel 内部头,不管攻击者怎么折腾大小写,只要语义上还是那个内部头,就不该从外部进入。
•实际实现: 过滤器只认识 "Camel" 和 "camel" 两种字面前缀,像 cAmelExecCommandExecutable、CAMelFileName 这类混合大小写变体会被当成“普通外部头”放行。
更值得注意的是,同一份实现里,Set型过滤反而考虑了equalsIgnoreCase
// core/camel-support/src/main/java/org/apache/camel/support/DefaultHeaderFilterStrategy.javaprivate boolean evalFilterMatch(String headerName, String lower, Set<String> filter) { if (isCaseInsensitive()) { for (String filterString : filter) { if (filterString.equalsIgnoreCase(headerName)) { return true; } } } else if (lowerCase) { // ... } return false;}
3.3-[攻击链路] 为什么绕过入口后,下游还能按规范头名精确命中
如果分析停在上一步,其实还差最后一块拼图: 就算攻击者用 cAmelExecCommandExecutable 绕过了 JMS 过滤器,下游组件读取的却是标准名字 CamelExecCommandExecutable。这两个字符串并不完全相同,为什么还能连上?
答案藏在 Camel 默认消息实现里。之所以回头去看DefaultMessage,是因为所有组件最终读的都是exchange.getIn().getHeader(...)。只要这里对头名查找是大小写不敏感的,前面的绕过和后面的命中就会自然拼接起来。
// core/camel-support/src/main/java/org/apache/camel/support/DefaultMessage.java/** * This implementation uses a {@link org.apache.camel.util.CaseInsensitiveMap} storing the headers. * This allows us to be able to lookup headers using case insensitive keys. */ public Object getHeader(String name) { if (headers == null) { headers = createHeaders(); } if (!headers.isEmpty()) { return headers.get(name); } else { return null; }}
再往底层看,CaseInsensitiveMap直接使用了String.CASE_INSENSITIVE_ORDER:
// core/camel-util/src/main/java/org/apache/camel/util/CaseInsensitiveMap.javapublic class CaseInsensitiveMap extends TreeMap<String, Object> { public CaseInsensitiveMap() { super(String.CASE_INSENSITIVE_ORDER); } public CaseInsensitiveMap(Map<? extends String, ?> map) { super(String.CASE_INSENSITIVE_ORDER); putAll(map); }}
- 入口过滤是在大小写敏感地看头名,消息对象内部却在大小写不敏感地存取头名。
- 攻击者只需要在入口边界把头名改成一个大小写变体,让它躲过过滤;
- 一旦进入
CaseInsensitiveMap,这个变体就会与规范头名合流。 - 下游组件完全不需要知道攻击者用了什么花样大小写,它按正常代码读取标准头名,就能把恶意值取出来。
3.4-[爆发点一] 为什么确信这条链能打到 camel-exec
确认了“能进来”和“能命中”之后,下一步就是找真正的危险操作函数。对camel-exec 来说,这个函数非常明确: DefaultExecBinding.readInput() 负责从消息头取出命令相关参数,随后 ExecProducer.process() 直接执行。
public ExecCommand readInput(Exchange exchange, ExecEndpoint endpoint) { Object args = exchange.getIn().removeHeader(EXEC_COMMAND_ARGS); String cmd = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_EXECUTABLE, endpoint.getExecutable(), String.class); String dir = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_WORKING_DIR, endpoint.getWorkingDir(), String.class); long timeout = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_TIMEOUT, endpoint.getTimeout(), Long.class); String exitValuesString = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_EXIT_VALUES, endpoint.getExitValues(), String.class); String outFilePath = getAndRemoveHeader(exchange.getIn(), EXEC_COMMAND_OUT_FILE, endpoint.getOutFile(), String.class); // ... return new ExecCommand( cmd, argsList, dir, timeout, exitValues, input, outFile, useStderrOnEmptyStdout, commandLogLevel);}
public void process(Exchange exchange) throws Exception { ExecCommand execCommand = getBinding().readInput(exchange, endpoint); ExecCommandExecutor executor = endpoint.getCommandExecutor(); // ... ExecResult result = executor.execute(execCommand);}
- 如果只看框架设计
CamelExecCommandExecutable、CamelExecCommandArgs这类头本来应该是路由内部受控参数,用于在可信处理器之间传递执行上下文,而不应该由外部消息生产者直接注入。 - 但是现在,攻击者只要先利用前面的大小写缺陷把这些头带进Exchange,再借助
CaseInsensitiveMap让它们被标准名命中ExecProducer就会心安理得地执行攻击者指定的命令。 - 在这条链上,最后一道失守的防线其实就是
ExecProducer.process()之前的DefaultExecBinding.readInput()。因为到了这里,框架已经不再区分“这个头是可信内部逻辑写入的,还是外部消息伪装带进来的”。一旦读到了值,它就会把它们当作合法执行参数组装成ExecCommand。
3.5-[爆发点二] 同样的逻辑为什么还能劫持 camel-file
接着继续找camel-file,是因为它代表另一类非常常见的风险: 不一定要执行命令,只要能影响文件路径,就能形成越权写入、投放后门文件、污染后续处理结果等更隐蔽的攻击面。
首先看框架对这些头的定义:
// components/camel-file/src/main/java/org/apache/camel/component/file/FileConstants.java
@Metadata(description = "(producer) Specifies the name of the file to write ...")public static final String FILE_NAME = Exchange.FILE_NAME;xxxxxx
@Metadata(label = "producer", description = "Is used for overruling `CamelFileName` header ...")public static final String OVERRULE_FILE_NAME = Exchange.OVERRULE_FILE_NAME;
然后看真正消费这些头的位置:
// components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileProducer.javaprotected void doProcess(Exchange exchange) throws Exception { final String existing = exchange.getIn().getHeader(FileConstants.FILE_NAME, String.class); String target = createFileName(exchange); // ... exchange.getIn().removeHeader(Exchange.OVERRULE_FILE_NAME); exchange.getIn().setHeader(FileConstants.FILE_NAME, existing);}// 2public String createFileName(Exchange exchange) { Object overrule = exchange.getIn().getHeader(FileConstants.OVERRULE_FILE_NAME); final Object value = getOverrule(exchange, overrule); // ...}private static Object getOverrule(Exchange exchange, Object overrule) { if (overrule != null) { // ... } else { value = exchange.getIn().getHeader(FileConstants.FILE_NAME); } return value;}// 3public void writeFile(Exchange exchange, String fileName) throws GenericFileOperationFailedException { if (endpoint.isAutoCreate()) { String name = FileUtil.normalizePath(fileName); File file = new File(name); String directory = file.getParent(); if (directory != null) { operations.buildDirectory(directory, absolute); } } boolean success = operations.storeFile(fileName, exchange, -1);}
这里的问题与camel-exec 是同构的。
CamelFileName / CamelOverruleFileName应该是路由内部用来控制输出文件名的保留头;- 实际中呢,只要攻击者能通过大小写变体把它们偷运进Exchange,下游
GenericFileProducer就会把它们作为正常的输出路径参数使用。 - 尤其当端点开启
autoCreate=true时,攻击者不仅能控制文件名,往往还可以顺手控制目录层级。
如果目标业务把 MQ 消息落盘到某个被其他系统消费的目录,那么这就不只是“任意写一个文件”那么简单了。它可能进一步变成:
1. 向任务目录投放伪造作业文件,诱导后续处理链执行;2. 覆盖关键业务输出,制造数据污染;3. 在某些部署结构下,向 Web 可访问目录写入可执行脚本或恶意内容。
#
3.6-[攻击链路] 从注入点到爆发点的完整闭环
现在整条链已经可以完整闭环了。我们重新串起来,会发现这个漏洞并不是单点编码失误,而是三个“各自看起来合理”的设计在边界上发生了危险叠加:
1. JMS/SJMS 希望用 HeaderFilterStrategy 阻止外部消息伪装内部头。2. Camel 核心为了易用性,默认把消息头放进 CaseInsensitiveMap。3. camel-exec、camel-file 等下游组件按规范内部头名读取参数。
完整调用链如下:
// 外部 HTTP/JMS 生产者 -> 注入大小写变体头(如 cAmelExecCommandExecutable / cAmelFileName) -> JMS Consumer / SJMS Consumer -> JmsBinding.extractHeadersFromJms() -> HeaderFilterStrategy.applyFilterToExternalHeaders() -> DefaultHeaderFilterStrategy.doFiltering() 前缀匹配遗漏混合大小写 -> map.put(key, value) 写入 Camel Message -> DefaultMessage / CaseInsensitiveMap 以不区分大小写方式存储与检索 -> 下游组件按规范头名 getHeader()/removeHeader() -> 爆发点 A: DefaultExecBinding.readInput() -> ExecProducer.process() -> 命令执行 -> 爆发点 B: GenericFileProducer.createFileName()/writeFile() -> 文件写入
#
#
0x4 修复建议
1、升级最新版本:将组件升级安全版本
https://camel.apache.org/security/CVE-2026-40453.html
2、临时防护措施:
-
限制访问:严格限制谁可以向JMS/消息队列生产消息;对桥接MQ的HTTP入口增加鉴权,不允许匿名或低信任租户直接投递
-
防火墙 / WAF:可拦截包含异常Camel内部头特征的请求头,例如 :(?i)^camel(exec|file);
-
危险组件隔离:避免把jms:或其他外部可写消息源直接连接到exec:、file:、bean:等受Header强驱动的端点,中间增加显式映射层,只复制白名单字段。
-
审计与检测:重点检索日志、Broker 属性和流量中是否出现非常规大小写的Camel 内部头,如cAmelExecCommandExecutable、CAMelFileName、cAmelOverruleFileName。这类特征在正常业务里几乎没有正当理由出现。
免责声明:本文仅用于安全研究目的,未经授权不得用于非法渗透测试活动。
/** 怎么样怎么样?专门找今天发,因为假期最后一天啦,同志们要注意时间管理呀**/
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:404号浪漫 404号浪漫 404号浪漫《Apache Camel 远程代码执行漏洞 | CVE-2026-40453复现&研究》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论