Micro0トレンドマイクロは、人気のあるオープンソースの自動化サーバ「Jenkins」の初期設定で、限られた権限のユーザが管理者権限を取得し、遠隔から任意のコードを実行できる可能性があることを確認しました。本記事では、このセキュリティ課題の詳細と想定される攻撃シナリオについて解説します。■「Jenkins」とはJenkinsは、ソフトウェア開発チームのDevOpsにおいて開発側の作業を管理するために使用される人気のあるオープンソースの自動化サーバです。CD)プロセスにおいてソフトウェアプロジェクトを自動的にビルドすることが可能です。このようなタスクはジョブと呼ばれます。Jenkinsは分散型アーキテクチャに基づいて実装されています。Jenkinsがインストールされた「マスター」は、「スレーブ」と呼ばれるエージェントのグループを管理します。スレーブの実体は遠隔のコンピュータで実行されているJavaの実行可能ファイルで、これらのスレーブがビルドジョブを実行します。Jenkinsはモジュール型のアーキテクチャを採用しており、ビルド後のタスクのようにコア機能を拡張する機能のほとんどはプラグイン内に実装されています。Jenkinsは、「行列による権限設定」によってセキュリティ機能を提供します。Hub」から公式イメージを取得するだけで容易に使用可能です。派生した革新的なソリューションを利用し、既定ではありませんがマトリックス認証を通じてセキュリティの側面も補っています。初期設定のまま行列による権限設定を有効化するだけで、セキュリティがすでに安全に設定されていると思い込むのは禁物です。残念なことに、トレンドマイクロはこの設定が潜在的なセキュリティ問題に繋がる可能性があることを確認しました。弊社による解析の結果、ジョブがマスターつまりメインのJenkinsサーバで構築されるという初期設定のもと、限られた権限しか持たないユーザアカウントがマスターに対する管理者権限を取得できることを確認しました。これを利用する攻撃コードは、既定のビルド手順であるシェル生成を使用して簡単に作成することができます。Execution、RCE)が可能になるため、Jenkinsが完全に上書きされてしまう恐れがあります。設定がセキュリティ上安全でないもしくは弱い場合、サーバは前述の設計機能を利用する攻撃を受けやすくなります。これに関して、弊社は独自に解析を行い、この調査から得られた内容をすでにJenkinsプロジェクトに提供しました。これに対して、Jenkinsは、Jenkinsが提供するユーザハンドブックとウィキ(Wiki)に記載されている情報を元に、トレンドマイクロが提供した調査結果はセキュリティ上の脆弱性によるものではないと回答しました。■Jenkinsにおけるセキュリティの初期設定についての考察Jenkinsのセキュリティページによると、Jenkinsバージョン2.0では、管理者が特定のオプションを明示的に無効化しない限りは、Jenkins環境の安全性を維持するために初期設定によって多くのセキュリティオプションが有効化されています。Jenkinsのセキュリティは、「グローバルセキュリティの設定」ページで設定可能です。初期設定では、セキュリティレルム(認証)として「Jenkinsのユーザデータベース」が有効化されています。このユーザデータベースはマスターに保存されていて、注視すべき点はこの初期設定の下でログインしたユーザはJenkisが持つすべての機能にアクセス可能であるということです。Jenkinsの「行列による権限設定」Jenkinsでは、「行列による権限設定」や「行列による権限設定(プロジェクト単位)」などの権限管理オプションを有効にすることで、管理者は特定のJenkins機能へのアクセスを制限することが可能です。■マスターにおけるシェル生成の実行Jenkinsのセキュリティ設定が弱い場合、この隙を攻撃者に利用されてしまう可能性があります。ここでは、この隙を突く攻撃がどのようにして発生する可能性があるかを示す前に、まずはジョブを実行する際に行われる手順を解説します。CD)の流れにおける基本的な処理です。トリガーを契機にビルドを開始ソースコード管理(SCM)システムに対する定期的な問い合わせ(SCMポーリング)ビルド環境を設定ビルド手順を実行(コンパイラの設定など)ビルド後の処理(テストの実行、展開など)ビルド手順をスクリプトによって実行する機能は、Jenkins内にインストールされたプラグインを使用して拡張することが可能です。本記事で焦点を当てて解説する「シェルの実行」は「ビルド手順の追加」内の既定の機能の1つです。Webアプリケーション内のビルドスクリプトに使用可能なあらゆる機能を実装する代わりに、ビルド処理をシェルスクリプトに記述する方法は、開発者にとって一般的な方法であり、これにより効率的にビルド処理を行うことが可能です。Webアプリケーション内でシェル生成を実行すると、特にユーザのアクセス許可が正しく管理されていない場合、セキュリティ上の脅威が生じると考えられます。Jenkinsを利用するユーザに不要な権限を許可することは、セキュリティが侵害されてしまう可能性があるため、セキュリティ衛生上問題となります。Security」というプラグインは、このような脅威に対処するためにホワイトリストベースのサンドボックスを使用して信頼できないGroovyスクリプトの実行を制限することが可能です。Groovyスクリプトは、管理者の承認を得て、またはサンドボックス内にある場合にのみ実行できます。サンドボックスは、ユーザがJenkinsインスタンスを妨害し「Jenkins.getInstance()」のような内部関数を呼び出すことができるような状況を回避するために使用されます。この事とは対照的に、「シェルの実行」機能は制限されておらず、管理者による承認を必要としないため、権限を持たないユーザにシェルを起動してスクリプトを実行することを許します。そのため、もしジョブがマスターで実行される場合セキュリティ上のリスクが発生します。前述の通り、初期設定ではジョブがマスターで実行されるように設定されています。マスターは、Jenkinsの設定、アプリケーションのバイナリ、ジョブ定義、およびユーザデータベースを格納しています。ジョブはJenkinsアプリケーションと同じユーザの下で実行され、ジョブの作業ディレクトリはJenkinsのホームディレクトリ「JENKINS_HOME」内にあるため、相対ファイルパスを使用した設定ファイルへのアクセスが許可され、Jenkinsファイルの読み取り、書き込み、実行が可能になります。■起こりうる攻撃シナリオJenkinsの初期設定に依存するとセキュリティ上の脅威が生じる可能性があることを示すために、次のシナリオを見てみましょう。Jenkinsは、推奨されているプラグインと行列による権限設定を持った状態でインストールされますが、エージェントのための設定は行われていません。この設定の下では、限られた権限しか持たないユーザは以下の図2に示されている権限を利用してログインします。上記のユーザ権限を利用すると、攻撃者はシェルスクリプトを作成することによって不正なジョブを作成または変更することができます。この設定の下で攻撃者が使用可能なツールはオペレーティングシステム(OS)によって決まります。Dockerコンテナのように、echo、sed、Python、およびwgetなどのバイナリが含まれるLinux環境で実行されている場合、攻撃者は遠隔からのコード実行を行うためのさまざまな手段を検討することができます。遠隔からのコード実行を通して、攻撃者は以下のような動作を実行可能です。Concept、PoC)攻撃者はsedを使用して以下のシェルコマンドを実行することが可能でしょう。../../onfig.xml3.図3:マスター上でシェルにアクセスすることが可能このシェルコマンドが実行された場合、「グローバルセキュリティの設定」ページのチェックボックス「セキュリティを有効化」を無効にし、Jenkinsが設定ファイルをディスクから再度読み込むと、すべてのユーザに管理者アクセス権が与えられます。■被害に遭わないためにはJenkinsの管理者はJenkinsのセキュリティと適切な設定における全責任を担っています。一般的に、最小権限の原則を実装する必要があります。ユーザのアクセス権限を、タスクを実行するための必要最低限の範囲に制限することで、アカウントの悪用またはハイジャックのリスクを減らすことが可能です。ユーザがサービスやソフトウェアを利用していない場合は、これらを制限、置き換え、または完全に無効化することを検討する必要があります。既定のセキュリティ設定をそのまま利用することに伴うリスクは、シェルの悪用だけではなく、マスターでの不正なコードの実行も含まれます。そのため、マスターノードにおけるジョブの実行を無効化することを推奨します。スレーブ環境で実行されるジョブはマスターとは隔離されているためマスターの設定ファイルにはアクセスすることはできません。そのため、コンテナのようなスレーブ環境でシェル生成を使用しても、マスターの設定を不正に操作することはできません。Jenkinsは、このユーザ権限の問題に関する警告と推奨事項をすでに公開しています。Project」プラグインの使用を推奨しています。潜在的な不正利用をさらに防ぐために、遠隔からのコード実行を可能にするプラグインの中でも、特にシェルはユーザが必要としない場合無効にすることを推奨します。「システムの設定」ページで「シェル実行ファイル」のパスに「/bin/false」を設定することで、シェルの実行を制限することが可能です。この設定により、「/bin/false」がバイナリとして実行されますが、この引数がシェルスクリプトに渡されると、アプリは終了し、入力はすべて破棄されます。