Astrocamel - Blog/Portfolio of George Skouroupathis
https://www.astrocamel.com/web/2020/09/04/how-i-bypassed-cloudflares-sql-injection-filter.html
が元の記事で、さらっとまとめると
Cloudflareを使ってるサイトの脆弱性試験しようとしたら、そもそもサイトまでリクエストが届いてないことが判明
CloudflareのWAFで弾かれてるっぽいから、SQLのリクエスト難読化したら無事突破できたよ
って話です。この機能を回避するアプローチが面白かった。 ここでいう「難読化(obfuscation)」っていうのは、 SQLの意味はそのままに、Cloudflareのフィルタをパスできるクエリの加工のことのようです。 (CDNのレイヤで、リクエストの中身まで見て攻撃を防ぐみたいなことしてるの知らなかった・・・。)
あと、目的のサイトの脆弱性試験しようとしたら、Cloudflareの脆弱性試験になってるやんっていう。
具体的な流れのサマリーは以下の通り。
- 脆弱性試験の対象サイトはMySQL + PHPのよくあるサイト
- POSTリクエストでTime-based SQL Injection使って試験しようとした
- 何故かリクエストがサイトに届かない
- CloudflareのWAF(SQLインジェクションフィルタ)で弾かれてるっぽい
- どういうリクエストが弾かれるか調べよう
- 文字とか=とかをPOSTすると弾かれるっぽい
- いろいろSQL難読化したら無事突破できました
- 無事突破したことをCloudflareに報告したらTシャツゲットしたよ
みたいなことのようです。ここで出てくる「Time-based SQL Injection」ってのは、
Time-based SQL Injectionは意外に実用的だった | 徳丸浩の日記
https://blog.tokumaru.org/2015/04/time-based-sql-injection.htmlTime-based SQL Injectionとは…
特定の条件にヒットする場合にのみ一定秒数Sleepする、というSQL(sleep()関数とかを使って)をInjectionすることで、 ヒットする場合としない場合の応答時間の差を利用して情報を盗む手法のこと。
らしいです。へー。 (後で気づいたけど、かの有名な徳丸さんのサイトだった)
あ、あと全部のSQLインジェクションが弾かれるわけではなかったみたいなのでそこは注意。
結局この人の場合、Time-based SQL Injectionという手法が使えなかったため、 その時に試すことができたSQLインジェクションを使って、
- 結果が返りうるSQLをインジェクション(例:
... WHERE 'a' = 'a'): 200 OK - 結果が返らないSQLをインジェクション(例:
... WHERE 'a' = 'b'): 500 Internal Server Error
となる特性を発見し、これを利用してテーブル名やカラム名の特定を行う方法を探っていったみたい。
で、どうやって特定するのかというと、テーブルやカラム名が格納されているDBのメタテーブルに対して、
WHERE ‘a’ = メタテーブルの中のテーブル名の1文字目
WHERE ‘b’ = メタテーブルの中のテーブル名の1文字目
… と繰り返す。1文字目が分かったら
WHERE ‘a’ = メタテーブルの中のテーブル名の2文字目
WHERE ‘b’ = メタテーブルの中のテーブル名の2文字目
… と繰り返す。以下繰り返し
って感じでブルートフォース攻撃を行ったらしい。 この比較を行うSQLが実行されると、↑の通りサーバーとしては
- 合ってたら:
200 OK - 間違いなら:
500 Internal Server Error
となり、がっつりチェック可能ということになります。
で、具体的にどういうふうにSQLを難読化したかについては元の記事に詳しく載っているのでそちらを参照ください。
所感として、SQLインジェクション自体をさせないことも重要だけど、 エラーハンドリングが甘いと↑のように攻撃者に手がかりを与えてしまうことになるなーと痛感しました。