Aqua Nautilus 研究人员在广泛使用的 Jenkins 服务器和更新中心发现了一系列称为 CorePlague 的关键漏洞(CVE-2023-27898、CVE-2023-27905)。利用这些漏洞可能允许未经身份验证的攻击者在受害者的 Jenkins 服务器上执行任意代码,从而可能导致 Jenkins 服务器完全受损。
此外,即使攻击者无法直接访问 Jenkins 服务器,这些漏洞也可能被利用,并且还可能影响自托管的 Jenkins 服务器。
研究简介
Jenkins 是一个开源自动化服务器,支持软件开发生命周期 (SDLC),可以使用插件进行自定义以扩展其功能。
在我们的研究过程中,我们发现了 Jenkins 处理可用插件的方式存在漏洞,这可能导致从跨站点脚本 (XSS) 到远程代码执行 (RCE) 的各种安全问题。
这些漏洞是通过存储的 XSS 实现的,攻击者将其上传到 Jenkins 更新中心,该 XSS 可被具有恶意核心版本的 Jenkins 插件利用。
一旦受害者在其 Jenkins 服务器上打开可用插件管理器,就会触发 XSS,允许攻击者利用脚本控制台 API 在 Jenkins 服务器上运行任意代码。
重要的是,该漏洞是在受害者无需执行任何其他操作的情况下触发的,并且利用该漏洞不需要安装纵的插件。
攻击者可以利用这些漏洞来破坏 Jenkins 服务器,即使它们无法直接访问,因为攻击者可能会注入公共 Jenkins 更新中心(在 Jenkins 服务器上默认用于获取可用的插件列表)。
我们于 2023 年 1 月向 Jenkins 团队披露了这些漏洞 CVE-2023-27898 和 CVE-2023-27905。Jenkins 团队承认了这些漏洞,并为 Jenkins 服务器发布了补丁。他们还发布了 Jenkins 更新中心的补丁。我们感谢他们在披露过程中的合作和专业精神。
常见问题解答
我需要修补我的 Jenkins 服务器吗?
Jenkins 团队于 2 月 15 日发布了公共 Jenkins 更新中心的补丁,该补丁减轻了与此漏洞相关的一些风险,因为它是第一个涉及的组件。这一点尤其重要,因为大多数 Jenkins 用户都依赖公共 Jenkins 更新中心来获取可用 Jenkins 插件的列表。这意味着,如果您依赖公共 Jenkins 更新中心来获取插件,您的 Jenkins 服务器将容易受到攻击,但可能无法利用。因此,无需立即更新它。但是,如果您使用自托管或自定义的更新中心,则会面临风险。
哪些 Jenkins Server 版本容易受到攻击?
运行版本 2.270 到 2.393(包括两者)、LTS 2.277.1 到 2.375.3(包括两者)的 Jenkins 服务器容易受到攻击(本博客将详细介绍最新版本的利用限制)
哪些 Jenkins 更新中心版本容易受到攻击?
版本低于 3.15 的 Jenkins 更新中心容易受到攻击。
有关详细信息,请参阅 Jenkins 安全公告 2023-03-08。
一些基本的 Jenkins 定义
构件注册表 用于存储和管理软件构件的二进制存储库管理器。Jenkins 项目使用自己的 Artifactory 二进制存储库来分发核心、库和插件版本。
Jenkins 更新中心 Jenkins 自动化服务器的一个组件,提供对 Jenkins 平台的各种插件和更新的访问。它允许 Jenkins 管理员轻松发现、下载和安装扩展其 Jenkins 服务器功能的插件。这也称为 Jenkins 社区更新站点。
Jenkins 服务器 Jenkins 是一种广泛使用的开源自动化服务器,支持软件项目的持续集成和交付。
Jenkins 插件是扩展 Jenkins 服务器功能的软件组件,使用户能够增强和自定义他们的体验和自动化过程。这些 Jenkins 插件提供源代码管理、构建触发器、通知机制以及与外部工具和系统集成等功能。它们可以通过 Jenkins 更新中心进行安装、更新和管理。我们在博客中描述的漏洞与 Jenkins 插件有关。
卫生不当:Jenkins 更新中心
现在我们已经清楚地了解了什么是 Jenkins 插件,让我们了解创建插件的过程,以便每个人都可以使用它。
简而言之,初始上传过程是用 Java 编写一个插件,并向 Jenkins 团队提交一个 pull request。审核通过后,将在 https://github.com/jenkinsci/your_plugin_name 创建一个 GitHub 存储库,您将被授予对它的写入权限。
此外,Jenkins 团队还授予您对构件注册表的写入权限,从而允许您上传已编译的插件。
一旦 Jenkins 团队批准了初始插件版本(这通常只是一个程序步骤),开发人员就可以发布插件的后续版本,而无需团队的任何参与。
因此,攻击者可能会上传一个无害的插件,然后将其更改为纵的插件,而无需任何额外的批准。
要将插件的新版本发布到构件注册表,开发人员必须运行 publish 命令,该命令将构建项目并将其存储在指定的文件夹中。如下图所示(在此示例中,ascii-magician 作为插件名称):
构建完成后,publish 命令会将生成的构件(如 、 和 文件)上传到构件注册表。plugin_name.hpi
plugin_name.jar
plugin_name-ver.pom
在继续之前,让我们检查一下已上传到构件注册表的文件。.hpi
该文件实际上是一个压缩的 zip 文件,其中包含各种文件和目录。让我们仔细看看这个文件:.hpi
META_INF/ MANIFEST.MF
META-INF/MANIFEST.MF 文件包含键值对,这些键值对提供有关正在发布的插件的元数据。(Jenkins 版本突出显示以供将来参考。
到目前为止,我们已经从发布者的角度概述了上传过程。现在,在构件位于构件注册表中之后,让我们将重点转移到向 Jenkins 服务器提供插件的更新中心。
Update Center 处理构件注册表中的所有插件,并生成包含有关所有可用插件的元数据的 update-center.json 文件。此文件可在此处找到:https://updates.jenkins.io/update-center.json
为了说明这一点,让我们简要地看一下与插件相关的元数据示例:
在上图中,您可以看到 pam-auth 插件的一些元数据。此元数据包括构建日期、标签、下载 URL 和 requiredCore(插件所需的最低 Jenkins 版本)等详细信息。
如何将插件的元数据添加到此 JSON 文件中?
Update Center 从构件注册表中获取插件,并为每个插件创建有关插件的元数据的 JSON。以下是 JSON 的一部分的构造方式:
从上图中,我们可以观察到 requiredCore 的 JSONField 是通过函数 hpi.getRequiredJenkinsVersion() 从 HPI 分配的。现在我们来检查一下这个函数:
在此图像中,我们可以看到使用了函数 getManifestAttributes().getValue(“Jenkins-Version”),该函数从插件的 HPI 文件中的 Manifest 文件中检索 Jenkins-Version 键的值(在上面的清单示例中,它将返回 2.361.3)。
该代码验证获得的值是否不为 null,然后将其分配给前面提到的 requiredCore JSONField。因此,更新中心没有对 requiredCore 字段进行清理,从而允许攻击者在此字段中输入任何字符串。
总之,攻击者可以上传一个 HPI 文件,其中包含一个带有 Jenkins-Version 字段的 Manifest 文件,该文件可以不受限制地具有任何值。此值将插入到 JSON 的 requiredCore 字段中,该字段位于 https://updates.jenkins.io/update-center.json
CVE-2023-27905漏洞
更新中心也是一个网站,用户可以在其中浏览以查看可用的插件并检索有关它们的信息。这可以通过访问此 URL https://updates.jenkins.io/download/plugins/plugin_name/ 来完成
现在,让我们看看以下页面:
在此页面上,我们可以查看有关 script-security 插件的详细信息,包括每个插件版本的哈希值和所需的 Jenkins 服务器版本。
在前面的部分中,我们展示了攻击者如何通过修改插件的 Manifest 文件来操纵插件的 Jenkins-Version 属性,并且更新中心不会对此字段执行任何输入清理。现在,如果攻击者试图将 XSS 有效负载插入 Jenkins-Version 属性,例如:
<image src =q onerror=prompt(8)>
让我们检查一下生成此页面的代码:
从代码中可以看出,requiredJenkinsVersion 的值直接附加到 HTML 中,没有任何转义。
因此,攻击者可能会上传具有前面 Jenkins-Version 属性中显示的 XSS 有效负载的插件。
然后,当用户访问插件 https://updates.jenkins.io/download/plugins/attacker_plugin 的 URL 时,payload 将在他们的浏览器中执行:
此漏洞已被确定为 CVE-2023-27905,Jenkins 团队已在其托管网站上对其进行修补。
CVE-2023-27898漏洞
在我们之前的漏洞演示中,我们在 updates.jenkins.io 站点中发现了 User 上的 XSS,该 XSS 可能被用于各种恶意目的。由于我们的目标是识别 Jenkins 服务器上下文中对内部网络的潜在威胁,因此我们继续搜索。
鉴于攻击者可以控制上传到 Jenkins 更新站点的插件的 requiredCore 值,因此检查 Jenkins 服务器将如何处理此值至关重要。
Jenkins 服务器和 Jenkins 更新中心如何连接?
Jenkins 服务器与 Jenkins 更新中心交互,以获取有关可用插件的信息,并下载和安装 Jenkins 服务器的更新和插件。
Jenkins 服务器从 URL https://updates.jenkins.io/update-center.json 获取可用的插件列表 并存储其副本。
此列表会自动更新,也可以通过 Check now 按钮手动更新 Jenkins 服务器中的 Available Plugins 页面。
由攻击者控制的 requiredCore 值用在什么地方?
每当 Jenkins 管理员访问 Available Plugin Manager 页面 (http://<Jenkins_URL>/manage/pluginManager/available) 搜索插件时,
Jenkins 服务器从更新中心检索的可用插件列表由 Jenkins 服务器处理。
对于列表中的每个可用插件,Jenkins 服务器通过将插件的 requiredCore 插件版本与当前 Jenkins 服务器版本进行比较,来检查该插件是否是为较新版本的 Jenkins 服务器构建的。
如果为较新版本构建,Jenkins 服务器将返回以下消息:“警告:此插件是为 Jenkins {attacker control requiredCore} 或更高版本构建的。如果安装了此插件,Jenkins 将拒绝加载此插件。
此警告最终将由 available.hbs 文件呈现:
此处的问题是,之前的警告消息将使用三重存储 {{{ Handlebars 表示法呈现。这意味着,这些 triple-stash handlebars 表示法中的任何值都不会被转义。
在这种情况下,攻击者可以操纵警告消息中的 requiredCore 版本,从而允许消息中包含的恶意脚本执行而不会被正确转义。
总之,攻击者已将具有恶意核心版本的Jenkins插件上传到Jenkins更新中心,例如9.9.9<image src =q onerror=prompt(8)>
现在,由于恶意核心版本的Jenkins插件大于受害Jenkins服务器版本,因此会显示警告消息。(假设受害者的 Jenkins 版本为 2.270,这意味着恶意插件版本以 9.X.payload 根据 isForNewerHusdon 函数考虑更大版本的 Jenkins 服务器。
因此,每当 Jenkins 管理员访问可用插件管理页面 (http://<Jenkins_Server>/manage/pluginManager/available) 以安装或搜索插件时,恶意核心版本就会呈现,显示警告消息并触发 XSS。
需要注意的是,XSS 漏洞会在不安装任何恶意插件的情况下触发;源中存在恶意插件就足以激活漏洞。
分层机制
从上一节来看,攻击者似乎可以很容易地破坏世界上的每一个 Jenkins 服务器。然而,这并不完全准确。
Jenkins 团队实施了一种站点分层机制,以仅显示与当前 Jenkins 服务器兼容的插件,这意味着插件的 requiredCore 版本早于 Jenkins 服务器。由于 requiredCore 版本较旧,因此不会显示前面显示的警告消息,并且 requiredCore 值不会作为 HTML 处理,因此不会受到 XSS 的影响。
为了确定是否存在任何易受攻击的版本,我们必须对分层机制有基本的了解。
当 Jenkins 服务器想要更新可用插件的列表时,它会向更新中心的 JSON 发送请求以及与 Jenkins 服务器版本匹配的 version 参数,例如:https://updates.jenkins.io/update-center.json?version=2.332.3
然后,Update Center 使用此 version 参数将请求重定向到不同的 URL,该 URL 对应于不同的 JSON。例如,前面提到的 URL 将重定向到 https://updates.jenkins.io/dynamic-stable-2.332.3/update-center.json
此特定版本的 JSON 将包含需要 2.332.3 或更早版本的 requiredCore 的所有插件。
为了简单起见,我们不会深入研究完整的分层机制。尽管如此,请务必注意,并非所有版本都有单独的页面,最早拥有专用页面的版本是发布时间少于 400 天的版本(我们简化了此解释)。
因此,如果超过 400 天的 Jenkins 服务器版本发出请求,它将被重定向到具有单个页面的最旧版本。
例如,目前具有专用页面的最旧版本是 2.319.2。因此,如果具有早期版本(如 2.319)的 Jenkins 服务器提交以下请求:https://updates.jenkins.io/update-center.json?version=2.319.1
请求将被重定向到 https://updates.jenkins.io/dynamic-stable-2.319.2/update-center.json
我们知道,位于 https://updates.jenkins.io/dynamic-stable-2.319.2/update-center.json 的 JSON 包含需要 2.319.2 或更早版本的 requiredCore 的所有插件。尽管如此,发起请求的 Jenkins 服务器具有较旧的 2.319.1 版本。因此,Jenkins 服务器将收到需要比其自身版本更新的 requiredCore 版本的插件,因此会显示警告消息,如前所述。
在确定了显示警告消息的版本的存在之后,问题出现了:我们如何利用它?
为了实现这一点,我们需要选择带有页面的最旧版本,目前是 2.319.2(尽管由于 400 天的限制,它最终会发生变化)。然后,我们将其修改为较低的版本,例如 2.319.1.1,并附加我们的 XSS 有效负载。例如:
2.319.1.1 <image src =q onerror=prompt(8)>
现在,当管理员打开 Available Plugin Manager 页面时:
XSS 攻击成功,从而使攻击者能够在 Jenkins 服务器网站的上下文中在受害者的浏览器上执行任意 JavaScript。
这使得在撰写本文时,所有早于 2.319.2 的 Jenkins 版本都可以被利用。
从 XSS 到 RCE
在确定 XSS 攻击成功后,我们决定测试是否可以将其升级到 Jenkins 服务器上的 RCE。目前,我们的自定义 JavaScript 正在 Jenkins 管理员的浏览器上运行,为我们提供了与管理员相同的权限。这意味着我们可以执行管理员能够执行的任何任务,包括通过 Script Console API 在 Jenkins 服务器上运行 Groovy 代码。
在以下步骤中,我们将演示攻击者如何利用此漏洞,通过 Groovy Script Console 获取其计算机的反向 shell。
攻击者可能插入到 Manifest 文件的 Jenkins-Version 属性中的初始有效负载如下:
简而言之,有效负载指示浏览器从攻击者的服务器 https://attackers_machine/evil.js 检索 JavaScript 文件,并在 Jenkins 服务器范围内执行其内容。
以下是攻击者的服务器将提供给受害者的 JavaScript 文件 (evil.js) 的示例:
在 JavaScript 代码中,我们为 Groovy 中的反向 shell 有效负载指定了攻击者的 IP 地址和端口。
接下来,我们组合了所有必要的数据,并向 /script 端点发出了一个 POST 请求,以便在私有 Jenkins 服务器上执行 Groovy 代码。
恶意 Groovy 代码被 Jenkins Server 执行后:
攻击者的 C2 从受害者的 Jenkins 服务器接收到反向 shell!
现在,攻击者被授予对整个 Jenkins 基础设施的完全控制权。此级别的访问权限使攻击者能够操纵构建、将有害代码注入工件并执行其他恶意活动。
将恶意插件带到前面
默认情况下,Jenkins Server 仅在主源中显示下载最频繁的插件。
攻击者可以使用某些技术将恶意插件带到可用插件源的主页,或增加它在 Available Plugin Manager 页面上呈现的可能性:
-
由于搜索功能基于在插件描述中找到的任何关键字,因此攻击者可以通过上传包含描述中嵌入的所有插件名称和流行关键字的插件来利用此功能。
为了使其更难检测,攻击者可以在 HTML 标签中嵌入大量插件名称和流行术语,例如 <a> 标签,例如 <a href=“long_text”> .</a>
由于此标签是允许的,因此插件不会显得可疑。在我们的测试过程中,我们发现我们进行的几乎每次搜索都返回了恶意插件。 -
可以通过提交来自虚假实例的请求来增加特定插件的下载数量并提高其受欢迎程度。
攻击步骤摘要
第 1 步 | 攻击者创建了一个初始无辜的插件并获得上传权限。 |
步骤 2 | 攻击者使用 Jenkins-Version 属性中的 XSS 负载修改 HPI 文件。 |
步骤 3 | 攻击者将修改后的 HPI 上传到公共 Jenkins 构件注册表。 |
步骤 4 | 更新中心获取插件并将有效负载存储在可用插件的 JSON 中。 |
步骤 5 | Jenkins 服务器从 Jenkins 更新中心获取新的 JSON。 |
步骤 6 | 易受攻击的 Jenkins 服务器的管理员打开 Available Plugin Manager 页面。 |
步骤 7 | 攻击者的 XSS 有效负载被执行,通过 /script 端点以管理员的权限在 Jenkins 服务器上执行恶意命令。 |
步骤 8 | 攻击者入侵 Jenkins 服务器 |
披露时间表
16 1月 2023 | Aqua Research 团队向 Jenkins 安全团队报告了这些漏洞。 |
16 1月 2023 | Jenkins 安全团队证实了这些漏洞。 |
15 2月 2023 | Jenkins 发布了 update-center2 的修复程序,并修补了公共 Jenkins 更新中心。 |
8 3月 2023 | Jenkins 发布了 Jenkins 服务器的修复程序,并宣布了安全公告 CVE-2023-27898 和 CVE-2023-27905。 |
总结
从我们的研究中可以得出几个重要的教训。
首先,与超过 400 天的 Jenkins 可以立即利用相反,我们发现使用 400 天以下的 Jenkins 服务器容易受到这些漏洞的影响,但无法立即利用。但是,如果这些服务器没有更新并且仍然过时,它们将来可能会被利用。这强调了为环境的所有组件维护定期更新计划的重要性,这有助于防止已知和未知漏洞被利用。
其次,我们的研究强调了深度防御策略对保护环境的重要性。实施多层保护以保护环境及其组件免受漏洞影响至关重要。通过实施不同的安全措施,即使一个组件遭到入侵,其他保护层也可以减轻损害并防止攻击者升级攻击。
使用 Aqua Platform 进行预防
我们建议采用深度防御方法,在关键点使用多种控制措施来防止安全事件。
使用 Aqua Trivy 等工具扫描 SDLC 环境有助于确保您的 Jenkins 版本不易受到已知漏洞的影响。
我们建议实施进一步的控制措施来保护您的环境,以防您的环境中利用了任何漏洞。例如,您可以使用 Tracee 等开源工具扫描工作负载在运行时是否存在可疑和恶意行为。如果您使用 Aqua CNAPP,我们强烈建议您使用 CNDR。
该解决方案旨在使安全团队能够在开发的各个阶段使用强大的工具检测和防止网络攻击,例如防止下载和运行恶意元素的漂移预防,以及基于 eBPF 的工具,旨在检测运行时的恶意行为。
原文始发于微信公众号(菜鸟小新):CorePlague:Jenkins Server 中的严重漏洞导致 RCE
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论