Host:リクエストヘッダによるXSS
本日、とある会合にてTwitterで交わされていたこの会話が話題になりました。
紹介されている例はHostヘッダの操作を経路とする攻撃ということであり、Hostヘッダインジェクションという脆弱性はないと思いますよ / “PHPにおけるHostヘッダインジェクション脆弱性 ― A Day in Serenit…” https://t.co/sTzTQEE7a8
— 徳丸 浩 (@ockeghem) 2015, 11月 6
@ockeghem @okumuri 実はIEでは細工したホストヘッダを送出できる手法が知られています。間違いなくIEのバグですが、このせいで値をそのまま出力しているサイトではXSSがありえてしまいます。ここが参考になります: https://t.co/G419aaUgNi
— Masato Kinugawa (@kinugawamasato) 2015, 11月 9
知る人ぞ知る、細工したlocationヘッダを介すことで、ホストヘッダに変な文字を入れられるIEの面白挙動を使ったXSS
http://t.co/i1vJyZa2pz
— Masato Kinugawa (@kinugawamasato) 2015, 3月 21
HTML内にHostリクエストヘッダをエスケープせずに出力しているケースは実際のWebサイトでもまれに見かけるものの、それはBurpやFiddlerなどのProxyツールでHostリクエストヘッダを書き換えた場合に発見されるものであり、受動的攻撃すなわち罠ページを経由して利用者のブラウザから偽のHostヘッダを送信することはできないため、実際にXSSの脅威は存在しないというのが知る限りWebセキュリティ業界でも一般的な考え方でした。あるいはDNSリバインディングを用いて罠サイトのドメインの一部として該当WebサーバのIPアドレスを返すことで偽のHostヘッダを与えることはできるものの、その場合にXSSが発生したとしてもそれは偽サイトのドメイン上でのXSSであり、やはり実際の脅威は考えにくいと思われていました。
ところが、Masato Kinugawaさんの示された情報によると、IEでは罠ページ上で302などでリダイレクトしつつLocationヘッダに%2Fなどを含めると、それらをデコードした値をHostヘッダとして送信するということで、これらを利用するとHostヘッダをHTML上にそのまま出力しているサイトではXSSが可能ということになります。
- XSS via Host header - www.google.com/cse | MB blog
- Kolejny XSS w www.google.com (Custom Search Engine)
実際に、以下のようなnode.jsのコードで罠サイト(example.jp)および攻撃対象サイト(example.com)を動作させた場合、IEでexample.jpを訪問するとブラウザとしてはexample.comへ訪問するにも関わらず、Host:ヘッダには「example.com/?"onmouseover=alert(location.host)//」がセットされ、それがそのままエスケープされずに出力されているのでXSSが発生します。
"use strict"; var http = require('http'); (function(){ http.createServer(function (req, res) { if( req.headers["host"] === "example.jp" ){ // 攻撃者の用意した罠サイト example.jp res.writeHead( 302, { "Location" : "http://example.com%2f%3f%22onmouseover=alert(location.host)%2f%2f"} ); res.end(); }else{ // 攻撃対象となるサイト example.com では Host ヘッダをエスケープせずに出力している res.writeHead( 200, { "Content-Type" : "text/html;charset=utf-8", "X-XSS-Protection" : "0" } ); res.end( '<html><body><a href="' + req.headers["host"] + '">aa</a></html>' ); } }).listen(80); console.log( "Running server on port 80" ); })();
なお、この例のように単純なXSSであればIEのXSSフィルターが作動するためにJavaScriptの実行はブロックされますが、実際にはXSSフィルターをバイパスする手法も多くみつかっているため、XSSフィルターの存在を以て脅威を軽視するべきではありません。また、上記例では、挙動をわかりやすくするためにあえてXSSフィルターを無効にしています。
その他検証が足りていない部分
- IE11でも動作するとXSS via Host header - www.google.com/cse | MB blogには書かれているが、IE11 on Windows 10 ではこの問題は修正されているように見える。
- ApacheやNginxではHostヘッダに/が含まれる場合に 400 Bad Request を返すとのこと