シェルコマンドインジェクションでのスペース禁止フィルタの回避(${IFS})
概要
コマンドインジェクションの対策として、入力文字列からスペース(半角空白)を単純に禁止・除去しているだけのフィルタが存在することがある。しかし、シェル上ではコマンドの引数区切りに使われる文字はスペースだけではない。$IFS(Internal Field Separator)はシェルが単語分割に使う区切り文字を保持する環境変数で、既定値には空白文字が含まれている。これを ${IFS} という変数展開の形で埋め込むと、シェルによって実行時に空白文字へ展開されるため、入力文字列自体にはスペースが含まれないままコマンドを区切って実行できる。
echo "hello"
echo${IFS}"hello"
上の 2 行は、シェル上では同じ意味になる。echo${IFS}"hello" という文字列にはスペースが 1 文字も含まれていないため、「スペースを含む入力を拒否する」だけのフィルタを素通りする。
手順
- 対象の入力フィルタが、スペース文字そのものを拒否・除去しているだけかを確認する(他の区切り文字やエンコードまでは見ていないか)。
- コマンドの引数区切りに使いたい箇所を、スペースの代わりに
${IFS}に置き換える。 - 置き換えたペイロードを送信する。
コマンド
cat${IFS}/etc/passwd
注意点
${IFS}はあくまで「スペース 1 文字を禁止しているだけのフィルタ」に対する回避策。フィルタが正規表現で区切り文字全般(タブ、$IFSのような変数展開自体)まで見ている場合は通らない。- 同様の考え方で、
$IFS$9($9が空文字列に展開されることを利用して$IFSの直後をトークンとして区切る)のような亜種や、ブレース展開・タブ文字での代替など、スペース以外の手段で単語を区切る回避パターンも存在する。「スペースだけを弾く」フィルタは原理的に突破されやすいと考えてよい。