1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=950 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=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00210202 mso!Ordinal4899+0xd33: 66acdf93 f6465804testbyte ptr [esi+58h],4 ds:0023:1a53d038=?? 0:000> uf 0x66acdf8b mso!Ordinal4899+0xd2b: 66acdf8b 55pushebp 66acdf8c 8becmov ebp,esp 66acdf8e 51pushecx 66acdf8f 51pushecx 66acdf90 56pushesi 66acdf91 8bf1mov esi,ecx => 66acdf93 f6465804testbyte ptr [esi+58h],4 Call Stack: 0:000> kb ChildEBP RetAddrArgs 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 56pushesi 66ba76f0 8bf1mov esi,ecx 66ba76f2 e8a7ddfaffcallmso!Ordinal8038+0x461 (66b5549e) ; first call 66ba76f7 85c0testeax,eax 66ba76f9 7427jemso!Ordinal4720+0x203 (66ba7722) mso!Ordinal4720+0x1dc: 66ba76fb 8bcemov ecx,esi 66ba76fd e89cddfaffcallmso!Ordinal8038+0x461 (66b5549e) ; second call 66ba7702 83781400cmp dword ptr [eax+14h],0 66ba7706 741ajemso!Ordinal4720+0x203 (66ba7722) mso!Ordinal4720+0x1e9: 66ba7708 8bcemov ecx,esi 66ba770a e88fddfaffcallmso!Ordinal8038+0x461 (66b5549e) ; third call 66ba770f 8b4014mov eax,dword ptr [eax+14h] 66ba7712 8b4810mov ecx,dword ptr [eax+10h] ; crashing ecx value 66ba7715 85c9testecx,ecx 66ba7717 7413jemso!Ordinal4720+0x20d (66ba772c) mso!Ordinal4720+0x1fa: 66ba7719 6a00push0 66ba771b e86b68f2ffcallmso!Ordinal4899+0xd2b (66acdf8b) ; crashing function 66ba7720 5epop esi 66ba7721 c3ret mso!Ordinal4720+0x203: 66ba7722 f6465804testbyte ptr [esi+58h],4 ; same check as crashing function 66ba7726 7404jemso!Ordinal4720+0x20d (66ba772c) mso!Ordinal4720+0x209: 66ba7728 8bcemov ecx,esi 66ba772a ebedjmp mso!Ordinal4720+0x1fa (66ba7719) mso!Ordinal4720+0x20d: 66ba772c b8ff0f0000mov eax,0FFFh 66ba7731 5epop esi 66ba7732 c3ret 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: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41418.zip |