この前のFacebook CTFで出てたし、まとめておく。
起きる現象1
MySQLで起こる。
わかりやすい例で言うとこんな感じ。
mysql> select * from users where username = 'admin'; Empty set (0.00 sec) mysql> insert into users values('admin', 'pass'); Query OK, 1 row affected (0.01 sec) mysql> select * from users where username = 'admin'; +----------+----------+ | username | password | +----------+----------+ | admin | pass | +----------+----------+ 1 row in set (0.00 sec) mysql> insert into users values('admin ', 'pass2'); Query OK, 1 row affected (0.02 sec) mysql> select * from users where username = 'admin'; +----------+----------+ | username | password | +----------+----------+ | admin | pass | | admin | pass2 | +----------+----------+ 2 rows in set (0.00 sec)
selectのwhereで検索するときに末尾に空白が入っていても無視して取ってきてしまう。
つまり、何らかの方法で
- ユーザID「攻撃したいユーザID+空白」
- パスワード「好きに決定」
を入れることができれば、ログイン時にユーザID「攻撃したいユーザID」パスワード「好きに決定」でログインができてしまう。
起きる現象2
後ろの空白を消して入れるみたいな処理を入れてやれば良さそう。
だけど、カラムのサイズの上限で切り捨てされるというトリックを使えば、無理矢理空白で終わるユーザー名をねじ込める。
これを使えば、「admin a」で重複チェックをすり抜けて、実際は「admin 」を入れるということもできる。
つまり、チェック時の文字列と実際に入る文字列を変えることができる。
mysql> select * from users where username = 'admin'; Empty set (0.00 sec) mysql> insert into users values('admin a', 'pass'); Query OK, 1 row affected, 1 warning (0.04 sec) mysql> select * from users where username = 'admin'; +------------+----------+ | username | password | +------------+----------+ | admin | pass | +------------+----------+ 1 row in set (0.00 sec)