2020年6月3日に修正されたDjangoの脆弱性CVE-2020-13254・CVE-2020-13596について解説します。

CVE-2020-13254はデータ漏洩の可能性があります

CVE-2020-13596はXSSに関する脆弱性です
公式サイトでのリリース情報は以下を参照してください。
Django security releases issued: 3.0.7 and 2.2.13 | Weblog | Django
影響を受けるバージョン
以下のバージョンが影響を受けます。
- Django master branch
- Django 3.1
- Django 3.0
- Django 2.2
脆弱性の内容
CVE-2020-13254: Potential data leakage via malformed memcached keys
memcachedを使っている場合に、不正なキーを渡すことでデータの漏洩を起こす可能性があります。
CVE-2020-13596: Possible XSS via admin ForeignKeyRawIdWidget
ForeignKeyRawIdWidgetがadmin上で生成するクエリパラメータにXSS脆弱性があります。
この脆弱性は、モデルにForeignKey.limit_choices_to・ManyToManyField.limit_choices_toを指定したフィールドがある場合に発生する可能性があります。
脆弱性を利用した攻撃の例
サンプルコードで使っている環境のバージョンは以下の通りです。
- Django 3.0.6
- pylibmc 1.6.1
- Python 3.8.3
- memcached 1.6.6
- libmemcached 1.0.18
CVE-2020-13254: Potential data leakage via malformed memcached keys
まず、公式ドキュメントに従ってsettings.pyを編集します。以下が設定例です。
| |
次に、shellコマンド上で以下を実行します。
| |
最後のcache.get('my_key' + c)はNoneが返ってくるはずですが、'my_key'キーで設定された値'hello, world!'を取得できてしまいました。
CVE-2020-13596: Possible XSS via admin ForeignKeyRawIdWidget
以下のコードを用意します。
example/models.py
| |
example/admin.py
| |
makemigrationsコマンド・migrateコマンドでデータベースを作成し、createsuperuserコマンドでadminユーザーを作成してください。
shellコマンドで以下のデータも作っておきます。
| |
runserverコマンドで開発サーバーを立ち上げ、以下URLからUnsafeLimitChoicesToを作成します。Bandは1を指定してください。
http://127.0.0.1:8000/admin/example/unsafelimitchoicesto/add/
登録後のデータを表示して、以下の虫眼鏡ボタン(赤枠部分)のHTMLを確認してみましょう。

http://127.0.0.1:8000/admin/example/unsafelimitchoicesto/1/change/ の表示内容
以下のように"&><escapemeの部分がエスケープされずに埋め込まれています。
| |
limit_choices_toを'"></a><script>alert(\'XSS\');</script><a href="'のような値にすれば、adminにスクリプトを仕込むことも可能です。
どのコードに問題があったか・どのように修正されたか
実際の変更内容は以下のGitHubコードを参照してください。
CVE-2020-13254:
- On the master branch
- On the 3.1 release branch
- On the 3.0 release branch
- On the 2.2 release branch
CVE-2020-13596:
- On the master branch
- On the 3.1 release branch
- On the 3.0 release branch
- On the 2.2 release branch
CVE-2020-13254: Potential data leakage via malformed memcached keys
django.core.cache.backends.memcached.BaseMemcachedCacheではmemcachedにキーを渡す際に入力値をそのまま渡していました。
そこで、validate_keyメソッドを追加して入力値を検査し、不正な値が含まれている場合はmemcachedにキーを渡さず、警告メッセージを出力させるようになりました。
Django 3.0.7で先述の「脆弱性を利用した攻撃の例」に載せたコードを実行すると、以下のメッセージが表示されます。
| |
CVE-2020-13596: Possible XSS via admin ForeignKeyRawIdWidget
django.contrib.admin.widgets.ForeignKeyRawIdWidget.get_contextの中で、related_url変数(limit_choices_toの値を虫眼鏡ボタンに埋め込むために使う)にdjango.utils.safestring.mark_safeを使った値を渡していたことが原因でした。django.utils.safestring.mark_safeを使った値はテンプレート上でエスケープされません。
修正後のコードではdjango.utils.safestring.mark_safeを使わずdjango.utils.http.urlencodeを使うようになりました。
Django 3.0.7で先述の「脆弱性を利用した攻撃の例」に載せたコードを実行すると、"&><escapemeがエスケープされるようになります。
| |