2007-08-21 アンチ「サニタイびんぷ」
● 画像版サニタイズ言うな(2)
前回のエントリーの後、mod_imagefightのコマンドライン版を作ったりして、検証してみました。まだ検証途中ですが、今回はBMP形式についてのアンチmod_imagefightについて紹介します。
まず、BMP形式のヘッダは以下のようになります(カッコ内はバイト数)。
0000:MARK(2) ='BM' 0002:ファイルサイズ(4) 0006:予約1(2) =0 0008:予約2(2) =0 000A:ビットマップ開始位置(4) 000E:ヘッダサイズ(4) =0x28 0012:イメージ横幅(4) 0016:イメージ高さ(4) 001A:プレーン数(2) =1 001C:ピクセルあたりのビット数(2) 1,4,8,24 001E:圧縮形式(4) =0,1 0022:圧縮後のイメージサイズ 0026:水平解像度(4) 002A:垂直解像度(4) 002E:使用色数(4) 0032:重要な色数(4) 0036:カラーパレット BGR0 の繰り返し(8ビット以下の場合のみ) XXXX:サニタイジング文字列 ※注 ZZZZ:ビットマップ上記で、サニタイジング文字列(※注)については、mod_imagefightが挿入する部分です。BMPは上記のように単純な形式のため、カラーパレットの後にサニタイジング文字列が来ています。本来はカラーパレットの前にこれを起きたいのですが、BMPの構造上、それは不可能と思われます。id:takesakoさんも相当苦労されたのではないかと思います。
このため、カラーパレット(を含むヘッダ部分)については、サニタイジング文字列以外の方法で対処が必要となります。BMPの場合、カラーパレットは最大1024バイト確保されるので、とくにカラーパレットに対する対策は重要です。
mod_imagefightで採用されている方法は次の二点です。
まず、通常カラーパレットは24ビット(3バイト)で表現されますが、BMP形式の場合は、ワード境界に合わせたのか、カラーパレットは一色あたり4バイト使います。4バイト目は予約領域であり、0が入ることになっていますが、ここに攻撃用の文字列を挿入することは可能です。
このため、mod_imagefightでは、この4バイト目の領域を強制的に0にリセットしています。
次に、RGB値に対しては、たまたま'<'や'>'の値になった場合は、値を一つ増やすことによって'<'や'>'の出現を防止しています(関数sanitize_RGB)。ここは、mod_imagefightでもっとも苦しいなぁと感じるところで、微妙に色が変化することになりますが、実用上はそれほど問題にはならないのでしょう。きっと。
さて、この前提で、mod_imagefightに対する攻撃手法を検討します。
BMPは単純な構造であり、またヘッダの多くはmod_imagefightによる正規化により値をあるべき値に変更されています。攻撃文字列のほとんどは、カラーパレットに置くしかないでしょう。しかし、この部分には、肝心の'<'と'>'を使うことができません。
唯一、mod_imagefightが見逃している領域として、「002E:使用色数(4)」があります。ここにタグを書くことにしましょう。といっても、'<'は一つ書くのがせいぜいなので、JavaScriptはイベントハンドラの中に書くことにします。使用色数は4バイトしか使えないので、<IMG>を使うことにして、JavaScriptはonloadイベントとして記述します。
使用色数:<IMG
パレット: SRC="a.png" onload="alert('xss');"
ただし、このままでは、カラーパレットに対する4バイト目のゼロクリアで、JavaScriptがズタズタに切り裂かれますので、3バイトずつに区切った上で、間に一文字入れておきます。以下では、区切りを「~」で表現していますが、ここはゼロクリアされるので、値は何でもかまいません。IEがヌル文字(値0の文字)を無視する性質を利用しています。
パレット: SR~C="~a.p~ng"~ on~loa~d="~ale~rt(~'xs~s')~;"この状態で、mod_imagefightを通すと、以下のようになります。
また、IEでこの画像を表示されると、以下のようにJavaScriptが起動されます。a.pngが存在することが必要ですが、置き場所は調整可能です。
この攻撃への対策は簡単だと思いますので、id:takesakoさんが速攻で修正してくださることでしょう。イメージファイトはまだまだ続く・・・
PS.
mod_imagefightにはGET32LEとかGET32BEというマクロが出てきます。LEとBEはそれぞれリトルエンディアンとビッグエンディアンを表すような気がしますが、名前と実体が逆になっているようです。ご確認を。
参考文献
T.Teradaの日記 - [セキュリティ]ImageFight2
葉っぱ日記 - Apacheに埋め込まれたイメージファイトと戦う文字コードな方法
追記
id:takesakoさんからはてなブックマークコメントを頂戴しました。>ゼロじゃない別の文字でパディングする方法も検討してみます。
これは巧妙な方法ですね。カラーパレット中の予約領域をゼロでクリアしているために、却ってIEがゼロ(ヌル文字)を無視するという仕様を悪用されるわけで、意味のある文字を挿入したら、パレット領域に攻撃文字列を仕込むことは非常に困難になるでしょうね。
# どの文字だったら、攻撃が成立し得るかを考えることは、挑戦的なパズルではありますが。
今後の改良に期待します。
[ツッコミを入れる]
[]