技術者ブログ
クラウド型WAF「Scutum(スキュータム)」の開発者/エンジニアによるブログです。
金床“Kanatoko”をはじめとする株式会社ビットフォレストの技術チームが、“WAFを支える技術”をテーマに幅広く、不定期に更新中!
table_to_xml関数とSQLインジェクション
はじめに
前々回の記事ではサブクエリを「(select」ではない形で書けるようになったことによってWAFが回避されるケースがあるという例について触れました。今回の記事では、PostgreSQLの特定の関数をSQLインジェクションに使うケースを見ていきます。
table_to_xmlという特殊な関数
PostgreSQLで2008年頃から使えるようになった関数の1つとして、table_to_xmlがあります。
test=# select table_to_xml('pg_shseclabel',true, false, ''); table_to_xml ----------------------------------------------------------------------- <pg_shseclabel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">+ + </pg_shseclabel> + (1 行)
上の例のように、この関数は、引数にテーブル名を指定するとそのテーブルの中身が全てXMLに変換された形で取得できる、という非常に珍しいものです。私の知っている限りでは、他のRDBにはこのような「引数にテーブル名を受け取る」関数はありません。
次のようにすれば、データベースの中身を文字列を使って検索することができます。例えば、w3.orgという文字列を検索してみます。
test=# select position ( 'w3.org' in table_to_xml('pg_shseclabel',true, false, '')::text ); position ---------- 38 (1 行)
SQLインジェクションにおけるtable_to_xmlの意味
この「引数にテーブル名を受け取る」という特徴を使うことで、攻撃者がWAFを回避してSQLインジェクション攻撃を行う可能性があります。
例として、最もありがちなパターンのSQLインジェクションである、where句の右の条件部分へインジェクションが可能なケースを考えます。
select * from users where userid = ' [ここにインジェクション] ...
このselect文はテーブルとしてはusersにのみアクセスするものです。そのため攻撃者はusersテーブルについては、where句の条件部分をコントロールすることにより、データを盗むことができてしまいます。このような状況でusers以外のテーブルにアクセスするためには、次の2つの方法を使うのが一般的です。
- UNION
- サブクエリ
どちらもウェブセキュリティの教科書に乗っているような良く知られた手法です。そのため、多くのWAF(※1)は「UNION SELECT」や「(SELECT」などを含むSQLインジェクションは、かなりの確率で止めます。
table_to_xmlはUNIONとサブクエリに続く、「他のテーブルのデータにアクセスする」ための第三の方法になります。
筆者が調べてみたところ、いくつかのシグネチャ依存型のWAFはこの「table_to_xmlを使うことで、他のテーブルにまでアクセスする」攻撃を止めることができませんでした。table_to_xmlという文字列自体はそれほど一般的なものではないと考えられるため、シグネチャで止めるのに向いている、言い換えると誤検知をあまり起こさない、止めやすい性質のものです。つまりそれらのWAFには単純に、「table_to_xmlという文字列を含んでいたらブロックする」というようなシグネチャは(少なくとも筆者の調査時点では)存在していなかったのだろうと推測しています。
table_to_xmlをはじめとする「テーブル名を引数に取る」関数は、UNIONやサブクエリと同じレベルの危険性を持つものなので、WAFに対しては、積極的に止めることが求められていると考えています。
Scutum開発チームでは数年前にこの関数が危険であることに気づいたので、これらのPostgreSQLの関数を利用する攻撃に関しても以前から対応済みです。
PostgreSQLとSQLインジェクション
「もしSQLインジェクションの脆弱性が存在する場合に、そこから、その脆弱性を利用してどんな事まで出来てしまうか?」という点については、昔から複数のRDBに対して多くの研究・考察が行われてきました。かつてはMicrosoft SQL Serverがxp_cmdshellという最凶のストアドプロシージャによって名を馳せていましたが、当然ながら危険すぎるためデフォルトでは無効となりました。
最近では意外にPostgreSQLの危険度が高いことが知られつつあり(※2)、またMySQLがOracleに買収された後にPostgreSQLの人気が高まっていることから、攻撃者の注目を集めるようになっています。
この記事で紹介したtable_to_xmlを使う攻撃手法は、以前はtable_to_xmlとsql injectionというキーワードで検索してもロシア語のファイルが1つヒットするだけで、ほぼ知られていない状態でした。しかし最近になり、ポツリポツリと英語の記事もヒットするようになっているので、日本語の情報としてもそろそろ紹介するべきタイミングになってきたと考えます。
table_to_xmlもかつてのxp_cmdshellと同じく、99%の実環境では必要がないものであるにも関わらず、攻撃者にとっては非常に有用な存在となってしまっています。このような関数はデータベースサーバをセットアップしたデフォルトの状態では使用できないようになっていることが好ましいのですが、PostgreSQLはまだまだその辺はゆるいというか利便性重視というか、あまりセキュリティが考慮されていないように思えます。
SQLインジェクション対策は昔と同じ
この記事は「PostgreSQLって結構危ないの?」という印象を与えてしまうかもしれませんが、基本的に述べているのは「もしウェブアプリケーション側に、SQLインジェクションの脆弱性があったら...」という仮定が満たされた場合についての話です。
ウェブアプリケーションをきちんと構築し、SQLインジェクションの脆弱性が存在しなければ、table_to_xmlなどを利用したPostgreSQLへの攻撃はできません。SQLインジェクションの対策は昔から変わらず、バインド機構をできるだけ利用し、文字列連結でSQL文を組み立てるようなことを避け、ユーザ入力がSQL文に自由に入り込まないようにすることです。
きちんとSQLインジェクション対策が行われていれば、PostgreSQLを利用することには何も問題はありません。筆者も昔から多くの環境で利用している、ポスグレ愛好者です。
まとめ
今回はPostgreSQLに存在するtable_to_xmlがUNIONやサブクエリに続く重要な攻撃のパーツとして使われる可能性があること、そしてこの攻撃を止められないシグネチャ依存型WAFが存在することについて紹介しました。PostgreSQLには他にもいくつか似たような関数があるので、一度ドキュメントに目を通すことをおすすめします。
※1: Scutumも含む
※2: https://pulsesecurity.co.nz/articles/postgres-sqli