检测和抵御 Apache Camel 漏洞
执行摘要
2025 年 3 月 9 日,Apache Camel 公开了 CVE-2025–27636。此漏洞源于错误地筛选请求标头,因而导致远程代码执行。
它位于一个库中,会造成直接和间接的依赖关系,使得检测和抵御此漏洞的方法异常复杂。
在本博文中,Akamai 研究人员详细介绍该漏洞及其利用方式和检测策略。
Akamai 自适应安全引擎快速规则自动为 Akamai App & API Protector 客户提供保护。
我们还提供 Akamai Guardicore Segmentation Insight 查询来进行检测。
- 受影响的 Akamai Hunt 客户已经收到了存在漏洞的资产的详细清单。
- 更新:2025 年 3 月 11 日,Akamai 安全情报组 (SIG) 向 Apache Camel 安全团队报告了一种绕过筛选的情况。2025 年 3 月 12 日,Apache 发布了新 CVE: CVE-2025-29891。
简介
2025 年 3 月 9 日,Apache 修复 了 Apache Camel中的一个漏洞,这是一个广泛使用的 Java 库。Apache 解决了该漏洞,并在版本 4.10.2、4.8.5 和 3.22.4 中予以修复。虽然最初的报告宣称该漏洞会造成严重影响,但开发团队向其分配的严重程度为中等。
不管其严重性评级如何,如果您的环境运行的是已修复版本,则强烈建议您尽快进行修复。然而, 运行版本 4.10.0、4.10.1、4.8.0 到 4.8.4 以及 3.10.0 到 3.22.3 的应用程序仍会受到影响。
要想利用这个漏洞,存在漏洞的应用程序必须满足一些特定的先决条件(这些内容将 在本博文的稍后部分中详述)。虽然如此,但这一漏洞仍可能造成巨大的影响。该漏洞很容易被利用,并会导致 远程代码执行等严重后果。
Camel 的普遍应用以及漏洞在库中的嵌入式特性,证明了此发现的严重程度。本博文意在指导企业完成其应对流程。
我们将仔细审查该漏洞,说明漏洞对应用程序的潜在影响,分析利用方法以便确立检测手段,并解决可能是此漏洞以及隐藏在库中的其他漏洞带来的最困难的挑战:识别存在漏洞的应用程序。
什么是 Apache Camel?
Apache Camel 是一种广泛使用的开源集成框架,用于在不同的系统、应用程序和云服务之间实现无缝的数据交换。该框架可以跨多种企业环境,简化消息路由、转换和连接。许多企业依靠 Camel 来实现关键的业务工作流、API 集成以及微服务编排。
分析 CVE-2025-27636 漏洞
Apache Camel 使用 DefaultHeaderFilterStrategy.java 来阻止向外部转发内部标头。此举可防止标头泄露敏感路由信息,以免被攻击者滥用。这些标头的示例包括:
- CamelHttpResponseCode
- CamelHttpUri
- CamelContextId
- org.apache.camel.SomeInternalHeader
当基于 HTTP 的组件在处理请求时会应用此筛选机制,例如:
- Camel-http 和 camel-http4(标准 HTTP 处理)
- camel-rest(REST DSL 处理)
- camel-cxf(Apache CXF Web 服务)
该漏洞源自 Camel 筛选请求标头时的错误。在进行修复之前,Apache Camel 使用区分大小写的筛选规则(图 1)。
此逻辑仅匹配以 Camel 或 org.apache.camel 开头(完全按照所示大小写)的标头。如果攻击者更改了大小写,例如使用 CAmelHttpUri 或 cAMELHttpResponseCode,则不会筛选标头。
这意味着攻击者可以将任意标头注入我们的请求中,并让 Camel 将标头转发到内部组件。需要注意的是, Apache 在其建议中曾提到, 该漏洞不允许访问任意内部方法,而仅限于访问在 bean URI 内声明的同一 bean 中的方法。这是在利用该漏洞时必须满足的一个特定先决条件,意味着如果仅运行存在漏洞的 Apache Camel 版本,并不一定就会自动让应用程序变得易受攻击。
威胁测试
为了演示漏洞,我们创建了可被远程侵入的 存在漏洞的应用程序示例 。该应用程序监听 HTTP 端口 80,在收到请求时,使用 Camel“Exec”组件执行 whoami 命令,并将结果回显给客户端。
使用 curl 调用简单的请求会返回意料之中的结果:暴露漏洞(图 2)。
正如在代码中所看到的, whoami 命令是静态定义的,使得代码看起来相对安全。当我们检查 Exec 可能支持的内部消息标头时,就会出现问题。检查 CamelExecCommandExecutable 标头时,我们发现它覆盖了在代码的静态 URI 中定义的可执行文件(图 3)。
Apache Camel 会筛选出与字母大小写匹配的内部标头,例如 CamelExecCommandExecutable。但是,通过输入 CAmelExecCommandExecutable (或其他只有大小写不同的字符串),CVE-2025–27636 会允许绕过筛选器,并将 在服务器上执行任意命令 (图 4)。
我们还可以采用类似的方法指定 CAmelExecCommandArgs ,向执行的命令提供参数(图 5)。
这个示例比较简单,用于演示利用此漏洞的大致方法。利用注入任意内部标头的能力,根据服务器使用的 Camel 组件,攻击者可以侵入各种应用程序。
Apache Camel 如何解决 CVE-2025-27636?
该问题的 解决方法 是强制执行字母大小写一致性。这就使得攻击者失去了通过篡改字母大小写来绕过筛选器的能力。例如, CAmelHttpUri 变成 camelhttpuri,现在与筛选器匹配,因而会被发现。
引入 .toLowerCase()
GitHub 提交了 DefaultHeaderFilterStrategy.java 中更新后的标头筛选逻辑,其中使用 toLowerCase(Locale.ENGLISH) 来确保先将所有标头名称转换为小写,然后再应用筛选器(图 6)。
该修复在防止注入之外,还利用优化的检查来保持效率。第一个检查快速处理正常的“Camel”和“camel”情况,然后仅在必要时才运行 .toLowerCase() 检查,防止出现不必要的性能成本。
检测存在漏洞的应用程序
识别一个网络中所有存在漏洞的 Apache Camel 实例非常困难。安全团队必须评估各种资产,因为 Apache Camel 会集成到多个位置中。这甚至会包括防御者都不知道的使用了这些库的应用程序。
库可能作为间接依赖项出现,意味着源代码中并没有明确地包含库,而是通过另一个软件包引入。不论是对于检测还是抵御,这都进一步加剧了复杂性。
通常,在 Java 应用程序中,通过递归扫描目录中是否存在名称包含“camel”的 JAR 文件,即可识别出 Apache Camel。 一旦找到与 Camel 相关的 JAR 文件,通过检查其清单文件就能确定所用的版本。
对于提取出来的版本,安全团队可以根据 Apache 的安全建议 进行交叉引用,来评估可能存在的漏洞。以下版本受到影响:
- 4.10.0 ——低于下列版本即存在漏洞: 4.10.2
- 4.8.0 ——低于下列版本即存在漏洞: 4.8.5
- 3.10.0 ——低于下列版本即存在漏洞: 3.22.4
自动检测
为了方便识别存在漏洞的应用程序,我们开发了 PowerShell 和 Bash 脚本 ,这两个脚本递归扫描目录,检测 Apache Camel JAR 文件,并输出可能存在漏洞的应用程序。我们提供了面向 Windows 和 Linux 的选项。 受影响的 Akamai Hunt 客户已经收到了存在漏洞的资产的详细清单。
利用 Akamai Guardicore Segmentation 进行检测
对于 Akamai Guardicore Segmentation 客户,我们已经构建了 Insight 查询,可以识别存在漏洞的资产。在查询文件版本时,如果返回的查询结果是“未找到版本”,则可以在 VirusTotal 中检查返回的哈希值,或者通过 jar 中的清单文件来获取正确的版本。
Windows
WITH relevant_cwds as (
SELECT DISTINCT
proc.pid,
proc.path,
proc.cmdline,
proc.cwd,
mmap.path AS mmap_path
FROM process_memory_map AS mmap
LEFT JOIN processes AS proc USING(pid)
WHERE mmap_path LIKE "%jvm%"
UNION
SELECT DISTINCT
proc.pid,
proc.path,
proc.cmdline,
proc.cwd,
proc.path AS placeholder_path
FROM processes AS proc
WHERE proc.name IN ("java", "javaw", "java.exe", "javaw.exe")
),
RELEVANT_JAR_PATHS AS (
SELECT file.path as lib_path, cwd, cwd || '..\%\%\camel-core%.jar' AS jar_path, sha256
FROM file INNER JOIN relevant_cwds ON file.path LIKE jar_path
INNER JOIN hash on file.path = hash.path
UNION
SELECT file.path as lib_path, cwd, cwd || '..\%\camel-core%.jar' AS jar_path, sha256
FROM file INNER JOIN relevant_cwds ON file.path LIKE jar_path
INNER JOIN hash on file.path = hash.path
UNION
SELECT file.path as lib_path, cwd, cwd || '%\%\camel-core%.jar' AS jar_path, sha256
FROM file INNER JOIN relevant_cwds ON file.path LIKE jar_path
INNER JOIN hash on file.path = hash.path
)
SELECT lib_path, relevant_cwds.path as proc_path,
CASE WHEN lib_path LIKE '%camel-core-2%' OR lib_path LIKE '%camel-core-3%' OR lib_path LIKE '%camel-core-4%' THEN SUBSTR(lib_path, INSTR(lib_path, 'camel-core-') + 11, INSTR(lib_path, '.jar') - (INSTR(lib_path, 'camel-core-') + 11))
WHEN lib_path like '%camel-core.jar' THEN 'Version not found' ELSE NULL END as version, cmdline, sha256 FROM RELEVANT_JAR_PATHS
INNER JOIN relevant_cwds ON relevant_cwds.cwd = RELEVANT_JAR_PATHS.cwd
WHERE
version is not null
Linux
WITH relevant_cwds as (
SELECT DISTINCT
proc.pid,
proc.path,
proc.cmdline,
proc.cwd,
mmap.path AS mmap_path
FROM process_memory_map AS mmap
LEFT JOIN processes AS proc USING(pid)
WHERE mmap_path LIKE "%jvm%"
UNION
SELECT DISTINCT
proc.pid,
proc.path,
proc.cmdline,
proc.cwd,
proc.path AS placeholder_path
FROM processes AS proc
WHERE proc.name IN ("java", "javaw", "java.exe", "javaw.exe")
),
RELEVANT_JAR_PATHS AS (
SELECT file.path as lib_path, cwd, cwd || '/../%/%/camel-core%.jar' AS jar_path, sha256
FROM file INNER JOIN relevant_cwds ON file.path LIKE jar_path
INNER JOIN hash on file.path = hash.path
UNION
SELECT file.path as lib_path, cwd, cwd || '/../%/camel-core%.jar' AS jar_path, sha256
FROM file INNER JOIN relevant_cwds ON file.path LIKE jar_path
INNER JOIN hash on file.path = hash.path
UNION
SELECT file.path as lib_path, cwd, cwd || '/%/%/camel-core%.jar' AS jar_path, sha256
FROM file INNER JOIN relevant_cwds ON file.path LIKE jar_path
INNER JOIN hash on file.path = hash.path
)
SELECT lib_path, relevant_cwds.path as proc_path,
CASE WHEN lib_path LIKE '%camel-core-2%' OR lib_path LIKE '%camel-core-3%' OR lib_path LIKE '%camel-core-4%' THEN SUBSTR(lib_path, INSTR(lib_path, 'camel-core-') + 11, INSTR(lib_path, '.jar') - (INSTR(lib_path, 'camel-core-') + 11))
WHEN lib_path like '%camel-core.jar' THEN 'Version not found' ELSE NULL END as version, cmdline, sha256 FROM RELEVANT_JAR_PATHS
INNER JOIN relevant_cwds ON relevant_cwds.cwd = RELEVANT_JAR_PATHS.cwd
WHERE
version is not null
利用 Akamai App & API Protector 进行抵御
2025 年 3 月 7 日星期五,Akamai 的威胁研究团队部署了适用于 App & API Protector 客户的自适应安全引擎快速规则:
检测到 3000911 v2 - Apache Camel (CVE-2025-27636) 攻击——默认操作:拒绝
客户如果启用了快速规则并将默认操作设置为“Akamai 托管”,就能够自动防御此威胁。客户如果启用了快速规则并将默认操作设置为“告警”,就需要评估所有规则触发器并将规则操作设置为拒绝。
快速规则 3000911 的设计理念是,在原本可以规避 Camel 内部筛选逻辑的标头上触发(图 7)。 该规则不会在普通 Camel 标头上触发,以防止对合法用户操作造成任何影响。
观察到的攻击流量
目前, Akamai 安全情报组 观察到的攻击有效负载仅仅尝试确认了该漏洞,而没有利用它。在观察到的攻击有效负载中,大部分使用两种不同的策略来确认漏洞。
首先,我们看到了使用 CAmELDestinationOverrideUrl 标头名称,其中的攻击有效负载在带外 (OOB) 向域发送信标。此流量源自商业漏洞扫描供应商,攻击有效负载 URL 会将信标发送回其域(图 8)。
其次,我们看到攻击有效负载使用 CAmelHttpResponseCode 标头,尝试从服务器诱发特定的 HTTP 响应状态代码(图 9)。如果攻击有效负载成功,则从服务器返回的 HTTP 响应状态代码会匹配攻击有效负载中提供的代码之一。
最后,我们看到上述攻击有效负载均尝试使用简单的 URL 编码来规避检测,例如 ca%4d%45%6cHttpResponseCode (图 10)。不过,自适应安全引擎仍会检测到并阻止这些尝试。
更新:CVE-2025-29891
Akamai SIG 与 Citi Cyber Security Operations 合作发现了另一个漏洞利用媒介,该媒介同样源于导致 CVE-2025-27636 的筛选问题。在测试存在漏洞的应用程序时,我们发现在请求标头之外, 查询字符串和 post 正文参数也会造成有效的攻击路径。
在图 11 中,我们看到,指定 CAmelExecCommandExecutable 查询参数会导致任意命令执行,就像原始的标头媒介一样。

Akamai SIG 向 Apache Camel 安全团队报告了这种绕过筛选的情况。他们验证了调查结果并创建新的 CVE: CVE-2025-29891。Apache Camel 在 CVE-2025-27636 中的修复代码也能修复此绕过情况,不过 Akamai 仍然必须在 2025 年 3 月 12 日发布更新后的 App & API Protector 快速规则 3000911 v3 ,用于解决这个缺陷。
修复 CVE-2025-27636 的原始补丁也解决了此问题,因此使用最新版本的 Apache Camel 不会暴露在此漏洞利用媒介下。
我们更新了我们的 GitHub 存储库,现在其中同样包含有关 CVE-2025-29891 及其攻击方法的详细信息。
虽然通过检查请求标头可以检测以前的漏洞利用情况,但此问题同样需要筛选请求参数。