CVE: CVE-2020-0961

Tested Versions:

  • msexcl40.dll 4.0.9801.17

Product URL(s):

Description of the vulnerability

msexcl40.dll is a part of Microsoft Jet Excel, it is responsible for to process excel files when opening a specially crafted .xls file, an memory corruption will occur.

The crash occurs at msexcl40!memcpy+0x2a:

(42b8.1bc0): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=9f33c218 ebx=00000004 ecx=00000004 edx=00000004 esi=9f33c214 edi=00b3e080
eip=5374abda esp=00b3e00c ebp=00b3e1cc iopl=0         nv up ei pl nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000217
5374abda f3a4            rep movs byte ptr es:[edi],byte ptr [esi]
0:000> kb
 # ChildEBP RetAddr  Args to Child              
00 00b3e010 5373b647 00b3e080 9f33c214 00000004 msexcl40!memcpy+0x2a
01 00b3e028 5372cd8d 25111a7a 00b3e080 00000004 msexcl40!BFReadFile+0x57
02 00b3e1cc 537276c4 251117de 5375c770 00000000 msexcl40!ExcelScanFile+0x12d
03 00b3e1e0 53727c8e 25111776 00000000 00b3e324 msexcl40!NextName+0x24
04 00b3e200 5371cc1a 25111776 00b3e324 00000100 msexcl40!WorkbookNameFirst+0x2e
05 00b3e524 5371dc52 251127a6 256a6168 00b3e54c msexcl40!LocateTableInDatabase+0x28a
06 00b3eb6c 7b8bb575 20a16f20 00000001 256a6168 msexcl40!WBDBDeleteTable+0x1f2
07 00b3eb80 7b89b716 20a16f20 000000ff 256a6168 msjet40!ErrDispDeleteTable+0x35
08 00b3eb9c 7b978e1a 20a16f20 000000ff 256a6168 msjet40!ErrDeleteTable+0x56
09 00b3ed98 7b9449c8 20a16f20 000000ff 000007ff msjet40!ErrExecuteDDL+0xe2e
0a 00b3edc8 7b94634d 20a16f20 000000ff 000007ff msjet40!ErrExecuteTempQuery+0xa0
0b 00b3edf8 7b7f5d40 20a16f20 000000ff 000007ff msjet40!JetExecuteTempQuery+0x90
0c 00b3eea4 7b64d303 25630ff0 25652f34 7b5c48bc msjetoledb40!CImpICommandText::Execute+0x390
0d 00b3efdc 00707521 25648fdc 00000000 0079ae58 oledb32!CCommandText::Execute+0x313

From the crash, we get to know that the source address of memcpy is wrong. In our case, it is 0x9f33c214. Through reverse engineering, we found this value comes from [EDI+0x8] at 0x1002B611:

.text:1002B60A                 push    edi
.text:1002B60B                 mov     edi, [esp+8+arg_0]
.text:1002B60F                 mov     eax, [edi]
.text:1002B611                 mov     ecx, [edi+8]// dirty value

After some further analysis, we found out that the dirty value was written at msexcl40!BFSetFilePosition+0x54:

0:000> r
eax=00000000 ebx=80000000 ecx=9f33c214 edx=80000000 esi=25111a7a edi=251117de
eip=5373b857 esp=00b3e024 ebp=60cc3dec iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
5373b857 5e              pop     esi
0:000> kb3
 # ChildEBP RetAddr  Args to Child              
00 00b3e02c 5372cd26 25111a7a 00000000 00000000 msexcl40!BFSetFilePosition+0x57
01 00b3e1cc 537276c4 251117de 5375c770 00000000 msexcl40!ExcelScanFile+0xc6
02 00b3e1e0 53727c8e 25111776 00000000 00b3e324 msexcl40!NextName+0x24

We can know this value is related to lDistanceToMove, so we will look further. When we look at msexcl40!BFSetFilePosition+0x4d:

eax=7fffffff ebx=80000000 ecx=1f33c214 edx=80000000 esi=25111a7a edi=00000000
eip=5373b84d esp=00b3e020 ebp=60cc3dec iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
5373b84d 2bcb            sub     ecx,ebx

We can easily see that ecx-ebx will result in a negative value, which causes an integer overflow. Next, we are going to see what is ebx: ebx retrieved its value from msexcl40+0x2B817, and ebp is related with [esi+54]:

.text:1002B80C                 mov     edx, [esi+54h]
.text:1002B80F                 mov     ebp, edx
.text:1002B811                 sub     ebp, [esi+4]
.text:1002B814                 mov     ecx, [esi+8]
.text:1002B817                 lea     ebx, [ecx+ebp]
.text:1002B81A                 test    eax, eax
0:000> dd esi+54
25111ace  80000000 00001c00 00000000 00000002
25111ade  00000838 00000000 00000000 00000000
25111aee  00000000 00000000 00000000 00000000

That’s weird that a file position related value is so huge. We set several access breakpoints to trace the value and finally found that it comes from 0x1f33c2a2:

0:000> dd 1f33c2a2
1f33c2a2  80000000 00020042 000d04e4 00010002
1f33c2b2  0002000c 000f0064 00010002 00020011
1f33c2c2  00100000 a9fc0008 624dd2f1 005f3f50
1f33c2d2  00010002 0002000e 00220001 00010002

When we set an access breakpoint at 0x1f33c2a2:

0:000> r
eax=00000000 ebx=0000fde8 ecx=0000fd58 edx=0000fde8 esi=1f33c214 edi=1f33c2a4
eip=5374b224 esp=00b3d2b0 ebp=251117f2 iopl=0         nv up ei pl nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000207
5374b224 f3aa            rep stos byte ptr es:[edi]
0:000> kb3
 # ChildEBP RetAddr  Args to Child              
00 00b3d2b0 537421eb 1f33c214 00000000 0000fde8 msexcl40!memset+0x24
01 00b3d2cc 5373b244 0000fde8 251117de 25111862 msexcl40!AllocateFromGlobalHeap+0x3b
02 00b3d2dc 5372b98f 25111862 00000012 251117f2 msexcl40!BFOpenFile+0x74

We can see BFOpenFile in the call stack, then we infer that the program is trying to read the file. When we go back to see the memory at 0x1f33c2a2. We found the content of this block is the same in the PoC.



  • 2019-11-13 Vendor disclosure
  • 2020-04-14 Vendor patched

Vendor Response

The vendor has patched the Component plugin and acknowledged the security issues at