少々古いOperaでもinnerHTMLで何かを取得すると危うい

はせがわようすけさんによる連載の記事、『[これはひどい]IEの引用符の解釈』が面白かったので手元の少々古めのOpera(9.02ぐらい)で試すことにしました。

<div id="div1">
<input type="text" value="ここに攻撃者の指定した文字列が挿入可能">
</div>
<div id="div2">
</div>
<script>
document.getElementById( "div2" ).innerHTML =
document.getElementById( "div1" ).innerHTML;
</script>
攻撃者の指定した文字列ですが、IEの場合には『``』などを含ませると結果的にDOM構造が壊れるとのこと、私が試した範囲ではOpera(9.02ぐらい)の場合には、『``』の替わりに『&quot;』を入れるとDOMが壊れてしまいました。なお現時点での最新版(9.64)ではこのような問題をみつけられませんでした。Operaサイドでは修正をしたのですね、IEもなおるといいなぁ。

2009/11/18追記: もう少し詳しい情報を、Opera9.27におけるinnerHTML取得時の引用符解釈の不備に書きました。

IEのcreateElementの不思議な挙動

善用も悪用も出来ない豆知識です。いくつかのバージョンのIEではcreateElementに不具合があります。以下のサンプルを見てください。

<!-- saved from url=(0014)about:internet -->
<html>
<head>
<title>FOO</title>
<script>
var strA;
strA = 'textarea'; //ここに文字列を設定可能だとします

var myfunc = function () {
var nDiv, nElm;
nDiv = document.createElement('div');
nElm = document.createElement(strA);
nDiv.appendChild(nElm);
document.body.innerHTML = nDiv.innerHTML;
};

window.onload = myfunc;

</script>
</head>

<body>
</body>

</html>

上のサンプルでは、body要素にtextarea要素を流し込んでいます。ウェブアプリの実践ではこのようなことは、まず、しないと思いますけれど、私はかつて上記のような例題を複数みつけたことがあります。さて、上のサンプルにおける『textarea』が格納されているstrAという文字リテラルを第三者が設定可能だと考えてみましょう。createElementに不具合があるバージョンのIEでは不思議なことが起きます。以下のサンプルを見てください。JavaScriptが実行されてalert(0)の無限ループが発生することになるかと思います。

<!-- saved from url=(0014)about:internet -->
<html>
<head>
<title>FOO</title>
<script>
var strA;
strA = 'textarea style="width:expression(' +
'&#101;&#118;&#97;&#108;(&#34;&#97;' +
'&#108;&#101;&#114;&#116;(0)&#34;)' +
')">FOO<' +
'/textarea><!-- ';


var myfunc = function () {
var nDiv, nElm;
nDiv = document.createElement('div');
nElm = document.createElement(strA);
nDiv.appendChild(nElm);
document.body.innerHTML = nDiv.innerHTML;
};

window.onload = myfunc;

</script>
</head>

<body>
</body>
</html>

IEではcreateElementメソッドに与える文字について検査していないので事実上なんでも良いという不具合です。このことがただちに脆弱性であると言えません。だいたいにおいて上のサンプルのようにcreateElementメソッドに悪意あるユーザが任意の文字列を与えることができるようなウェブサービスなんてありえない、と思っています。なお、サンプルではstyle属性をもちこんでのexpressionを使っていますが、替わりにonmouseover属性をもちこんだりすることも可能なようです。このときには不自然にinnerHTMLで流し込まなくともappendChildメソッドでうまくいくのではないかとお試し中です…うまくいくかなぁ????
いずれにせよ、セキュリティ上は何も心配する必要がないような無駄知識です。でも何かしら脳ミソのニューロンが結線するのではないかと思って書いてみました。いかがでしょうか?

JavaScriptで文字列を結合するハナシ(これで何回目?)

プラス記号を使わずに文字列を結合した〜い。はせがわさんややまがたさんによるevalを使って文字列を結合させる方法に刺激を受けまして、この方向性で手法を拡張したく思いました。ただし、eval, setTimeout, setInterval, Function, constructor , expression(styleの),execscriptなど、実質的にevalを実現できる文字列を明示的に含まないようにです。 今回はDOM操作も我慢しようと思いますのでwindowやdocumentといった文字列を含む記述を禁止かな?今考えているのは、HTMLのscript要素に含まれている形でなんとかできまいかと。 つらいのは、プラス記号を使わないのになんとかして上の複数の文字列のどれかを偽造して実質的にevalこと。ほぼ出来上がったので、デッサンを書いてみます。…IEでうまくいかないんですよねぇ。理由はわかりますけど。

var a, os, ou;
a = "alert(99)";
os = { setTimeous : 0 };
ou = { setTimeouu : 0 };
for (var u in ou) {
for (var s in os) {
for (var t in this) {
if (t > s && t < u) {
(this[t])(a,500)
}
}
}
}
というわけで、setTimeout が windowオブジェクトのメソッドなので呼び出してやろうと。this はグローバルスコープなのでwindowオブジェクトを指し示していると。で、その子供をぐるぐるまわしてos とouとで挟み撃ちしてやればいいのかなぁと。これならsetTimeoutを明示しないで使えませんか?自分の中ではちょっと新しいやりかたです。
なんか今日は日記の量が多いので書き込む時間がなくなってしまいました。以上、書きかけ編集中です。