なぜPHPアプリにセキュリティホールが多いのか?

第31回 番外編:sqlmapの紹介

この記事を読むのに必要な時間:およそ 13 分

sqlmapの使い方

コマンドのヘルプメッセージからも分かるようにsqlmapは非常に多くの機能を持っています。ここでは簡単な使い方を紹介します。

脆弱なWebアプリ

sqlmapを使うには脆弱なWebアプリが必要です。MacBookにPostgreSQL One-ClickインストーラでApache, PHP, PostgreSQLがインストールされた環境に脆弱なWebアプリを作りました。

ソースコード

<?php
error_reporting(E_ALL);

$msg = 'ユーザ名とパスワードを送信してください';
if (!empty($_REQUEST['username'])) {
    // check login
    $conn = pg_connect('host=localhost dbname=vulndb user=postgres password=postgres');
    $sql = "SELECT id FROM users WHERE username= '".$_REQUEST['username']."' AND password = '".$_REQUEST['password']."';";
    $res = pg_query($conn, $sql);
    if (pg_num_rows($res)) {
        $msg = 'ログインしました';
    } else {
        $msg = 'ユーザ名とパスワードを確認してください';
    }
}
?>
<html>
<head><title>VulnAPp</title><head>
<body>
<div align="center">
<form action="<?php echo $_SERVER['PHP_SELF'] ?>">
<br />
ログインしてください<br />
<br />
ユーザ名:<input type="text" name="username" /><br />
パスワード:<input type="text" name="password" /><br />
<br />
<input type="submit" /><br />
<br />
<?php echo $msg ?><br />
</body>
</html>

単純にフォームに記入された内容がusersテーブルに保存されているユーザ名とパスワードに一致していれば「ログインしました」と表示するだけの中身がないアプリです。

このアプリは典型的なSQLインジェクションに脆弱なアプリで,どこが脆弱かすぐに分かったと思います。ユーザ入力である$_REQUEST['username']と$_REQUEST['password']がエスケープなしでpg_query関数に渡され実行されています。

このスクリプトは http://localhost:8080/vulnapp/index.php でアクセスできるように設定されています。

作成済みのデータベース

$ psql -U postgres -l
                         List of databases
      Name       |     Owner     | Encoding |   Access privileges   
-----------------+---------------+----------+-----------------------
 drupal          | drupaluser    | UTF8     | 
 drupal7-alpha   | postgres      | UTF8     | 
 guestbook       | zfblog        | UTF8     | 
 mediawiki       | mediawikiuser | UTF8     | 
 phpbb           | phpbbuser     | UTF8     | 
 phpwiki         | phpwikiuser   | UTF8     | 
 postgres        | postgres      | UTF8     | 
 template0       | postgres      | UTF8     | =c/postgres
                                            : postgres=CTc/postgres
 template1       | postgres      | UTF8     | =c/postgres
                                            : postgres=CTc/postgres
 vulndb          | postgres      | UTF8     | 
(10 rows)

攻撃対象のvuldbの中身

$ psql -U postgres vulndb
psql (8.4.0, server 8.3.5)
WARNING: psql version 8.4, server version 8.3.
         Some psql features might not work.
Type "help" for help.

vulndb=# \d
                          List of relations
 Schema |                 Name                 |   Type   |  Owner   
--------+--------------------------------------+----------+----------
 public | sadernzytn_cannot_guess_234234234234 | table    | postgres
 public | users                                | table    | postgres
 public | users_id_seq                         | sequence | postgres
(3 rows)

vulndb=# \d users
                          Table "public.users"
  Column  |  Type   |                     Modifiers                      
----------+---------+----------------------------------------------------
 username | text    | 
 password | text    | 
 id       | integer | not null default nextval('users_id_seq'::regclass)

vulndb=# select * from users;
 username | password | id 
----------+----------+----
 foo      | 1234     |  1
 bar      | bar      |  2
 hoge     | fuga     |  3
 admin    | admin    |  4
(4 rows)

vulndbにはusersとおかしな名前のテーブルsadernzytn_cannot_guess_234234234234が定義されています。

sqlmapが自動的にエラーを検出できるようphp.iniをdisplay_errors=on設定しています。

図1 DBエラーが表示された画面

図1 DBエラーが表示された画面

これだけ明らかな脆弱性があると何もしなくてもデータベースの中身は丸見えになります。

sqlmapの実行

sqlmapの基本的な使い方を紹介します。

GETメソッドでパラメータが渡せる場合はURLにパラメータが記載された状態で渡します。

 GETメソッドでのパラメータ指定

python sqlmap.py -u http://example.com/script.php?param=a&param=b

POSTメソッドでパラメータが渡される場合,--methodオプションで明示的にPOSTを指定する必要があります。送信されてデータは--dataオプションで指定します。

 POSTメソッドでのパラメータ指定

python sqlmap.py -u http://example.com/script.php --method POST --data "id=1"

ログイン済みのサイトでSQLインジェクションを実行する場合,セッションIDが必要です。あらかじめWebブラウザでログインしてセッションIDを取得し,--cookie "PHPSESSID=XXXXXXXX" のように指定し取得済みのセッションIDを利用します。

基本的なコマンド

--dbsデータベースの一覧
--tablesテーブルの一覧
-Dテータベースの指定(PostgreSQLではサーチパス)
-Tテーブルの指定
--colums-Tと一緒に使いテーブル定義を一覧
--dump-Tと一緒に使いテーブルデータをダンプ

沢山のオプションがあるので基本的なコマンドの使い方だけを紹介します。これだけもSQLインジェクション脆弱性の危険性を理解できると思います。

著者プロフィール

大垣靖男(おおがきやすお)

University of Denver卒。同校にてコンピュータサイエンスとビジネスを学ぶ。株式会社シーエーシーを経て,エレクトロニック・サービス・イニシアチブ有限会社を設立。
オープンソース製品は比較的古くから利用し,Linuxは0.9xのころから利用している。オープンソースシステム開発への参加はエレクトロニック・サービス・イニシアチブ設立後から。PHPプロジェクトでは,PostgreSQLモジュールのメンテナンスを担当している。

URLhttp://blog.ohgaki.net/

著書