Source: Platform: Microsoft Office 2010 on Windows 7 x86 Class: Time of check time of use leading to memory corruption The following crash was observed in Microsoft Office 2010 running under Windows 7 x86 with Application Verifier enabled. This crash is non-deterministic and will not reproduce in all instances but the crash demonstrated a high degree of reliability. Attached files: 910494862.ppt: fuzzed crashing file File versions: mso.dll: 14.0.7173.5000 oart.dll: 14.0.7169.5000 ppcore.dll: 14.0.7173.5000 (510.66c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=1a6f0fb0 ebx=3c782fc4 ecx=1a53cfe0 edx=000004bf esi=1a53cfe0 edi=1a4d6fc0 eip=66acdf93 esp=0013d8b0 ebp=0013d8bc iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210202 mso!Ordinal4899+0xd33: 66acdf93 f6465804 test byte ptr [esi+58h],4 ds:0023:1a53d038=?? 0:000> uf 0x66acdf8b mso!Ordinal4899+0xd2b: 66acdf8b 55 push ebp 66acdf8c 8bec mov ebp,esp 66acdf8e 51 push ecx 66acdf8f 51 push ecx 66acdf90 56 push esi 66acdf91 8bf1 mov esi,ecx => 66acdf93 f6465804 test byte ptr [esi+58h],4 Call Stack: 0:000> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 0013d8bc 66ba7720 00000000 1a9d6f98 66ad3d33 mso!Ordinal4899+0xd33 0013d948 67908f0d 1a996e30 1a9d6f98 0000001a mso!Ordinal4720+0x201 0013d980 67906400 0013d9fc 679063f4 0013d9fc oart!Ordinal7979+0x35 0013d994 67908f30 2cccaf58 0013d9fc 0013d9cc oart!Ordinal2490+0x10b 0013d9a4 677e2a14 0013d9fc 1a4d6fd8 1a984ff0 oart!Ordinal7979+0x58 0013d9cc 677e2999 1a4d6ff0 0013d9fc 0013da0c oart!Ordinal6+0xc4 0013d9dc 6788730f 0013d9fc 3a5fe1a5 1a554f8c oart!Ordinal6+0x49 0013da0c 68c8e465 3c782fc4 3a5ff871 68b7e504 oart!Ordinal1989+0xaa 0013da44 68c985dd 3a5fc635 0013e4b4 68b8661c ppcore!PPMain+0x9130c 0013e400 68d0540f 00000000 3c886ea0 00000001 ppcore!PPMain+0x9b484 In this crash the pointer being dereferenced in esi is being tested for a flag value. However, the pointer is referencing invalid memory generating an access violation. The esi value came from the ecx register which is presumably the this pointer. Previous chunk at esi-0x58 is valid memory but 0x58 is beyond that allocated size of that chunk: 0:000> !heap -p -a 19841038 address 19841038 found in _DPH_HEAP_ROOT @ 11a1000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 197f1d9c: 19840fe0 20 - 19840000 2000 70588e89 verifier!AVrfDebugPageHeapAllocate+0x00000229 778c616e ntdll!RtlDebugAllocateHeap+0x00000030 7788a08b ntdll!RtlpAllocateHeap+0x000000c4 77855920 ntdll!RtlAllocateHeap+0x0000023a 710ead1a vrfcore!VerifierSetAPIClassName+0x000000aa 6d7b16ac vfbasics+0x000116ac 60b20233 mso!Ordinal9052+0x0000713f 67808744 oart!Ordinal2033+0x00000090 678086ab oart!Ordinal6561+0x000000ac 6781af9f oart!Ordinal5870+0x00000060 Looking at the calling function: 0:000> uf 0x66ba76ef mso!Ordinal4720+0x1d0: 66ba76ef 56 push esi 66ba76f0 8bf1 mov esi,ecx 66ba76f2 e8a7ddfaff call mso!Ordinal8038+0x461 (66b5549e) ; first call 66ba76f7 85c0 test eax,eax 66ba76f9 7427 je mso!Ordinal4720+0x203 (66ba7722) mso!Ordinal4720+0x1dc: 66ba76fb 8bce mov ecx,esi 66ba76fd e89cddfaff call mso!Ordinal8038+0x461 (66b5549e) ; second call 66ba7702 83781400 cmp dword ptr [eax+14h],0 66ba7706 741a je mso!Ordinal4720+0x203 (66ba7722) mso!Ordinal4720+0x1e9: 66ba7708 8bce mov ecx,esi 66ba770a e88fddfaff call mso!Ordinal8038+0x461 (66b5549e) ; third call 66ba770f 8b4014 mov eax,dword ptr [eax+14h] 66ba7712 8b4810 mov ecx,dword ptr [eax+10h] ; crashing ecx value 66ba7715 85c9 test ecx,ecx 66ba7717 7413 je mso!Ordinal4720+0x20d (66ba772c) mso!Ordinal4720+0x1fa: 66ba7719 6a00 push 0 66ba771b e86b68f2ff call mso!Ordinal4899+0xd2b (66acdf8b) ; crashing function 66ba7720 5e pop esi 66ba7721 c3 ret mso!Ordinal4720+0x203: 66ba7722 f6465804 test byte ptr [esi+58h],4 ; same check as crashing function 66ba7726 7404 je mso!Ordinal4720+0x20d (66ba772c) mso!Ordinal4720+0x209: 66ba7728 8bce mov ecx,esi 66ba772a ebed jmp mso!Ordinal4720+0x1fa (66ba7719) mso!Ordinal4720+0x20d: 66ba772c b8ff0f0000 mov eax,0FFFh 66ba7731 5e pop esi 66ba7732 c3 ret Looking at the logic flow from this function we see at the very first call to mso!Ordinal8038+0x461 must return a non-null value or else the same check in the crashing function is performed in the calling function. With a non-null return this same function is called again only this time the value at [eax+0x14h] is checked to be non-null. If this second check passed then the we call the same function a third time! This time we follow the pointer at [[eax+0x14]+0x10] and check it to be non-null before passing it to the crashing function. Given the repeating calls to the same function and the non-determinism of the bug I suspect this is a time of check time of use bug on the object implementing these methods. Proof of Concept: # Iranian Exploit DataBase = http://IeDb.Ir [2017-02-22]