詰めXSS回答第弐回(分割方式)

続きです。Firefoxにおいては、注入するスクリプト断片に「()」を含まないようにしながら関数の実行が可能です。まず簡単のために、詰めXSS出題時に比べて制限をゆるめてみます。とりあえずalert(1)をしてみようとするものです。


<script>
a setter = alert
a = 1
</script>

上記でalert(1)が実行されます。この記法は、Firefoxの初期の実装でして、setter や getter の古い書き方です。また、既に廃止予定の記述方法です。近い将来無効になるかもしれません。

さて、さらに、location.hashがスクリプト注入時のペイロードになっているケースを想定してみましょう。Firefox3.0.11 で確認済みです。


<script>
u setter = unescape
e setter = eval
e = u = location.hash
</script>
location.hashに与えられている文字列をunescapeした後に、evalに引き渡しています。評価が右側から行われます。

ペイロードとしてのlocation.hashは、alert(1)を目標としたいならば、たとえば、以下が考えられます。冒頭の「#」を黙らせた後にalert(1)します。


#1={};alert(1)

#の始末には、もちろん、よくセキュリティ方面の記事でみかけるように、適宜slice(1)などを利用しても良いでしょう。

さて、本来の詰めXSS出題時点では、「.(ドット)」を使わずに記述しようとしていました。要するに、上記のようにlocation.hashをそのまま書き下せません。同様にlocation['hash']やwith(location){hash}のコーディングも出来ません。替わりに、location を使います。Firefox3.0.11で確認しました。


u setter = unescape
e setter = eval
e = u = location

ここで、locationの値として、何を設定すればよいでしょうか。alice.tldが舞台であるとすれば、以下が考えられます。method="POST"として…(GETでもほぼ同じです。)


http://alice.tld/foo.php#%0Aalert(1)
などとすれば、alert(1)が作動します。http;が、JavaScriptの文法でいうラベルに相当します。ラベルのすぐ次に//が来ていますから、ここから先はコメントになります。しかし、途中で%0Aがありますから、unescapeすると改行になります。そこから先はコメントではありません。従って、alert(1)が作動するというわけです。つまり、2行分の文字列をeval関数に引き渡しているわけです。

最後になります。詰めXSSの解といたしましては、先日のcookieを取得する説明で得られたコードをescapeしておいて、上記同様にlocation.hash部に%0Aとともに記してあげればオッケーとなります。

【お詫び】1月ほど前の出題時においてFirefoxの最新バージョンは3.0.10でした。その直後、3.0.11になり、回答の動作確認をしましたが、現時点では最新はFirefox3.5です。ver3.5はこの回答ではまずいようです。e = u = locationの部分でunescapeが何もしてくれないという動作状況です。ここが原因で詰められなくなっているようです。回避方法をさぐりましたが、私の力では及ばないようです。謹んでお詫び申し上げます。(7月になってからとりくもうとおっしゃっていたTAKESAKOさん、ごめんなさい)