###### tags: `SQLI` `日文` # SQL injection ## 仕組み 一般的にログイン画面のSQL文は ```sql= SELECT * FROM users WHERE id='XXX' AND password='YYY' ``` (`'`を`"`に置換する場合もあります) XXXとYYYは入力しユーザー名とパスワード。 XXXとYYYはDBの中の資料に合ったら、ログイン成功です。 もしユーザー名のところに`" OR 1=1 #`を入力したら、 こうになる: ```sql= SELECT * FROM users WHERE id='' OR 1=1 #' AND password='YYY' ``` `id='' OR 1=1`の部分は`1=1`があるので、ずっと真になる。 そして`#`の後ろの部分は全部コメントにして無視される。 (`#`を`--`に置換する場合もあります) この場合もログインできます。そして使っているユーザー名はDBのテーブル一番のユーザー名かもしれない。 ## SQL injectionを使って、DB内の資料を引き出す ``` ' OR 1=1 # --- ``` 「下線部の部分が真になるとログインできる」という点を利用して、 DBの資料を全部引き出すことができる。`SUBSTRING`という関数を利用します! ### まずはDBの中のすべてのテーブルの名前を引き出す 上の下線部分をこうに置換すると ```sql= SUBSTRING((SELECT table_name FROM information_schema.tables LIMIT i, 1), j, 1) = "k" ``` `information_schema.tables`はデータベース内のテーブルに関する情報を提供します。 そしてテーブルの名前は`table_name`のカラムに保存されています。 `LIMIT i, 1`文は結果の行数を制限する関数です。`i`は第`i`行目、`1`は`1`行だけの意味。 だから`SELECT table_name FROM information_schema.tables LIMIT i, 1`という文は **第`i`番目のテーブル名を引き出すことです** そして`SUBSTRING(x, j, 1) = "k"`は、 string `x`の第`j`番目の文字は`"k"`ですかという意味です。 これらをくっつくと、「第`i`番目のテーブル名の第`j`番目の文字は`"k"`ですか」になる。 そして`for`などのループを使って、`i, j, "k"`を置換して、テーブルの名前を合ってってみよう~ もしログイン成功したら、合った! ### 次はカラム名 例えば、さき引き出したテーブルの名前は`'users'` ```sql= SUBSTRING((SELECT column_name FROM information_schema.columns WHERE table_name = 'users' LIMIT {},1), j, 1) = "k" ``` 「'users'の第`i`番目のカラム名の第`j`番目の文字は`"k"`ですか」という意味です。 `information_schema.columns`はデータベース内のカラムに関する情報を提供します。 そしてカラムの名前は`column_name`のカラムに保存されて、そのカラムはどのテーブルのカラムは`table_name`の中に保存されています。 ### 最後はユーザー名とパスワード 例えば、さき引き出したカラムの名前は`'username'`と`'password'` ```sql= SUBSTRING((SELECT username FROM users LIMIT i, 1), j, 1) = "k" ``` ⇒「'users'の第`i`番目の"username"の第`j`番目の文字は`"k"`ですか」 ```sql= SUBSTRING((SELECT password FROM users LIMIT i, 1), j, 1) = "k" ``` ⇒「'users'の第`i`番目の"password"の第`j`番目の文字は`"k"`ですか」 ユーザー名とパスワードをゲット! ## SQL injectionを防ぐ * 入力した内容を確認: * 引用符(`'`と`"`)を取り除く * コメント符号(`#`と`--`)を取り除く * テーブルの権限をもう一度確認 * sqlmapなどのツールで脆弱性を診断