先日の日記を見て頂いたようで、id:TAKESAKOさんがmod_imagefightをアップデートされていました。
ソースを見ると、height/widthがそれぞれ最大6000pixelに変更されていました。
むむむ・・・これは厳しい(今日は完全に攻撃者の視点になってます)。
しつこく試してみる
前回の日記で書いた攻撃方法のうち、最も攻撃コードが短いのは、<xmp>のパターンでした(これでも5Byteあります)。今のところ、これより短いものは思いつきません。
height/widthの制限が加わったことで、height/widthそれぞれ1Byte強しか使えない事になり、5Byteには全然足りません。
しかし、IHDRには他にも攻撃に使える部分が残されています。
攻撃PNGファイルの構造
IHDRチャンクを以下のようにします。
チャンク名称 | 49 48 44 52 | I H D R |
イメージの幅 | 00 00 08 3c | . . . < |
イメージの高さ | 00 00 00 58 | . . . X |
色深度 | 6d | m |
カラータイプ | 70 | p |
圧縮方式 | 00 | . |
フィルター方式 | 00 | . |
インターレース方式 | 00 | . |
CRC32 | 0c 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)