CVE: CVE-2019-1406

Tested Versions:

  • Windows 10 version 1903 and below
  • Windows 7

Product URL(s): https://www.microsoft.com

The Microsoft Jet Database Engine (also Microsoft JET Engine or simply Jet) is a database engine on which several Microsoft products have been built. JET stands for Joint Engine Technology. Microsoft Access and Visual Basic have used Jet as their underlying database engine.

Description of the vulnerability

The vulnerable DLL msjet40.dll is a component in versions from Windows 7 to Windows 10. The vulnerability described here can be triggered with a specially-crafted MDB file, and could lead to code execution.

Version information for the vulnerable module is as follows:

0:000> lmvm msjet40
start    end        module name
71750000 718d8000   msjet40    (pdb symbols)    C:\sym\msjet40.pdb\FCEE9E59F87341C385D3737ED014D6DA1\msjet40.pdb
    Loaded symbol image file: C:\Windows\SysWOW64\msjet40.dll
    Image path: C:\Windows\SysWOW64\msjet40.dll
    Image name: msjet40.dll
    Timestamp:        Thu Apr  4 06:26:36 2019 (5CA5331C)
    CheckSum:         0014C8B8
    ImageSize:        00188000
    File version:     4.0.9801.15
    Product version:  4.0.9801.15
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0000.04b0
    Information from resource tables:
        CompanyName:      Microsoft Corporation
        ProductName:      Microsoft (R) Jet
        InternalName:     MSJET40.DLL
        OriginalFilename: MSJET40.DLL
        ProductVersion:   4.00.9801.15
        FileVersion:      4.00.9801.15
        FileDescription:  Microsoft Jet Engine Library
        LegalCopyright:   Copyright (C) Microsoft Corp. 1993-1999

Crash context:

0:000> g
(ab4.1b0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=0521b008 ecx=0521d048 edx=0521b008 esi=07db63e6 edi=00000003
eip=41414141 esp=004bdcb0 ebp=0000003c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
41414141 ??              ???
0:000> kb8
ChildEBP RetAddr  Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
004bdcac 717dc3f6 004bddd0 004bdd34 000003ca 0x41414141
004bdcc0 717dcca7 0521b008 07db63d2 00000050 msjet40!TblPage::CreateLvSMLocs+0x76
004bdd08 717d9c0a 0521b008 051ee968 004bddd0 msjet40!TblPage::InitTable+0x277
004bdd58 717c0513 051ee968 00000002 00000001 msjet40!Table::Open+0x15a
004bdd7c 717cb2ac 05207300 051ed2a8 00000001 msjet40!Instance::Instance+0x213
004bdda4 717b9b80 05211f0c 004be0d0 00000000 msjet40!Session::OpenDatabase+0x14c
004bdde0 7176ba18 05207300 05211f0c 004be0d0 msjet40!ErrIsamOpenDatabase+0xb0
004be048 7176f6cd 05207300 05211f0c 004be0d0 msjet40!ErrOpenDatabase+0x208

The specially-crafted MDB file will cause the program execute ErrOpenDatabase function. From the crash location, we can see the program tried to execute code at an arbitrary location.

In a normal case, ECX would point to a ColumnLvText object:

eax=71042f10 ebx=0518a008 ecx=05159308 edx=0518a008 esi=07e263d2 edi=00000001
eip=7107c3f4 esp=004ade90 ebp=00000050 iopl=0         nv up ei ng nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000297
msjet40!TblPage::CreateLvSMLocs+0x74:
7107c3f4 ffd0            call    eax {msjet40!ColumnLvText::GetType (71042f10)}
address 05159308 found in
_HEAP @ 5120000
  HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
    051592e0 0020 0000  [00]   05159308    000c8 - (busy)
      msjet40!ColumnLvText::`vftable'
    7301a6a7 verifier!AVrfpDphNormalHeapAllocate+0x000000d7
    73018f6e verifier!AVrfDebugPageHeapAllocate+0x0000030e
    77e10fe6 ntdll!RtlDebugAllocateHeap+0x00000030
    77dcab8e ntdll!RtlpAllocateHeap+0x000000c4
    77d73461 ntdll!RtlAllocateHeap+0x0000023a
    7302cb62 verifier!AVrfpRtlAllocateHeap+0x00000092
    711074b9 msjet40!malloc+0x00000049
    71108abf msjet40!operator new+0x0000001d
    71043410 msjet40!Column::NewColumn+0x000002b0

But in this case, ECX points to an Index object, which was created in TblPage::CreateIndexes():

eax=41414141 ebx=007c9fe8 ecx=007cc170 edx=007c9fe8 esi=07f263e6 edi=00000003
eip=7098c3f4 esp=003dda98 ebp=0000003c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
msjet40!TblPage::CreateLvSMLocs+0x74:
7098c3f4 ffd0            call    eax {41414141}
address 007cc170 found in
_HEAP @ 760000
  HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
    007cc148 0020 0000  [00]   007cc170    000c4 - (busy)
    73f9a6a7 verifier!AVrfpDphNormalHeapAllocate+0x000000d7
    73f98f6e verifier!AVrfDebugPageHeapAllocate+0x0000030e
    77e10fe6 ntdll!RtlDebugAllocateHeap+0x00000030
    77dcab8e ntdll!RtlpAllocateHeap+0x000000c4
    77d73461 ntdll!RtlAllocateHeap+0x0000023a
    73facb62 verifier!AVrfpRtlAllocateHeap+0x00000092
    70a174b9 msjet40!malloc+0x00000049
    70a18abf msjet40!operator new+0x0000001d
    7098c1b2 msjet40!TblPage::CreateIndexes+0x000000e2

The contents at this Index+0x50 can be controlled in our specially-crafted file at offset 0x23CA, which has the value 0x41414141. As you can see above, this ultimately leads to code execution at an attacker-controlled address.

Timeline

  • 2019-09-09 Reported to vendor
  • 2019-11-12 Vendor patched

Vendor Response

The vendor has acknowledged the issue and released an update to address it. This issue has been independently found and reported by other researchers – see the vendor advisory for details.

The vendor advisory can be found here: https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1406.