CSS(Cascading Style Sheets)でCSS(Cross Site Scripting)というダジャレを言いたかったために、タイトルで誤解があると良くないため、先に否定すべき要点を挙げます。
- Attack vectorはCSS Injectionであるが、安全ではないJavaScriptコードを実行しない限りXSSは成立しない
- CSSの疑似要素(Pseudo-elements)の仕組みに問題がある訳ではない
●はじめに
Cascading Style SheetsでCross Site Scripting(以下、XSS)と言うと、expression()を用いた手法が知られている。ただし、その他のテクニックも含め攻撃は限定的であり、モダンなブラウザでCSSインジェクションによるXSSは限りなく難しいだろう、と思われている方が多いのではないかと考えています。CSSインジェクションの主な脅威として、HTMLドキュメントからTokenなどの機微な情報を窃取すること、限定的なXSSでしょう。もっとも、CSS Injectionが起こりうる状況であれば、わざわざCSSにコードを仕込まなくとも、セオリー通りに<script>alert(document.cookie)</script>を注入すれば良い話ではあるが。とはいえ、JavaScriptコードは入らないが任意のCSSコードは実行できるといった、もどかしい場面も稀にある。そして、CSSインジェクションは、XSSやSQLインジェクションのような、たいそうな事は出来ないからといって軽視されているのではないか、という懸念と、モダンなブラウザにおいて、CSSインジェクションはXSSの脅威が内在しているのか、という興味・探究心から考察した。なお、現状は組み合わせ技の程度で、途中経過を取りまとめた記事である。
●攻撃手法の概要
今回は英題の通り、CSSの疑似要素に着目し、CSSインジェクションによってContentプロパティの値にJavaScriptコードを仕込み、JavaScriptによる安全ではないDOMの操作を悪用して、DOM based XSSを引き起こさせるという内容です。ここでの、JavaScriptによる安全ではないDOMの操作は、document.body.appendChild();のような動的にDOMの操作を行っており、尚且、HTMLエンティティ文字のエスケープ処理をしていない場合のことを指しています。攻撃手法自体は、古典的なDOM based XSSであり、当たり前のことを言っているので、物足りない内容かもしれないですが、CSSインジェクションで無理にでもXSSを引き起こさせる、ややひねくれ系のやり方です。
●CSSの疑似要素は悪用できるのか
さて、ここで矛盾が生じます。CSSの疑似要素は、DOMではないということです。つまり、JavaScriptからのDOM操作では、CSSの疑似要素を参照することができない仕様です。ブラウザの実装上においても参照できず、DOMを見ると<hoge>::after</hoge>のように隠蔽され、値を参照できませんでした。さらに、疑似要素はおおよそ安全にstring文字列として表現され、HTMLエンティティ文字もHTMLタグとしては機能しません。たとえ、<script>alert(1)</script>が挿入できたとしても、文字列として<script>alert(1)</script>が表示されるだけにとどまります。ここまでは、仮にCSS インジェクションによって任意のJavaScriptコードが挿入されたとしても、XSSは起こりえないと断言しても過言ではないかと考えています。ここで述べているのは、私が調べて検証した限りの範囲です。
いよいよ、悪用できるのか、という箇所に言及します。少々屁理屈ですが、CSSの疑似要素をDOMから参照しなくとも、直接StyleSheetsのContentプロパティ値を参照すれば良いのです。これで、参照できる値としては、疑似要素から参照している値と同じです。話の厳密性で言えば、疑似要素を参照することと、CSSのプロパティ値を参照することは、違うのもではあるのですが、現状はXSSが起こりうるということを示せる程度で良いと考えます。ですので、真にCSSの疑似要素を参照してXSSを引き起こせた、というわけではないです。
●現実的な話
ここまで、攻撃手法の概要を明かしましたが、実際現場で使えるのかどうかという疑問と、恣意的にやっているのではないかと思われるかもしれないです。脆弱性を内在させるように恣意的にコードを書けば、なんとでもXSSが起こりうるよ、と言えるものです。しかし、今回取り上げたのが、主観的ですが、どうやらこの作り込みはWeb開発において全くありえない訳ではなさそうだ、と読んでます。なぜなら、Google検索の結果において、悪魔的なサンプルコードの紹介ページが、トップに表示されていました。このような作り込みだとXSSの脆弱性が内在する恐れがあります。下記にいくつかの例を挙げます。
- 疑似要素のCSSのプロパティ値を参照し、innerHTMLでDOMに追加する
- StyleSheetsのプロパティ値を参照し、document.headにstyle要素を文字列結合して追加する
前者は、疑似要素はDOMで参照できないため、無理矢理参照するというテクニックで、後者は、動的なStyleSheetsの変更のためのよくあるテクニックだそうです。これは、DOM based XSSの危ないかほりがしますね。次に、サンプルコードを参考に簡単なWebページを作成し実験してみました。
●コード例 / Proof of Concept
それでは、実際に脆弱性を作り込んだWebページを確認しましょう。検証用に、color.phpという、文字をクリックすると、何色の文字をクリックしたのかを、DOMに追加し表示させるものを用意しました。
◆color.php
少々作りに無理矢理感ありますが、私が言いたいことはこのような作りです。脆弱性を作り込んだのは二箇所で、DOM based XSSしてくださいと言わんばかりのinnerHTMLと、任意の背景色をQueryStringから指定できるPHPコードです。echo $_GET['color'];が完全にNGで、普通にXSSが出来てしまいますが、今回はCSSインジェクションで、DOM based XSSを起こすことが目的ですので、厳しいご指摘はご勘弁を。
※ソースコードはPC表示のみで確認できます。
◆Payload
これで刺さります。
color.php?color=white;}h3:after{content:%27%3Ca%20onmouseover=alert(1)%20style=position:absolute;width:100%;height:100%;top:0;left:0;%3E%3C/a%3E%27;}b{color:0
画面上は明らかに怪しいですが、実質的に即時発火させるようにスタイルシートを細工しています。
Elements上はこのようになっています。
この作りは、 onclickイベントからCSSの疑似要素のContentプロパティ値を参照し、何色をクリックしたのかを文字列結合を行い、body要素の子要素に追加するものです。このような、安全ではないJavaScriptコードを悪用して、CSSインジェクションを行い、Contentプロパティ値にJavaScriptを発火させるコード仕込ませ、上書きさせるという手法です。攻撃者は、CSSインジェクションだけで、XSS攻撃を成功させることができると言えるでしょう。
実際のProductで起こりうるか、と言われるとごく稀だとは思いますが、作り込み次第ですし、今回のCSSインジェクションによるXSSのPayloadも、不等号記号<>を使わずにXSSができる恐れはあると考えています。当然、@import url()による外部CSSファイルの読み込みでも攻撃可能です。
●対策方法
一般的な改修方法と同様ですので詳細は割愛しますが、抜本的な解決として、ユーザ入力値を動的に出力をせず、innerHTMLのような危ないDOM操作しないような作りをしましょう。後者は、DOM操作をしない作りは厳しい場合、HTMLエンティティ文字をエスケープすることで、ある程度の緩和が期待できます。少なくともエスケープすることは必須でしょう。
クライアント(利用者)側でできることとして、今回のケースにおいては、DOM based XSSの緩和策として、NoScriptと呼ばれるJavaScriptの実行を制御する拡張機能を導入することや、実験的な機能ですが、ChromeのTrusted Typesで抑止できました。
NoScriptによるXSSの検出画面
ChromeのTrusted TypesでDOM based XSSが抑止された画面
詳細は下記のドキュメント、記事をご参照ください。
IPA テクニカルウォッチ 「DOM Based XSS」に関するレポート ~JavaScript で HTML を操作するアプリは要注意!~ - https://www.ipa.go.jp/files/000024729.pdf
●ほんまか?
なんや、普通のDOM based XSSやんけ、もっとシビれるの見せてーや。
と、もっと良さげな攻撃手法を思いつけば良かったのですが、現状、一旦ここまで、という具合です。実際にこのような組み合わせ技が成立するケースに遭遇することは稀だとは思いますが、ある一つのやり方として見ていただければと思います。
●CSSインジェクションは軽視できない?
危険だと騒ぎ立てる訳ではないですが、場合によってはCSSインジェクションでも、DOM based XSSが起こりうる。JavaScriptが入り込む怪しい箇所として、CSSも追加されてもいいように個人的には考えます。
●参考記事
本記事の作成にあたって、参照したページです。ありがとうございました。