Title: Python 3.5 deque.index() Uninitialized Variable
Credit: John Leitch (john@autosectools.com), Bryce Darling (darlingbryce@gmail.com)
Url1: http://autosectools.com/Page/Python-deque-index-Uninitialized-Variable
Url2: http://bugs.python.org/issue24913
Resolution: Fixed
Python 3.5 suffers from a vulnerability caused by the behavior of the newblock() function used by the collections.deque module. When called, newblock() allocates memory using PyMem_Malloc() and does not initialize it:
static block *
newblock(Py_ssize_t len) {
block *b;
if (len >= MAX_DEQUE_LEN) {
PyErr_SetString(PyExc_OverflowError,
"cannot add more blocks to the deque");
return NULL;
}
if (numfreeblocks) {
numfreeblocks--;
return freeblocks[numfreeblocks];
}
b = PyMem_Malloc(sizeof(block)); <<<< Memory allocation.
if (b != NULL) {
return b; <<<< Buffer returned without initialization.
}
PyErr_NoMemory();
return NULL;
}
Because PyMem_Malloc does not initialize the memory, the block may contain garbage data. In some cases, this can lead to memory corruption which could be exploitable to achieve code execution. The following exception analysis is an example of EIP corruption:
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** The OS name list needs to be updated! Unknown Windows version: 10.0 ***
FAULTING_IP:
python35!PyUnicode_Type+0
696f60d8 a800 test al,0
EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 696f60d8 (python35!PyUnicode_Type)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000008
Parameter[1]: 696f60d8
Attempt to execute non-executable address 696f60d8
CONTEXT: 00000000 -- (.cxr 0x0;r)
eax=696f60d8 ebx=00000002 ecx=00d9492c edx=00000002 esi=019b4e58 edi=0337b970
eip=696f60d8 esp=00bcf7dc ebp=00bcf7fc iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
python35!PyUnicode_Type:
696f60d8 a800 test al,0
PROCESS_NAME: pythonw.exe
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_PARAMETER1: 00000008
EXCEPTION_PARAMETER2: 696f60d8
WRITE_ADDRESS: 696f60d8
FOLLOWUP_IP:
python35!PyUnicode_Type+0
696f60d8 a800 test al,0
FAILED_INSTRUCTION_ADDRESS:
python35!PyUnicode_Type+0
696f60d8 a800 test al,0
APP: pythonw.exe
ANALYSIS_VERSION: 6.3.9600.17029 (debuggers(dbg).140219-1702) x86fre
FAULTING_THREAD: 000009dc
DEFAULT_BUCKET_ID: SOFTWARE_NX_FAULT_CODE
PRIMARY_PROBLEM_CLASS: SOFTWARE_NX_FAULT_CODE
BUGCHECK_STR: APPLICATION_FAULT_SOFTWARE_NX_FAULT_CODE_SOFTWARE_NX_FAULT_FALSE_POSITIVE
LAST_CONTROL_TRANSFER: from 69505ad3 to 696f60d8
STACK_TEXT:
00bcf7fc 69505ad3 00000002 00bcf840 694253fc python35!PyUnicode_Type
00bcf808 694253fc 0337b970 019b4e58 00000002 python35!PyObject_RichCompare+0x53
00bcf840 695031c3 03a1a8f0 03a21878 00f83340 python35!deque_index+0xac
00bcf85c 69564433 03a21120 03a21878 00000000 python35!PyCFunction_Call+0x113
00bcf890 695618d8 00e23a08 00000000 00000040 python35!call_function+0x303
00bcf908 6956339f 00e23a08 00000000 00f83000 python35!PyEval_EvalFrameEx+0x2318
00bcf954 6959a142 00e40f58 00000000 00000000 python35!_PyEval_EvalCodeWithName+0x82f
00bcf990 69599fd5 00e40f58 00e40f58 00bcfa5c python35!run_mod+0x42
00bcf9bc 6959904a 00f801f0 00e366f0 00000101 python35!PyRun_FileExFlags+0x85
00bcfa00 6946f037 00f801f0 00e366f0 00000001 python35!PyRun_SimpleFileExFlags+0x20a
00bcfa2c 6946f973 00bcfa5c 00000000 6ecb2100 python35!run_file+0xe7
00bcfad4 1ce31279 00000002 00f79eb0 1ce3c588 python35!Py_Main+0x913
00bcfae4 1ce3145f 1ce30000 00000000 00f71c68 pythonw!wWinMain+0x19
00bcfb30 74ed3744 7f174000 74ed3720 5c8b59d2 pythonw!__scrt_common_main_seh+0xfd
00bcfb44 775aa064 7f174000 a81800d2 00000000 kernel32!BaseThreadInitThunk+0x24
00bcfb8c 775aa02f ffffffff 775cd7c3 00000000 ntdll!__RtlUserThreadStart+0x2f
00bcfb9c 00000000 1ce3150a 7f174000 00000000 ntdll!_RtlUserThreadStart+0x1b
STACK_COMMAND: ~0s; .ecxr ; kb
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: python35!PyUnicode_Type+0
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: python35
IMAGE_NAME: python35.dll
DEBUG_FLR_IMAGE_TIMESTAMP: 5598ccc2
FAILURE_BUCKET_ID: SOFTWARE_NX_FAULT_CODE_c0000005_python35.dll!PyUnicode_Type
BUCKET_ID: APPLICATION_FAULT_SOFTWARE_NX_FAULT_CODE_SOFTWARE_NX_FAULT_FALSE_POSITIVE_BAD_IP_python35!PyUnicode_Type+0
ANALYSIS_SOURCE: UM
FAILURE_ID_HASH_STRING: um:software_nx_fault_code_c0000005_python35.dll!pyunicode_type
FAILURE_ID_HASH: {aa94d074-8f9b-b618-df4f-eaad15f84370}
Followup: MachineOwner
---------
To fix the issue, it is recommended that newblock use PyMem_Calloc instead of PyMem_Malloc. A proposed patch has been attached.