IE8のtoStaticHTML関数

以前の日記で、IE8β2のtoStaticHTML関数にバグがあると書きました。

そのバグについては、発見したときにMSに報告しました。その後、特に「直した」という連絡はありませんが、IE8の正式版では修正されていました。

β2にあったバグのPOCは、以下のようなものです。

<body>
<div id="foo"></div>
<script>
var tmp="<img style=\"color:expression(alert('; width:x'))\">";
document.getElementById('foo').innerHTML = toStaticHTML(tmp);
</script>
</body>

ポイントは、alertのちょっとうしろに入れたセミコロンです。β2では、セミコロンが含まれていると、そこで1つの宣言が終わると解釈していました。かなり荒っぽい解釈です。

IE8正式版で上記のHTMLを表示すると、style属性の中身はざっくり空っぽにされます。つまり何らかの対策がされたということだと思います。

そのほかのパターンも試して見ましたが、CSSに関しては非常に大胆な処理がされます。具体的にいうと、括弧がCSSに含まれていると、それだけではじいてしまいます。

ですので、以下のHTMLはJavaScriptを含んでいないのにも関わらず、toStaticHTMLを通りません。

<b style="background-image: url('http://...');">111</b>

<b style="font-family: 'foo(';">111</b>

括弧「(」は、「&#x28;」や「\0028」や「\&#x32;8」にしても、とにかく通してくれません。他にも「\26#x28;」などいろいろな手を使ってみましたが、文字参照まわりは割とまじめに正規化するようになっているため、「(」を入れることができません。なお、括弧が駄目なのは、style属性だけでなくstyleタグも同じです。

攻撃を防ぐためにはこれでよいのでしょうけども、実用上の観点でいうと「(」が使えないのは困ることがあると思います。

その他にも気になることがいくつかあります。

■入力A
<style>ul > li {color:red;}</style>

■出力A  (HTMLエンコードされる)
<style>
ul &gt; li
{color:red;}
</style>
---------------------------------------------------
■入力B
<style>li {font-family:'xxx\27\7Dyyy';}</style>

■出力B  (CSSの「\」エンコードがデコードされる)
<style>
li
{font-family:'xxx'}yyy';}
</style>
---------------------------------------------------
■入力C
<style>li {font-family:'xxx\yyy';}</style>

■出力C  (なぜかNULL文字が出てくる)
<style>
li
{font-family:'xxx&#0;yyy';}
</style>

上のBはXSSまであと一歩という感じですが、結局括弧が入らないために、どうにもなりません。

ただし方向性を少し変えると、うまいことXSSできる場合があります。また、一定の条件がそろえば、XSSできるような軽微な問題も残っています(いずれも互換モードの場合のみ)。CSS周りは、たいていのXSSフィルタにとって最大の鬼門ですが、toStaticHTMLも例外ではないようです。