オープンソースの脆弱性対策に学ぶ ~DrupalのSQLインジェクション対策(SA-CORE-2015-003、CVE-2015-6659)~ 4/4
Drupal ver.7.39で対策されたSQLインジェクションの脆弱性についてご紹介してまいりましたが、いよいよまとめです。
タネ明かし
SQLインジェクションの脆弱性の問題が顕在化するのは、除去処理後に除去した前後の文字列が連結した結果、新たにブロックコメント終端「*/」が生成されるパターンです。
例えば「**//’」が値に含まれる場合を考えます。
除去処理によって2文字目と3文字目の「*/」が除去され、1文字目と4文字目が連結されます。
その結果、「*/’」がブロックコメント「/* ~ */」の内部に埋め込まれます。
組み立てられたSQL文中には「/* ~*/’~ */」が含まれています。
後半の「’~ */」の部分によって、SQLの構文エラーが発生すると考えられます。
以下のソースコードはSQLの構文エラーを発生させます。
$param = "**//'"; $query = db_select('users', 'u') ->comment($param) ->condition('u.uid', 0, '<>') ->fields('u', array('uid', 'name', 'status', 'created', 'access')) ->range(0, 50);
組み立てられたSQL文
/**/'*/SELECT uid, name, status, created, access FROM {users} u WHERE uid <> 0 LIMIT 50 OFFSET 0
今回の教訓
SQLコメントの位置に外部から渡される値を埋め込むケースはあまり多くはないと思いますが、もしそのように実装したいのであれば、値のチェックを行うことになります。
しかし、値のチェックは案外難しいものです。
今回のケースでは、複数文字からなる部分文字列を除去する処理で、除去処理後に除去した前後の文字列を連結することで再び除去した部分文字列が生成される論理の抜けが生じていました。
$val = 'ababcdecde';' $ret = preg_replace('/abcde/', '', $val);//部分文字列「abcde」を除去する処理 echo "$ret";//結果「abcde」と表示される
ちなみに
仮にdrupal ver.7.38以前に対してWebアプリケーション脆弱性診断を実施した場合、パラメータ改ざん検査でこの脆弱性を検出するのはかなり難しいのではないかと予想しています。
SQLコメントを除く全ての位置で、検査文字列「’」はSQLの構文エラーを発生させることを期待できます。
しかし、SQLコメントの位置に値を埋め込むこの脆弱性を検出するには有効ではありません。
SQLコメントに対しては検査文字列「*/」や「*/’」が有効と考えられますが、そもそもWebアプリケーションを外から観察して、SQLコメントの位置に外部から渡される値が埋め込まれていることに気付けるかは大分疑問です。
しかも、これらの検査文字列でも今回の脆弱性を検出するには有効ではないのです。
SQLコメントの位置に埋め込む値に対する無害化処理の論理の抜けを想定して、検査文字列「**//’」を試せるかというともう・・・orz
おしまい。