はじめに
セキュリティに関する試験の勉強をする中で、OR 1=1
でデータベースを侵害する攻撃 をよく目にするな~と感じていました。また、そうした攻撃手法が SQL インジェクション と呼ばれるんだな~くらいの理解で過ごしてきました。そこで、本記事では、SQL インジェクションを実際に試してみて、座学での理解を経験に変えていこうと思います。
スクリーンショット ベースで、読者の皆様も経験したと同様のイメージを持っていただける内容になっているかと思います。
想定読者
- これからセキュリティに関する試験を対策する人
- CISSP 対策をする人
- 攻撃者側の雰囲気をつかみたい人
特別に許可された検証環境または自分の管理する環境以外で検証を実行することは犯罪につながる恐れがあります。
本記事で扱う内容:SQL インジェクション
SQL インジェクションとは
SQL インジェクションとは、クライアントからアプリケーションへの入力データを通じて、SQL クエリを挿入(インジェクション)する攻撃です。もし、SQL インジェクションが成功すると、データベースから機密データを読み取ったり、データベースのデータを変更するといったことが可能になります。
以降でスクリーンショットと一緒に、「攻撃者にとって何が見えるか」、「防御側としての対策は何か」 を個人的に整理したものを簡単にまとめていきます。
また、紹介する内容は、TryHackMe というハッキングの練習用サイトで実施したものの一部です。本検証に直接関係はしませんが、Kali Linux という攻撃者がよく使うマシンを検証用に使用しています。
TryHackMe とは
TryHackMe とは、攻撃手法や防御技術などを仮想マシン上で学べる、サイバーセキュリティ学習プラットフォームです。無料でハンズオンできるトレーニングがいくつも用意されています。ハッキングによって隠されたメッセージを探しながら、ゲーム感覚でハッカーになったつもりでセキュリティ技術を体験することができます。
今回は、TryHackMe の 「OWASP Juice Shop」 というトレーニングを活用します。
1. 探索:ターゲットとなるサイトにアクセスする
今回は OWASP Juice Shop という、TryHackMe が用意してくれている Web サービスにアクセスします。このサイトは、セキュリティを勉強する人のために、わざと脆弱性だらけのサービスとして公開されています。 本検証では、たくさん用意されている脆弱性の中の一つとして、SQL インジェクションを試していきます。
実際にサイトにアクセスしてみると、どうやらオンラインのジュースショップのようです。一見すると普通のサイトのように見えます。誰かしらのアカウントになりすましてこのサイトにログインできた場合、いらないジュースを大量に注文したり、商品の配送先を変更したりと、いたずらができそうだと攻撃者は考えるかもしれません。攻撃者は、サイトを探索しながらいたずらのヒントを探していきます。
🧑💻攻撃者視点
- ログイン・検索・お問い合わせなど文字を入れられる場所に自然と目が行く
- 画面に出ている変化する情報 (検索バーなど) をチェックする
🛡️防御者対策
- 公開している機能の棚卸しを行い、不要な入力欄・リンクなどは閉じる / 消す
- 画面上の情報露出を最小化
2. 偵察:ログイン画面の動きを探ってみる
なりすましができないか?ということで、ログイン画面に脆弱性がないか見てみます。こちらもよくあるログイン画面のように見えます(画像:左側)。Email も Password も知らないので、適当に入力してその際にどのような返答がサーバーから返されるのかを見てみます。 クライアント端末 (攻撃者が手元で操作しているマシン) とターゲット サーバーの通信のやり取りは、キーボードの F12
を押すことで表示できる 「開発者ツール」 から覗くことができます(画像:右側)。
以下のスクショでは、適当なサインイン入力として、Email を attack
、Password を password
とした際の返答を開発者ツールで覗いたものです。サーバーからの返答 (Response) として、「Invalid email or password.」と返されています。手掛かりはなさそうです。
そこで、これまで学生時代にプログラミングをかじった経験、セキュリティの勉強をするなかでいくつかのスクリプトを書いてきた経験をもとに裏側のやり取りを想像してみます。個人的によく、変数に値を代入する際に、シングル クォーテーション '
や ダブル クォーテーション "
で値を囲っていた印象があります。 今回の Email や Password も同様に、私たちユーザーが入力した値は変数として代入されている可能性があるかもしれません。そこで、わざと Email の入力として、シングル クォーテーションを混ぜてみます。 この時、攻撃者としては、サーバーからの返答が別のエラーに変わったりしないかな?という期待を込めているかもしれません。どうやらビンゴのようです。先ほどの「Invalid email or password.」とは異なり、赤文字でいろいろエラーの内容が返ってきています。
エラーの内容を細かく確認していくと、「message」の内容から、「SQLITE」というデータベースエンジンのエラーのようです。
また、エラーメッセージに SQL 構文が露出しており、Email や Password といったユーザー入力が SQL に連結されている可能性が高いと推測できます。 そして予想通り、シングル クォーテーション '
がユーザー入力の変数を囲っていることが確認できます。つまり、今回のエラーは、ユーザーが入力したシングル クォーテーション '
が SQL の Email 文字列を意図せず閉じてしまい、以降が構文エラーになっている状態です ('
が一つ余分で文法的におかしくなってしまっている状態)。
ここで、「このエラーをうまく悪用すれば、不正ログインができてしまいそうだな」と攻撃者は気づきそうです。
🧑💻攻撃者視点
- 開発者ツールのネットワーク タブでリクエスト / レスポンスやステータスコードを見てみる
- エラーメッセージからバックエンドの種類や構文のヒントを拾う
🛡️防御者対策
- サーバー側の入力検証(型/長さ/文字種など)を実装
- ログインの成否でレスポンス本文や時間差が極端に変わらないように統一する
3. 侵害:OR 1=1
でログインの入力を 真(True)
にする
「2. 偵察」で、ログイン時の入力にシングル クォーテーション '
を混ぜると、裏側で動作する SQL のクエリにいたずらできることが分かりました。ここからは、結果がエラーではなく、真(True)
として認識されて、ログインを突破する方法を考えます。
まず、サイトに登録されている Email を攻撃者は知らないので、Email の判定をクリアして WHERE
句全体を '真(True)' にする必要がありそうです。ここで、試験でよく見てきた OR 1=1
が活用できそうです。以下のようにログイン画面の Email に入力すると、「Email が登録されているとき、もしくは 1=1 のとき」という意味になり、Email がどんな値だったとしても、WHERE
句を常に 真(True)
にできそうです。
<適当な Email>' OR 1=1
以下のようにエラー内の SQL のクエリが書き換わっているのが確認できました。
しかしこのままだと、結局 OR 1=1
の後ろ側が邪魔をしてエラーのままです。そこで、OR 1=1
の後ろ側を無視できないか考えます。プログラミングなどで使う「コメント アウト」が使えるかもしれません。
そこで、先ほどエラーメッセージから確認していた、「SQLITE」について、コメントアウトの方法を検索してみます。そうすると、コメントアウトが --
で行えることが分かりました。これをもとに、ログイン画面の Email への入力を以下のようにしてみます。
<適当な Email>' OR 1=1--
こうすることで、Email の判定が常に 真(True)
であり、それ以降はコメントアウトされているためパスワード判定は無効化され、入力自体は正しいものになりそうです。
実際にやってみると、結果として admin@juice-sh.op
というアカウントでログインできてしまいました。どうやら、今回の検証環境では管理者アカウントとしてログインできてしまうようです。
サイトの管理者になりすますことができたので、サイトの中身を書き換えたり、他のユーザーの情報をのぞいたり、侵害が拡大していくことが予想されます。
🧑💻攻撃者視点
- 条件を 常に
真(True)
にできないか発想を切り替える - 権限が高いアカウントになりすますと、設定変更やデータ閲覧など被害が一気に広がると想像する (コスパの良い侵害)
🛡️防御者対策
- SQL クエリとユーザー入力を分離する
- 特権操作には MFA を要求することで被害の半径を狭める
4. おまけ:管理者以外のアカウントでサイトに不正ログインする
実は、サイトのトップ ページで商品を眺めていると、商品にレビューをしているユーザーがいることが分かります。このサイトでは、レビュー者のメールアドレス (bender@juice-sh.op
) が表示されているようです。
そこで、「3. 侵害」で実施したコメント アウトを利用して、管理者ではない一般ユーザーになりすましができるかもしれません。今回は、正しい Email を知ることができているので、OR 1=1
は不要です。以下のようにログイン画面の Email 欄に入力してみます。
bender@juice-sh.op'--
今回も不正ログインができてしまいました。ログイン中のアカウントを確認してみると、bender@juice-sh.op
のようです。サイトのあらゆる場所に散らばっている情報が、攻撃者の侵害のヒントになりうることが理解できました。
まとめ
今回は、セキュリティの試験でよく見る SQL インジェクションについて、TryHackMe の練習用サイトを用いて検証しました。有効なメールアドレスを知らない場合でも、' OR 1=1
を使うことでクエリを 真(True)
にできてしまうことが理解できました。こうした脆弱性を作らないために、Web サイトの設計段階から、ユーザーの意図しない入力を防ぐような設計を徹底したり、公開前に動的テストを行ったりすることでセキュリティを実現していくことが重要であると改めて実感することができました。便利なサービスを提供することだけを考えるのではなく、常に足元のセキュリティも固めていく、この両輪が大切です。
記事について誤った内容など修正すべき個所がありましたら、コメントいただけますと幸いです。
学習環境の参考
- 実験環境:Kali Linux + TryHackMe (OWASP Juice Shop Room)
他者が所有する資産への攻撃や悪意のあるコードの作成を行うことは、不正アクセス禁止法などに違反し犯罪につながる可能性があります。