classification
Title: msilib.OpenDatabase Type Confusion
Type: security Stage: resolved
Components: Library (Lib), Windows Versions: Python 3.6, Python 3.5, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: steve.dower Nosy List: JohnLeitch, christian.heimes, paul.moore, python-dev, steve.dower, tim.golden, zach.ware
Priority: normal Keywords: patch

Created on 2015-07-08 23:26 by JohnLeitch, last changed 2016-09-09 19:10 by steve.dower. This issue is now closed.

Files
File name Uploaded Description Edit
_msi.patch JohnLeitch, 2015-07-08 23:26 _msi.c patch
msilib.OpenDatabase_Type_Confusion.py JohnLeitch, 2015-07-08 23:27 Repro
Messages (5)
msg246474 - (view) Author: John Leitch (JohnLeitch) * Date: 2015-07-08 23:26
The msilib.OpenDatabase method suffers from a type confusion vulnerability caused by the behavior of MsiOpenDatabase(), the underlying win32 function utilized. This is due to the unorthodox handling of the szPersist parameter: when an MSIDBOPEN_* value is passed, it is treated as a predefined persistence mode. However, when a larger value is passed, it is treated as a string pointer, which is used as the path to a new file.

Because the Python method msilib.OpenDatabase passes its persist parameter through to MsiOpenDatabase, it may be possible for an attacker to trigger the type confusion bug should the seemingly innocuous persist parameter be exposed as attack surface. This could have a few consequences: 

1) An attacker might be able to leverage this vulnerability to probe for valid addresses, which could then be used in another exploit to bypass ASLR/DEP.
2) An attacker might be able to leverage this vulnerability to dereference aribtrary values in memory, disclosing secrets. 
3) An attacker may be able to spray memory with specially crafted string values, then leverage this vulnerability to pass one of the values as a persist string. Because this would lead to the creation of an MSI file in a location now controlled by the attacker, it could potentially be exploited to achieve remote code execution.

A Python script that demonstrates the vulnerability is as follows:

import msilib
msilib.OpenDatabase("",0x41414141)

And it produces the following exception:

0:000> r
eax=41414141 ebx=00000000 ecx=0027f8c0 edx=41414142 esi=0027f8c0 edi=00000000
eip=757252aa esp=0027f874 ebp=0027f89c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
KERNELBASE!lstrlenA+0x1a:
757252aa 8a08            mov     cl,byte ptr [eax]          ds:002b:41414141=??
0:000> !analyze -v -nodb
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************


FAULTING_IP: 
KERNELBASE!lstrlenA+1a
757252aa 8a08            mov     cl,byte ptr [eax]

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 757252aa (KERNELBASE!lstrlenA+0x0000001a)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 41414141
Attempt to read from address 41414141

CONTEXT:  00000000 -- (.cxr 0x0;r)
eax=41414141 ebx=00000000 ecx=0027f8c0 edx=41414142 esi=0027f8c0 edi=00000000
eip=757252aa esp=0027f874 ebp=0027f89c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
KERNELBASE!lstrlenA+0x1a:
757252aa 8a08            mov     cl,byte ptr [eax]          ds:002b:41414141=??

FAULTING_THREAD:  00000d38

PROCESS_NAME:  python.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:  00000000

EXCEPTION_PARAMETER2:  41414141

READ_ADDRESS:  41414141 

FOLLOWUP_IP: 
msi!CApiConvertString::operator unsigned short const *+1b1d
622e1fa1 40              inc     eax

NTGLOBALFLAG:  70

APPLICATION_VERIFIER_FLAGS:  0

APP:  python.exe

ANALYSIS_VERSION: 6.3.9600.17029 (debuggers(dbg).140219-1702) x86fre

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_READ_FILL_PATTERN_41414141

PRIMARY_PROBLEM_CLASS:  INVALID_POINTER_READ_FILL_PATTERN_41414141

DEFAULT_BUCKET_ID:  INVALID_POINTER_READ_FILL_PATTERN_41414141

LAST_CONTROL_TRANSFER:  from 622e1fa1 to 757252aa

STACK_TEXT:  
0027f89c 622e1fa1 41414141 41414141 623e22d0 KERNELBASE!lstrlenA+0x1a
0027fcfc 1d162217 01c54334 41414141 0027fd10 msi!CApiConvertString::operator unsigned short const *+0x1b1d
0027fd18 1e0aafd7 00000000 01d86940 01d7ea08 _msi!msiopendb+0x37
0027fd30 1e0edd10 01d7ea08 01d86940 00000000 python27!PyCFunction_Call+0x47
0027fd5c 1e0f017a 0027fdb4 01c86b18 01c86b18 python27!call_function+0x2b0
0027fdcc 1e0f1150 01cb4030 00000000 01c86b18 python27!PyEval_EvalFrameEx+0x239a
0027fe00 1e0f11b2 01c86b18 01cb4030 01c8aa50 python27!PyEval_EvalCodeEx+0x690
0027fe2c 1e11707a 01c86b18 01c8aa50 01c8aa50 python27!PyEval_EvalCode+0x22
0027fe44 1e1181c5 01d43a20 01c8aa50 01c8aa50 python27!run_mod+0x2a
0027fe64 1e118760 68e87408 003f2e93 00000101 python27!PyRun_FileExFlags+0x75
0027fea4 1e1190d9 68e87408 003f2e93 00000001 python27!PyRun_SimpleFileExFlags+0x190
0027fec0 1e038d35 68e87408 003f2e93 00000001 python27!PyRun_AnyFileExFlags+0x59
0027ff3c 1d00116d 00000002 003f2e70 003f1940 python27!Py_Main+0x965
0027ff80 75847c04 7ffde000 75847be0 0c2f39c0 python!__tmainCRTStartup+0x10f
0027ff94 77c9b90f 7ffde000 0e681648 00000000 KERNEL32!BaseThreadInitThunk+0x24
0027ffdc 77c9b8da ffffffff 77c806e0 00000000 ntdll!__RtlUserThreadStart+0x2f
0027ffec 00000000 1d001314 7ffde000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  .cxr 0x0 ; kb

SYMBOL_STACK_INDEX:  1

SYMBOL_NAME:  msi!CApiConvertString::operator unsigned short const *+1b1d

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: msi

IMAGE_NAME:  msi.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  5450468f

FAILURE_BUCKET_ID:  INVALID_POINTER_READ_FILL_PATTERN_41414141_c0000005_msi.dll!CApiConvertString::operator_unsigned_short_const_*

BUCKET_ID:  APPLICATION_FAULT_INVALID_POINTER_READ_FILL_PATTERN_41414141_msi!CApiConvertString::operator_unsigned_short_const_*+1b1d

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:invalid_pointer_read_fill_pattern_41414141_c0000005_msi.dll!capiconvertstring::operator_unsigned_short_const_*

FAILURE_ID_HASH:  {11693fba-32c4-0880-2440-574cbd780159}

Followup: MachineOwner
---------

To fix the issue, msiopendb() should perform whitelist validation of the persist value to confirm that it is a valid MSIDBOPEN_* constant. A proposed patch is attached.
msg246475 - (view) Author: John Leitch (JohnLeitch) * Date: 2015-07-08 23:27
Attaching repro file.
msg275223 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2016-09-09 00:01
Steve, please have a look.
msg275391 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2016-09-09 19:01
I'm applying the patch, with one small change to pass through persist rather than assuming the variable exists. It'll be 2.7, 3.5 and default.
msg275395 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2016-09-09 19:10
New changeset e524d5dc8767 by Steve Dower in branch '2.7':
Issue #24594: Validates persist parameter when opening MSI database
https://hg.python.org/cpython/rev/e524d5dc8767

New changeset fa89e107f43d by Steve Dower in branch '3.5':
Issue #24594: Validates persist parameter when opening MSI database
https://hg.python.org/cpython/rev/fa89e107f43d
History
Date User Action Args
2016-09-09 19:10:34steve.dowersetstatus: open -> closed
resolution: fixed
stage: resolved
2016-09-09 19:10:11python-devsetnosy: + python-dev
messages: + msg275395
2016-09-09 19:01:17steve.dowersetmessages: + msg275391
versions: + Python 3.5, - Python 3.7
2016-09-09 00:01:58christian.heimessetversions: + Python 2.7, Python 3.6, Python 3.7
nosy: + christian.heimes

messages: + msg275223

assignee: steve.dower
2015-07-09 07:43:01BreamoreBoysetnosy: + paul.moore, tim.golden, zach.ware, steve.dower
components: + Windows
2015-07-08 23:27:38JohnLeitchsetfiles: + msilib.OpenDatabase_Type_Confusion.py

messages: + msg246475
2015-07-08 23:26:41JohnLeitchcreate