「Apache Tomcat」の脆弱性「CVE-2019-0232」を解説、遠隔からコードが実行される恐れ

Apache Tomcat」は、オープンソースのJavaサーブレットコンテナで、Apache Software Foundation(ASF)の支援を受けるコミュニティによって開発されました。このApache Tomcatは、「Java Servlet」、「JavaServer Pages(JSP)」、「Java Expression Language(EL)」、「WebSocket」を含むいくつかのJava EE の仕様を実装しており、Javaのみで記述された「ピュアJava」のHTTP Webサーバ環境を提供します。

セキュリティ企業「Nightwatch Cyber security」は、2019年4月15日、脆弱性「CVE-2019-0232」に関する情報を公開しました。この情報によると、Apache Tomcatの「Common Gateway Interface(CGI)」サーブレットに関して、遠隔からのコード実行(Remote Code Execution、RCE)の脆弱性が確認されました。この深刻度の高い脆弱性が悪用されると、攻撃者に任意のコマンドを実行されてしまう可能性があります。コマンドを実行するために、攻撃者はTomcatのCGIサーブレットが入力値を検証する際の不具合に起因するOSコマンドインジェクションを利用します。本記事では、この脆弱性の仕組み、可能性のある攻撃シナリオ、、そしてその脅威への対処について詳しく解説します。

■脆弱性「CVE-2019-0232」とは?

CGIサーブレットの仕組み

「CGI」は、Webサーバが、コンテンツを生成する外部プログラムとやり取りする方法を定義したプロトコルです。Tomcatはこの仕組みを使用し、Java仮想マシン(JVM)の外部でCGIスクリプトと呼ばれるそれらの外部プログラムを実行します。この時、CGIサーブレットは、クエリ文字列からコマンドライン引数を受け取って外部プログラムを実行します。CGIサーブレットは、デフォルトでは無効になっています。ただし、CGIサーブレットの設定で「enableCmdLineArguments」が有効かつWindowsを使用している場合、Java Runtime Environment(JRE)のWindowsへのコマンドライン引数の渡し方にバグが存在することによって、遠隔からのコード実行脆弱性に対して脆弱となります。

Apache Tomcatは、web.xmlファイルを使用して、Tomcatのインスタンスに読み込むすべてのWebアプリケーションのデフォルト値を定義します。 ここで設定されているCGIサーブレットは、デフォルトで提供されているサーブレットの1つです。このサーブレットは、CGI仕様に倣った外部プログラムの実行をサポートしています。通常、CGIサーブレットはURLパターン「/cgi-bin/*」にマッピングされます。つまり、実行されるCGIスクリプトはWebアプリケーション内に存在する必要があります。

Windowsにおけるコマンドライン引数の処理

以下のフローチャート(図1)は、Windowsがコマンドライン引数を処理する全体的な流れを示しています。「program.exe」という名前の実行ファイルは解説のための例です。

図1:Windowsにおけるコマンドライン引数処理の全体的な流れ
図1:Windowsにおけるコマンドライン引数処理の全体的な流れ

Windows OSで、新しいプロセスは「CreateProcess()」関数を呼び出すことによって起動されます。この関数は以下のように、パラメータ「lpComandLine」の引数としてコマンドラインを文字列として受け取ります。

  • int CreateProcess( …, lpComandLine, … )

図1で「CreateProcess()」関数に与えられている引数「Cmdline」は以下の通りです。

Cmdline = “program.exe hello world”

Windowsでは、引数は文字列の配列として個別に渡されるというよりは、1つのコマンドライン文字列として渡されます。これを実行するには、まずAPI「GetCommandLine()」を使用してコマンドライン文字列を抽出し、ヘルパー関数「CommandLineArgvW()」を使用して引数の文字列を解析することによって、プログラムがコマンドライン自体を解析する必要があります。
上記コマンドライン「Cmdline」は以下のような配列として構文解析されます。

Argv[0]->program.exe
Argv[1]->hello
Argv[2]->world

脆弱性「CVE-2019-0232」の原因

この脆弱性は、JREからWindowsへの不適切なコマンドライン引数渡しが原因で起こります。
以下の図2は、Javaアプリケーションにおけるコマンドライン引数渡しの全体的な流れを示しています。

図2:Javaアプリケーションにおけるコマンドライン引数処理の全体的な流れ
図2:Javaアプリケーションにおけるコマンドライン引数処理の全体的な流れ

Javaアプリケーションでは、「CreateProcess()」関数が起動する前に「ProcessBuilder()」関数が呼び出されます。そして、引数は、OSに依存したクラス「ProcessImpl」のstaticメソッドに渡されます。「ProcessImpl」クラスのWindowsにおける実装では、startメソッドが「ProcessImpl」クラスのprivateコンストラクタを呼び出します。これにより、「CreateProcess()」関数を呼び出すためのコマンドラインが生成されます。こうして、コンストラクタ「ProcessImpl()」は引数「Cmdline」を作成し、Windowsの「CreateProcess()」関数に渡します。その後、「CreateProcess()」関数はシェル環境「cmd.exe」で.batファイルと.cmdファイルを実行します。実行するファイルの拡張子が.batまたは.cmdの場合、実行されるプロセスはWindowsのコマンドプロンプトであるcmd.exeになります。次に、処理は「CreateProcess()」関数の最初の段階から再開し、パラメータとフラグの検証が行われ、バッチファイルの名前がオプション「/c」に続く最初のパラメータとしてcmd.exeに渡されます。
その結果、例えば「hello.bat」というバッチファイルを実行するコマンド「hello.bat…」は「C:\Windows\system32\cmd.exe/c “hello.bat…”」となります。「CommandLineToArgvW」関数の引用規則はcmd.exeのものとは異なるため、cmd.exeが解釈するコマンドラインに対するコマンドインジェクションを回避するためには、追加の引用規則を適用する必要があります。
Javaの「ProcessImpl()」は、渡された引数に対して暗黙的にcmd.exeが呼び出されるこのようなコマンドラインの変換に対して、引用符を追加しません。そのため、cmd.exeに渡された不適切な引数が実行されるという課題が存在します。これがCVE-2019-0232の原因です。

■cmd.exeによる引数の構文解析

cmd.exeは本質的にテキストのプリプロセッサです。コマンドラインが与えられると、cmd.exeは一連のテキスト変換を行い、「CreateProcess()」関数に渡します。
テキスト変換により、環境変数は値に置き換えられます。演算子である「&」や「||」、「&&」を目印としてコマンドラインはいくつかの部分に分割されます。そして、cmd.exeのテキスト変換はすべて以下のいずれかのメタ文字が存在することによって実行されます。

  • (
  • )
  • %
  • !
  • ^
  • <
  • >
  • &
  • |

cmd.exeがコマンドラインを変換して「”」を発見した際、新しいコマンドラインに「”」がコピーされます。そして、古いコマンドラインから新しいコマンドラインへと文字がコピーされ始めます。これは、他の文字がメタ文字かどうか確認することなく、処理がコマンドラインの最後に到達するか、変数の代入に遭遇するか、または別の「”」を確認するまで続きます。これはメタ文字「“」において特に興味深い点です。
引数を保護するためにcmd.exeの「“」に関する動作に依存している場合、引用符を使用すると予期しない動作が発生します。信頼できないデータをコマンドラインパラメータとして渡すことによって、この規約の不一致によって引き起こされるバグがセキュリティ上の問題となります。
例えば、以下のコマンドが与えられたとします。

hello.bat “dir \”&whoami”
0: [hello.bat]
1: [&dir]

ここで、cmd.exeはメタ文字「&」をコマンドの区切り文字として解釈します。これは、cmd.exeから見て、「&」が引用符で囲まれた領域の外側にあるためです。このシナリオでは、「whoami」という部分を任意の数の不正なコマンドに置き換えることができます。「hello.bat」を使用して上記のコマンドを実行すると、以下の図3において示されているような出力が得られます。

図3:「hello.bat」を実行したときの結果の出力
図3:「hello.bat」を実行したときの結果の出力

以下の図4では、Apache Tomcatにおいて不正なコマンド実行が成功してしまっているという問題が示されています。

図4: 「Apache Tomcat」でのコマンドの実行
図4: 「Apache Tomcat」でのコマンドの実行

コマンドインジェクションに成功するには、「web.xml」ファイルでいくつかのパラメータを追加して「CGIサーブレット」を有効にする必要があります。

図5:「web.xml」ファイル
図5:「web.xml」ファイル

Apache Software Foundationは、CVE-2019-0232に対処するために設計された新しいパラメータ「cmdLineArgumentsDecoded」をApache Tomcat CGIサーブレットに導入しました。このパラメータは「enableCmdLineArguments」がtrueに設定されている場合のみ使用されます。さらに、個々のデコードされたコマンドラインが一致しなければならない正規表現のパターン「[[a-zA-Z0-9\Q-_.\\/:\E]+]」が定義されています。コマンドライン引数がこのパターンに一致しない場合、要求は拒否されます。この導入された修正プログラムは、コマンドライン引数においてスペースと二重引用符を使用することから生じる脆弱性を排除します。

図6:修正プログラムで追加された「Apache Tomcat」のコード
図6:修正プログラムで追加された「Apache Tomcat」のコード

■被害に遭わないためには

Apache Software Foundationはユーザに対して、Apache Tomcatを最新のバージョンに更新することを推奨しています。以下の表はApache Tomcatのバージョンとそれに対応する推奨パッチです。

バージョン 推奨パッチ
Apache Tomcat 9 Apache Tomcat 9.0.18 以降
Apache Tomcat 8 Apache Tomcat 8.5.40 以降
Apache Tomcat 7 Apache Tomcat 7.0.93 以降

さらに、CVE-2019-0232の悪用を防ぐために、ユーザはCGIサーブレット初期化パラメータ「enableCmdLineArguments」をFalseに設定する必要があります。

■トレンドマイクロの対策

「Apache Tomcat」を使用している開発者、プログラマ、およびシステム管理者は、総合サーバセキュリティ「 Trend Micro Deep Security 」や、 「Trend Micro Virtual Patch for Endpoint(旧 Trend Micro 脆弱性対策オプション) 」のような多層セキュリティ技術を検討することも可能です。これらのソリューションをご利用のお客様は、以下の DPIルールによってこの脆弱性を利用する脅威から保護されています。

  • 1009697 – Apache Tomcat Remote Code Execution Vulnerability (CVE-2019-0232)

ネットワーク脅威防御ソリューション「TippingPoint」は、以下のMainlineDV filterにより今回の脅威をブロックします。

  • 315387 – HTTP: Apache Tomcat Remote Code Execution on Windows

参考記事:

翻訳: 下舘 紗耶加(Core Technology Marketing, TrendLabs)