CVE-2024-42005 について
Django のクエリーセットの values() と values_list() にクリティカルな脆弱性。SQL インジェクションの可能性あり。CVSS 基本値は 9.8 と高レート。
LTS の 4.2. 台だと 4.2.14 までが脆弱性対象、4.2.15 が修正バージョン。
修正箇所
4.2.15 のコミットを見てみる。
JSONField の各フィールドに対して self.check_alias(field) を適用している。
check_alias は SQL インジェクションの原因となるメタ文字が混入してないかをチェックし、混入している場合はエラーを raise する。
試してみる
まずは Django 4.2.14 で試してみる。
なお、JSONField をサポートしている DB を使う必要があるため、PostgreSQL を用意する必要がある。
今回は Windows でセットアップ。PostgreSQL も普通にインストールし、psql -U postgres でログインし、create database cvetest; で cvetest という名前のデータベースを作成するだけ。
適当に temp フォルダを作り、そのフォルダ内で以下を実行。
> python -m venv .venv > .venv\Script\activate > python -m pip install -U pip > pip install django==4.2.14 > pip install psycopg > django-admin startproject config . > python manage.py startapp cvetest
config/settings.py を以下のように追記。
INSTALLED_APPS = [ ... 'cvetest', # 追記 ] ... # DATABASES を SQLite3 の設定から置き換え DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", "NAME": "cvetest", "USER": "postgres", "PASSWORD": "postgres", "HOST": "127.0.0.1", "TIME_ZONE": "Asia/Tokyo", } }
cvetest/models.py に以下を記述。
from django.db import models class JSONFieldModel(models.Model): data = models.JSONField(null=True)
そしてマイグレートし shell へ移動。
> python manage.py makemigrations > python manage.py migrate > python manage.py shell
4.2.14 の場合
上記コミットに追記された test の内容を模倣し、実際に試してみる。
>>> from cvetest.models import JSONFieldModel >>> a = JSONFieldModel.objects.create(data={"hoge": "fuga"}) >>> crafted_alias = """secret" from "secret_table"; --""" >>> j = JSONFieldModel.objects.values(f"data__{crafted_alias}")
4.2.14 の場合、エラーにはならない。そして以下の SQL 発行が確認できた。
SELECT ("cvetest_jsonfieldmodel"."data" -> 'secret" from "secret_table"; --') FROM "cvetest_jsonfieldmodel" LIMIT 21
ちなみにこれを見て craft_alias に ' (シングルクォーテーション) を入れたら攻撃成功しそうだと思いやってみたが、これはエラーにならず '' (シングルクォーテーション 2 つ) にサニタイジングされた。
つまり、今回のこの脆弱性単体では実攻撃は相当困難であることが分かった。
仮に今回の脆弱性を使って Django の Web UI から攻撃を成功させるには、以下の条件が必要となる。
- WebUI から入力可能なパラメーターを JSONField のカラムの values() あるいは values_list() の引数に入れられること
- その際、シングルクォーテーションのサニタイジングを突破する等の別の脆弱性を使って SQL を実行できること
- その SQL 実行結果を Web UI へ出力できること
4.2.15 の場合
pip install django==4.2.15 を実行し、上記と同じことを実行するとエラーになる。
>>> j = JSONFieldModel.objects.values(f"data__{crafted_alias}") Traceback (most recent call last): File "", line 1, in File "C:\Users\daisf\work\temp\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\daisf\work\temp\.venv\Lib\site-packages\django\db\models\query.py", line 1313, in values clone = self._values(*fields, **expressions) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\daisf\work\temp\.venv\Lib\site-packages\django\db\models\query.py", line 1308, in _values clone.query.set_values(fields) File "C:\Users\daisf\work\temp\.venv\Lib\site-packages\django\db\models\sql\query.py", line 2419, in set_values self.check_alias(field) File "C:\Users\daisf\work\temp\.venv\Lib\site-packages\django\db\models\sql\query.py", line 1125, in check_alias raise ValueError( ValueError: Column aliases cannot contain whitespace characters, quotation marks, semicolons, or SQL comments.
SQL が発行されていないことも確認できた。
コメント