ImageFight2

先日の日記を見て頂いたようで、id:TAKESAKOさんがmod_imagefightをアップデートされていました。

ソースを見ると、height/widthがそれぞれ最大6000pixelに変更されていました。

むむむ・・・これは厳しい(今日は完全に攻撃者の視点になってます)。

しつこく試してみる

前回の日記で書いた攻撃方法のうち、最も攻撃コードが短いのは、<xmp>のパターンでした(これでも5Byteあります)。今のところ、これより短いものは思いつきません。

height/widthの制限が加わったことで、height/widthそれぞれ1Byte強しか使えない事になり、5Byteには全然足りません。

しかし、IHDRには他にも攻撃に使える部分が残されています。

攻撃PNGファイルの構造

IHDRチャンクを以下のようにします。

チャンク名称49 48 44 52I H D R
イメージの幅00 00 08 3c. . . <
イメージの高さ00 00 00 58. . . X
色深度6dm
カラータイプ70p
圧縮方式00.
フィルター方式00.
インターレース方式00.
CRC320c dc 72 06. . r .

網掛けの圧縮方式、フィルター方式、インターレース方式の部分は、mod_imagefightによって上書きされてしまうため攻撃に利用できません。そのため、イメージの幅、イメージの高さ、色深度、カラータイプで何とかします。

攻撃に使えるバイト領域の一部は飛び飛びになっていますが(例えばイメージの幅の<と高さのXは連続していません)、IEがParseの際にNULL文字「00」を無視する事を利用することで、あたかも連続した領域のように使うことが出来ます。

少々苦労するのは、チャンクのデータ部分(イメージの幅〜インターレース方式)には「<xmp」までしか入らないことです。そのため、CRC32の先頭が「>」や空白文字などになるように調整しなければなりません*1

しかし、CRC32の部分に「>」や空白文字などを入れた画像を作っても、mod_imagefightはIHDRのデータ部分の内容に基づきCRC32の領域を再計算して、正しい値に上書きしてしまいます。

そのため、CRC32の「正しい値」の先頭が「>」や空白文字などになるように、イメージの幅の3Byte目を「08」に、xmpの先頭を大文字「X」にしています。この場合、CRC32の先頭文字は「0c」(改ページ文字)となり、IEはめでたくxmpの開始タグを認識してくれます。

xmpタグが認識されると、
<xmp>(mod_imagefightが挿入するplaintextタグ等)
のようなHTMLの構造となり、mod_imagefightが挿入するplaintextタグ等を無効化することができます。

あとは、PLTE(パレット)に、</xmp><script>... のようにJavaScript攻撃コードを仕込めば、それが有効になります。

対策

上記の攻撃は、現状のmod_imagefightが色深度とカラータイプのチェックを行なっていないことを利用し、攻撃コードの一部の埋め込みに使っています。この2つは、本来は規格で定められた値しかセットされてはならないのです(そのため、今回の攻撃で使った画像は、PNG画像として「valid」なものではありません)。

色深度とカラータイプのチェックを行なえば、IHDR内で攻撃者が自由にできる情報の量は非常に少なくなります。そのため、IHDRに対する攻撃コード挿入のリスクは非常に小さいものになると思います*2。少なくとも、私が書いたようなアプローチでの攻撃は無理なんじゃないかと思います。

PNG以外の画像やRFIのことについても、考えるべきことは色々あるのかもしれません。他にまた何か考え付いたら日記に書かせてもらうかもしれません。

#文章の一部におかしな点・判りにくい点があったので修正しました(2007/08/13)

*1:CRC32の先頭を空白文字にした場合、それ以降はxmpタグの属性として扱われ、IHDRの後にmod_imagefightが挿入する「>」によってxmpの開始タグが終端することになります。

*2:CRC32の32bitを自由に攻撃者が制御できれば、まだ攻撃の余地はあるかもしれませんが、イメージの幅と高さが大幅に制限されているので、攻撃者がIHDR内で自由に制御できる情報は32bitもありません。