GitHub Actions

允许的不安全命令

有一些已弃用的 set-envadd-path 工作流命令,可以通过将 ACTIONS_ALLOW_UNSECURE_COMMANDS 环境变量设置为 true 来显式启用。

  • set-env 通过以下工作流命令设置环境变量 ::set-env name=<NAME>::<VALUE>

  • add-path 通过以下工作流命令更新 PATH 环境变量 ::add-path::<VALUE>

根据环境变量的使用情况,在最坏的情况下,这可能允许攻击者更改路径并运行非预期的命令,导致任意命令执行。例如,考虑以下工作流:

name: 易受攻击的工作流

on:
  pull_request_target

env:
  # 1. 启用不安全命令
  ACTIONS_ALLOW_UNSECURE_COMMANDS: true
  ENVIRONMENT_NAME: prod

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      # 2. 打印 github 上下文
      - run: |
          print("""${{ toJSON(github) }}""")
        shell: python
      - name: 创建新的 PR 部署
        uses: actions/github-script@v5
        with:
          # 3. 创建部署
          script: |
            return await github.rest.repos.createDeployment({
                ...context.repo,
                ref: context.payload.pull_request.head.sha,
                auto_merge: false,
                required_contexts: [],
                environment: "${{ env.ENVIRONMENT_NAME }}",
                transient_environment: false,
                production_environment: false,
            });
          github-token: ${{ secrets.GITHUB_TOKEN }}

上述工作流通过在 env 部分将 ACTIONS_ALLOW_UNSECURE_COMMANDS 设置为 true 来启用不安全命令。可以看到,deploy 作业的第一步将 github 上下文打印到工作流日志中。由于 github 上下文中的部分变量是用户控制的,可能滥用不安全命令来设置任意环境变量。例如,攻击者可以使用拉取请求描述来传递以下payload,当打印 github 上下文时,这将重置 ENVIRONMENT_NAME

\n::set-env name=ENVIRONMENT_NAME::", <YOUR_JS_CODE>//\n

请注意,在2020年5月,GitHub 弃用了这些不安全的工作流命令。从那时起,GitHub 推荐使用环境文件:

然而,GitHub 仍然提供 ACTIONS_ALLOW_UNSECURE_COMMANDS 环境变量来启用已弃用的命令,以保持向后兼容性。

现在让我们看看上述payload的工作原理:

由于 payload 使用了 ::set-env name=ENVIRONMENT_NAME:: 命令,它将把环境变量 ENVIRONMENT_NAME 重置为 ", <YOUR_JS_CODE>//。因此,在 github-script 中,environment 将被设置为 ", <YOUR_JS_CODE>// 而不是 prod。然后,攻击者可以通过精心设计的 YOUR_JS_CODE 注入任意 JavaScript 代码。

实际上,github-script 的实现使用 new Function(...) 来评估 JavaScript 代码,这可能导致远程代码执行。

参考资料

脚本注入

GitHub Actions 允许您使用各种shell在运行器上执行命令。这些shell包括 bashpwshpowershellpython。然而,在某些情况下,GitHub Actions 会将用户控制的输入直接传递给shell命令,这可能导致命令注入。

例如,考虑以下易受攻击的工作流:

name: 易受攻击的工作流

on:
  pull_request_target

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 获取 PR 编号
        id: pr-number
        run: |
          echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
      - name: 注入命令
        run: |
          # 用户控制的输入
          PR_NUMBER=${{ env.PR_NUMBER }}

          # 直接传递给 shell
          echo "Processing PR #$PR_NUMBER"

          # 易受攻击的命令执行
          ./deploy.sh --pr $PR_NUMBER

在上述示例中,攻击者可以通过将恶意payload注入到PR标题或描述中来执行任意命令。例如,如果攻击者创建一个标题为 1; rm -rf / 的PR,这将导致执行 rm -rf / 命令。

为了防止此类攻击,应该:

  1. 验证和清理所有用户控制的输入

  2. 使用安全的参数传递方法

  3. 避免直接将用户输入传递给shell命令

参考资料

权限提升

GitHub Actions 运行器默认具有与仓库相同的权限。在某些情况下,这可能导致权限提升,特别是当工作流使用敏感的 secrets.GITHUB_TOKEN 时。

考虑以下示例:

name: 易受攻击的工作流

on:
  pull_request_target

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 创建 PR 部署
        uses: actions/github-script@v5
        with:
          script: |
            // 攻击者可以修改此代码
            return await github.rest.repos.createDeployment({
                ...context.repo,
                ref: context.payload.pull_request.head.sha,
                auto_merge: false,
                required_contexts: [],
                environment: "production",
                transient_environment: false,
                production_environment: false,
            });
          github-token: ${{ secrets.GITHUB_TOKEN }}

在上述示例中,攻击者可以通过修改 github-script 来创建生产环境的部署,即使原始工作流只打算用于测试环境。

参考资料

最后更新于