シェルコマンドインジェクションでのスペース禁止フィルタの回避(${IFS})

web command-injection bypass

概要

コマンドインジェクションの対策として、入力文字列からスペース(半角空白)を単純に禁止・除去しているだけのフィルタが存在することがある。しかし、シェル上ではコマンドの引数区切りに使われる文字はスペースだけではない。$IFS(Internal Field Separator)はシェルが単語分割に使う区切り文字を保持する環境変数で、既定値には空白文字が含まれている。これを ${IFS} という変数展開の形で埋め込むと、シェルによって実行時に空白文字へ展開されるため、入力文字列自体にはスペースが含まれないままコマンドを区切って実行できる。

echo "hello"
echo${IFS}"hello"

上の 2 行は、シェル上では同じ意味になる。echo${IFS}"hello" という文字列にはスペースが 1 文字も含まれていないため、「スペースを含む入力を拒否する」だけのフィルタを素通りする。

手順

  1. 対象の入力フィルタが、スペース文字そのものを拒否・除去しているだけかを確認する(他の区切り文字やエンコードまでは見ていないか)。
  2. コマンドの引数区切りに使いたい箇所を、スペースの代わりに ${IFS} に置き換える。
  3. 置き換えたペイロードを送信する。

コマンド

cat${IFS}/etc/passwd

注意点

  • ${IFS} はあくまで「スペース 1 文字を禁止しているだけのフィルタ」に対する回避策。フィルタが正規表現で区切り文字全般(タブ、$IFS のような変数展開自体)まで見ている場合は通らない。
  • 同様の考え方で、$IFS$9($9 が空文字列に展開されることを利用して $IFS の直後をトークンとして区切る)のような亜種や、ブレース展開・タブ文字での代替など、スペース以外の手段で単語を区切る回避パターンも存在する。「スペースだけを弾く」フィルタは原理的に突破されやすいと考えてよい。