詰め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さん、ごめんなさい)