プライバシーポリシー

2016年4月14日木曜日

hiddenなinput要素のXSSでJavaScript実行

脆弱性診断をやっていると、たまにtype=hiddenのinput要素にXSSがあるけど、現実的な攻撃には至らないものにぶちあたることがあります。サンプルコードを以下に示します。
<body>
入力確認をお願いします。
<?php echo htmlspecialchars($_GET['t']); ?><br>
<form action='submit.php'>
<input type='hidden' name='t' value='<?php
  echo htmlspecialchars($_GET['t']); ?>'>
<input type='submit'>
</body>
正常系の呼び出しは下記のようになります。

http://example/hidden-xss.php?t=yamada


HTMLソースは下記の通りです。
<body>
入力確認をお願いします。
yamada<br>
<form action='submit.php'>
<input type='hidden' name='t' value='yamada'>
<input type='submit'>
</body>
このスクリプトの何が悪いかというと、属性値をシングルクォートで囲っているのに、htmlspecialcharsのENT_QUOTESオプションを指定していないために、シングルクォートがエスケープされないところにあります。しかし、現実的な攻撃は難しいとされていました。

'><script>alert(1)</script>を指定すると、以下のHTMLが生成されますが、JavaScriptは実行されません。
<input type='hidden' name='t' value=''&gt;&lt;script&gt;alert(1)&lt;/script&gt;'>
' onmouseover='alert(1) を指定する方法はどうか。以下のように、onmouseover属性は作れますが、type=hiddenの場合、マウスカーソルを合わせることができずイベントも発生しません。
<input type='hidden' name='t' value='' onmouseover='alert(1)'>
ところが、malaさんのツイートで知りましたが、PortSwigger Web Security Blogに以下のPoCが発表されていました
<input type="hidden" accesskey="X" onclick="alert(1)">
上記のタグをXSSで生成させると、下記の条件でJavaScriptが実行されます。

  • 被害者ユーザがFirefoxを使っている かつ
  • 被害者がSHIFT+ALT+X キーを押す

これを応用して、前記のサンプルコードを攻撃してみましょう。

http://example/hidden-xss.php?t='+accesskey%3d'X'+onclick%3d'alert(1)

HTMLソースは下記となります。
<body>
入力確認をお願いします。
' accesskey='X' onclick='alert(1)<br>
<form action='submit.php'>
<input type='hidden' name='t' value='' accesskey='X' onclick='alert(1)'>
<input type='submit'>
</body>
ブラウザ側で SHIFT+ALT+X を押すと、下記のようにJavaScriptが実行されます。


ということで、type=hiddenなinput要素に閉じたXSSであっても、被害者がFirefoxを使っている場合、JavaScriptを起動できる場合があることが分かりました。

問題は、被害者にどうやって SHIFT+ALT+X を押させるかですが、以下のようにiframeを使う手があります。攻撃対象サイトは半透明にしていますが、実際の攻撃では透明にするなど、工夫の余地があります。


被害者が罠の誘導にだまされて SHIFT+ALT+X を押してしまうと、下記のようにJavaScriptが動きます。


まとめ

type=hiddenなinput要素に閉じたXSSでは、従来現実的な攻撃は難しいと思われていた(要出典)と考えますが、accesskeyとユーザーへの誘導により、JavaScriptを実行できる場合があることが分かりました。
脆弱性診断の実務では、従来でもこのような「エスケープ漏れ」に対しては指摘は行っていたと思いますが、その危険度の判定が変わる可能性があります。具体的には、元々「Information(念のためお知らせ)」としていた場合は、「Low(低)」くらいが妥当ではないでしょうか。元々Lowでつけていた場合は、Lowのままでもよいかと思いますが、現実的なリスクは変わることになります。

アプリケーション開発の立場においては、現実的な攻撃の可能性にまどわされないで、エスケープすべきものは淡々と正しくエスケープするようにしておけば、この手の「新たな攻撃経路」に右往左往する必要はありません。


【HASHコンサルティング広告】
HASHコンサルティング株式会社は、ウェブアプリケーションのセキュリティに関心のあるセキュリティエンジニアを募集しています。
興味のある方は、twitterfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。

2 件のコメント:

  1. こんにちは。anIORIentと申します。

    formで受け取った文字列を"text"のinput要素、もしくは"textarea"に反映させる場合のXSS対策を調べていて、こちらにたどり着きました。

    今更かもしれませんが、たとえば、隠し要素をラジオボタンにして、そのラベルに受け渡しすべき文字列(上記の例では「yamada」)を設定すれば、少なくとも外部入力で値を変更されたり、スクリプトを挿入されたりといった危険は回避できるのではないでしょうか?

    もちろん、余計な記述(inputタグで「hidden="hidden"」とか、cssで「opacity: 0;」とか)が必要だったり、そもそも最初の担当者以外の人物がメンテすることになったとき、ナゼこんなところに見えないラジオボタンがあるの??と戸惑ったりしそうなので、あまりスマートな解決法じゃないとは思いますが…

    返信削除
    返信
    1. 反応が遅れて申し訳ないです。コメントありがとうございます。どうしてラベルなら攻撃を防げるのか釈然としないことと、hiddenパラメータを使ってもXSS対策自体は難しいわけではないので、ご提案の趣旨がよく分かりません。

      削除