
CVE-2014-1773 का तकनीकी विश्लेषण, इंटरनेट एक्सप्लोरर के MSHTML इंजन में एक हीप भ्रष्टाचार भेद्यता, जिसमें विस्तृत क्रैश कॉलस्टैक, डिसअसेंबली और शोषण के लिए हीप हेरफेर तकनीकें शामिल हैं।
CClipStack::PushClipRect() अमान्य सरणी अनुक्रमण
पहले, pageheap सक्षम के साथ क्रैश से कॉलस्टैक से शुरू करते हैं:
ChildEBP RetAddr 0919aac8 6b58459f MSHTML!CWorldTransform::IsAxisAligned 0919ab40 6ba228e9 MSHTML!CDispSurface::CClipStack::PushClipRect+0x1a2 0919aba4 6be25b58 MSHTML!CDispSurface::PushClipRectInternal+0x2f 0919abc0 6bf1118f MSHTML!CDispSurface::PushClipRectUser+0x26 0919ac24 6bf1157e MSHTML!CCanvasCompositor::ClearRightAndBelowRenderedRegion+0xcd 0919acd8 6b28108c MSHTML!CCanvasCompositor::ExecuteCompositionEffects+0x34d 0919ace0 6b2802f4 MSHTML!CCanvasCompositor::Flush+0x3d 0919ace8 6bf0c867 MSHTML!CCanvasCompositor::~CCanvasCompositor+0x10 0919ae28 6bf0b668 MSHTML!CCanvasRenderingContext2D::StrokeRectInternal+0x1b3 0919ae70 6bf0e032 MSHTML!CCanvasRenderingContext2D::ExecuteStrokeRect+0x1c5 0919aebc 6bd74b6f MSHTML!CCanvasRenderingContext2D::Var_strokeRect+0xac 0919aee0 6ae7056e MSHTML!CFastDOM::CCanvasRenderingContext2D::Trampoline_strokeRect+0x3b 0919af50 6ae6cdda jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x165 0919b328 6ae6dc86 jscript9!Js::InterpreterStackFrame::Process+0x1e74 0919b474 09560fd9 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x1e7
यदि हम एक फ़ंक्शन पीछे जाएं, तो यह वह ऑब्जेक्ट पॉइंटर सेट करता है जो क्रैश में उपयोग किया गया है:
.text:63CDE575 ; public: long __thiscall CDispSurface::CClipStack::PushClipRect(class CRectF const &, class CWorldTransform const *, bool, bool) .text:63CDE575 mov edi, edi .text:63CDE577 push ebp .text:63CDE578 mov ebp, esp .text:63CDE57A sub esp, 64h .text:63CDE57D and [ebp+var_8], 0 .text:63CDE581 mov edx, ecx .text:63CDE583 push ebx .text:63CDE584 push esi .text:63CDE585 mov esi, [ebp+arg_0] .text:63CDE588 push edi .text:63CDE589 lea edi, [ebp+var_28] .text:63CDE58C mov [ebp+var_4], edx .text:63CDE58F movsd .text:63CDE590 movsd .text:63CDE591 movsd .text:63CDE592 movsd .text:63CDE593 mov esi, [ebp+arg_4] .text:63CDE596 test esi, esi .text:63CDE598 jnz loc_63B1A8DF .text:63CDE59E .text:63CDE59E loc_63CDE59E: .text:63CDE59E imul ecx, [edx+4], 18h .text:63CDE5A2 xor bl, bl .text:63CDE5A4 mov eax, [edx+8] .text:63CDE5A7 add eax, 0FFFFFFE8h .text:63CDE5AA add eax, ecx .text:63CDE5AC mov [ebp+arg_0], eax .text:63CDE5AF mov edi, [eax+14h]
बाहरी ऑब्जेक्ट CDispSurface, अपने अंदर एक CClipStack ऑब्जेक्ट रखता है। CClipStack ऑब्जेक्ट CDispSurface ऑब्जेक्ट में ऑफसेट 0x64 पर शुरू होता है। CClipStack मूलतः CImplAry का एक उपवर्ग (subclass) है, जो एक सामान्य सरणी क्लास है जिसका Internet Explorer सरणियों के लिए हर जगह उपयोग करता है। उपरोक्त फ़ंक्शन CDispSurface::CClipStack::PushClipRect में, 'this' पॉइंटर बाहरी CDispSurface के अंदर उप-ऑब्जेक्ट CClipStack है।
CClipStack ऑब्जेक्ट कुछ इस प्रकार दिखता है:
DWORD dwMaxElems; DWORD dwCurElems; VOID *pElems;
तो, उपरोक्त कोड को देखकर, आप अंदाजा लगा सकते हैं कि क्या हो रहा है। उपरोक्त कोड CClipStack सरणी से अंतिम तत्व निकाल रहा है। सरणी में प्रत्येक तत्व का आकार 0x18 बाइट्स है, इसलिए:
imul ecx, [edx+4], 18h ; dwCurElems * 0x18 mov eax, [edx+8] ;pElems
लेकिन फिर आप निम्न देख सकते हैं:
add eax, 0FFFFFFE8h ; subtract 0x18 from pElems add eax, ecx ; pElems += (dwCurElems * 0x18)
हालांकि, यदि सरणी खाली है, तो dwCurElems * 0x18 '==' 0, और इसलिए pElems वास्तव में सरणी के प्रारंभ के पीछे, उसके नीचे स्थित निकटवर्ती हीप चंक (heap chunk) की ओर इशारा करेगा। सरणी में स्वयं CWorldTransform प्रकार की वस्तुएँ होती हैं, जैसा कि आप उस कोड से अनुमान लगा सकते हैं जो सरणी से ऑब्जेक्ट निकालने के तुरंत बाद क्रैश होता है। ecx वह ऑब्जेक्ट पॉइंटर है जो 'mov edi, [eax+14h]' ऑपरेशन से लिया गया है:
.text:63B1A940 ; public: bool __thiscall CWorldTransform::IsAxisAligned(void)const
.text:63B1A940 test dword ptr [ecx+8], 80000000h ;ecx == BAD
तो, सरणी कहाँ आवंटित है:
MSHTML!CDispSurface::CClipStack::PushClipRect+0x32: 6b97e5a7 83c0e8 add eax,0FFFFFFE8h 0:013> !heap -p -a eax address 0c4b0fa0 found in _DPH_HEAP_ROOT @ 211000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) c45123c: c4b0fa0 60 - c4b0000 2000 739f8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229 77a95e7a ntdll!RtlDebugAllocateHeap+0x00000030 77a5a3ba ntdll!RtlpAllocateHeap+0x000000c4 77a25a70 ntdll!RtlAllocateHeap+0x0000023a 6b55c592 MSHTML!CImplAry::EnsureSizeWorker+0x00000061 6b584513 MSHTML!CDispSurface::BeginDraw+0x00000122 6b2847a0 MSHTML!CCanvasRenderingContext2D::BeginDraw+0x00000041 6b286155 MSHTML!CCanvasContextBase::OpenBitmapRenderTarget+0x00000014 6b283b77 MSHTML!CCanvasCompositor::Initialize+0x0000102f 6b285cf7 MSHTML!CCanvasRenderingContext2D::StrokeGeometry+0x00000131 6b285090 MSHTML!CCanvasRenderingContext2D::ExecuteStroke+0x000002c4 6b284dae MSHTML!CFastDOM::CCanvasRenderingContext2D::Trampoline_stroke+0x00000035 6ae7056e jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x00000165 6ae6cdda jscript9!Js::InterpreterStackFrame::Process+0x00001e74 6ae6dc86 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x000001e7
यह 0x60 LFH bin में है। हम कुछ हीप क्राफ्टिंग करके सरणी के पीछे के चंक को नियंत्रित कर सकते हैं। लेकिन उपरोक्त कोड का बुरा हिस्सा यह है कि उपयोग की गई वस्तु को निकालने के लिए गणना इस प्रकार है:
(BYTE *)pArrayStart - 0x18 + 0x14 => (BYTE *)pArrayStart - 0x4
इसके परिणामस्वरूप LFH चंक हेडर के फ़्लैग्स/इंडेक्स फ़ील्ड को एक ऑब्जेक्ट पॉइंटर के रूप में उपयोग किया जाता है। यह वास्तव में अच्छा नहीं है क्योंकि उस फ़ील्ड में बाइट्स अत्यधिक नियंत्रणीय नहीं हैं (मेरी राय में)।
यह देखने के लिए कि LFH हेडर के उस दूसरे dword को संभवतः कैसे नियंत्रित किया जाए:
http://illmatics.com/Understanding_the_LFH.pdf
Sean Larsson के साथ सहयोग