Djangoの脆弱性CVE-2019–12308・CVE-2019–11358について解説
こんにちは。筒井です。今日は、2019年6月3日のリリースで修正されたDjangoの脆弱性CVE-2019–12308(AdminURLFieldWidget XSS)・CVE-2019–11358(Prototype pollution)について解説します。
Django公式サイトのリリース記事については以下を参照してください。
影響を受けるバージョン
以下のバージョンが影響を受けます。
【CVE-2019–12308: AdminURLFieldWidget XSS】
- Django master development branch
- Django 2.2 before version 2.2.2
- Django 2.1 before version 2.1.9
- Django 1.11 before version 1.11.21
【CVE-2019–11358: Prototype pollution】
- Django master development branch
- Django 2.2 before version 2.2.2
- Django 2.1 before version 2.1.9
脆弱性の内容
【CVE-2019–12308: AdminURLFieldWidget XSS】
AdminURLFieldWidget
から生成されるリンクにXSS脆弱性があります。AdminURLFieldWidget
は URLField
を使ったモデルをadminで扱う際に使われるウィジェットです。
【CVE-2019–11358: Prototype pollution】
admin用にバンドルされているjQuery(3.4.0未満)に脆弱性があります。jQuery.extend(true, {}, …)
にユーザーからの入力値を渡すことで Object.prototype
を汚染し、任意のプロパティの挙動を書き換えたり、新しいプロパティを追加することができます。
以下jQuery公式ブログの解説も併せて参照してください。
この脆弱性はadmin用にバンドルされているJavaScriptライブラリ select2
を使っている場合にも影響があります。
脆弱性を利用した攻撃の例
以下で紹介するサンプルコードはDjango 2.2.1を使っています。
【CVE-2019–12308: AdminURLFieldWidget XSS】
まず、posts
アプリケーションに以下のコードを書きます。
次に、予め shell
コマンドで以下のデータを作っておきます。
( URLValidator
を使っていない入力フォームを作ってブラウザから登録してもいいです)
>>> from posts.models import Post
>>> Post.objects.create(title='テスト', content='テストテストテスト', url='javascript:alert(\'XSS\');')
<Post: テスト>
posts
に対してchangeの権限を持った管理者ユーザーでadminにログインし、上記で作ったデータの編集画面を開いてください。URLの欄に現在の値が表示されているはずです。
赤枠の部分は本来はURLをブラウザで開くためのリンクですが、JavaScriptコードが埋め込まれているので、アラートが実行されます。
また、新規登録画面でURLを javascript:alert('XSS');
にすると、入力エラーにはなりますが、 先述の例と同様にクリック時にアラートが表示されるリンクが表示されます。
(もっとも、この画面は入力者本人にしか表示されないので、これを攻撃に利用するには、かなり条件が限られてくるでしょう)
【CVE-2019–11358: Prototype pollution】
ModelAdmin.autocomplete_fields
は select2
を使っているので、内部で使っているjQuery.extend(true, {}, …)
にユーザーからの入力値を渡せば攻撃できるはずですが、具体的な例を見つけられませんでした。
JavaScriptのカスタマイズを行っている、かつ select2
や jQuery
を利用している場合は攻撃が成立する可能性はあります。
攻撃例の代わりに、adminで脆弱なjQueryが使われているか確認する方法を載せます。
ChromeのJavaScriptコンソールやFirefoxの開発ツールを使って、http://127.0.0.1:8000/admin/auth/user/
の画面上で以下のコードを実行してください。脆弱なjQueryを使っているなら true
が表示されます。
(つまり、 {}
に本来存在しないはずのプロパティ test
が追加されている)
django.jQuery.extend(true, {},
JSON.parse('{"__proto__": {"test": true}}')
);
console.log( "test" in {} );
どのように修正されたか
【CVE-2019–12308: AdminURLFieldWidget XSS】
AdminURLFieldWidget
にコンテキスト変数 url_valid
が追加され、以下のルールで値が設定されるようになりました。
- 入力値が
URLValidator
でエラーにならない→True
を設定 - 入力値が
URLValidator
でエラーになる→False
を設定
また、AdminURLFieldWidget
のレンダリング用に使われているテンプレートファイルでは、 url_valid
が True
の場合のみリンクが表示されるようになりました。
実際の変更内容は以下を参照してください。
【CVE-2019–11358: Prototype pollution】
keyが __proto__
の値はマージ対象から外すように変更されました。
jQuery自体のバージョンを上げたわけではなく、該当部分にパッチを当てただけのようです。
実際の変更内容は以下を参照してください。