CVE: CVE-2020-0889
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 processing Excel files. When opening a craft .xls file, especially when the pExcelRecordBuffer
is corrupt, this will cause an Out-of-Bounds write problem.
The crash occurs at msexcl40!WriteStringPool+0xa5
:
0:000> r
eax=25c90000 ebx=256662ec ecx=00000000 edx=00000000 esi=00000000 edi=256662ec
eip=7ca9a905 esp=00f6ea8c ebp=00000000 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
msexcl40!WriteStringPool+0xa5:
7ca9a905 8910 mov dword ptr [eax],edx ds:002b:25c90000=????????
0:000> kb
# ChildEBP RetAddr Args to Child
00 00f6eab0 7ca98066 256657ac 256600fc 256657ac msexcl40!WriteStringPool+0xa5
01 00f6ead4 7ca8b496 256657ac 00000000 00000000 msexcl40!ExcelMISave+0x86
02 00f6eaf0 7ca84f41 256657ac 00000000 00000000 msexcl40!ExcelCloseFile+0x26
03 00f6eb08 7ca7d996 25665744 00000000 252aaf20 msexcl40!WorkbookClose+0x31
04 00f6eb24 7c83b36a 00000000 00000001 00000000 msexcl40!WBDBCloseDatabase+0xd6
05 00f6eb3c 7c81cf4c 252aaf20 000000ff 00000000 msjet40!ErrDispCloseDatabase+0x4a
06 00f6eb50 7c77afb0 252aaf20 000000ff 00000000 msjet40!JetCloseDatabase+0x3c
07 00f6ebd4 7c5643e9 25cafef4 00000000 25cb3fb0 msjetoledb40!CDBSession::~CDBSession+0x220
08 00f6ebe8 7c5a67fb 25cafee8 7c562a99 45181ec9 oledb32!CACMDynamic<CACMAggregationWrapper>::CmFinalRelease+0x5c
09 00f6ebf0 7c562a99 45181ec9 27689fe0 7c562a40 oledb32!CSCM::FinalRelease+0xa
0a 00f6ec14 7c53dd1c 25cafee8 2767fee8 00f6ec9c oledb32!CSCMComPolyObject<CSCM>::Release+0x59
0b 00f6ec24 7c779255 25cafef4 f3aefcc7 2767fee8 oledb32!ATL::CComContainedObject<CACMAggregationWrapper>::Release+0x1c
0c 00f6ec6c 00297521 274e4fdc 00000000 0032ae58 msjetoledb40!CCommand::~CCommand+0x175
EAX
should be ExcelRecordBuffer
locates at msexcl40!pExcelRecordBuffer
, but as we see, the value is corrupted
We will add a breakpoint when the msexcl40!pExcelRecordBuffer
is changed, and then we found it in the function msexcl40!ExcelExtractString
, the msexcl40!pExcelRecordBuffer
is set to a corrupt value:
0:000> r
eax=00000400 ebx=00006161 ecx=00000000 edx=7cac2ce0 esi=00000200 edi=7cac28e0
eip=7ca8b7fc esp=00f6cdb8 ebp=00001908 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
msexcl40!ExcelExtractString+0xbc:
7ca8b7fc 5f pop edi
0:000> ub
msexcl40!ExcelExtractString+0xa8:
7ca8b7e8 668942fe mov word ptr [edx-2],ax
7ca8b7ec 8d4901 lea ecx,[ecx+1]
7ca8b7ef 4b dec ebx
7ca8b7f0 75f0 jne msexcl40!ExcelExtractString+0xa2 (7ca8b7e2)
7ca8b7f2 8d0436 lea eax,[esi+esi]
7ca8b7f5 33c9 xor ecx,ecx
7ca8b7f7 5b pop ebx
7ca8b7f8 66890c38 mov word ptr [eax+edi],cx
0:000> kb5
# ChildEBP RetAddr Args to Child
00 00f6cdbc 7ca8fe2c 00000008 000003a8 7cac28e0 msexcl40!ExcelExtractString+0xbc
01 00f6cde8 7ca8d1a9 256657ac 00f6ce40 7ca84c60 msexcl40!ProcessFormatRecord+0x9c
02 00f6cfb8 7ca8567f 256657ac 7cabc4e0 00000000 msexcl40!ExcelScanFile+0x549
03 00f6d5ec 7ca7eb7f 00f6dac8 00f6d650 00000112 msexcl40!WorkbookOpen+0x11f
04 00f6e0d4 7c827187 252aaf20 20a82ff4 00f6e3ec msexcl40!WBISAMOpenDatabase+0xb4f
0:000> dd msexcl40!pExcelRecordBuffer L1
7cac2ce0 25c90000
As we can see the msexcl40!pExcelRecordBuffer
is set to 0x25c90000
, the normal value should be 0x25c91cfc
:
0:000> dd eax+edi L1
7cac2ce0 25c91cfc
The instruction mov word ptr [eax+edi],cx
at 0x7ca8b7f8
causes this corrupt value. We can see that edi points to msexcl40!ExcelRecordTextBuffer
and it is a normal value, then the eax
is corrupt.
We analyzed the ExcelExtractString
function and find that eax
is related to the cbMultiByte
parameter.
ExcelExtractString
accepts 6 parameters:
ExcelExtractString (int, UINT CodePage, LPWSTR lpWideCharStr, int cchWideChar, LPCSTR lpMultiByteStr, int cbMultiByte)
0:000> dd esp
00f6cdc4 00000008 000003a8 7cac28e0 00000200
00f6cdd4 25c91d00 00001904 256657ac 00000000
00f6cde4 00f6cfb8 7cabc4e0 7ca8d1a9 256657ac
int =0x8
CodePage=0x000003a8
lpWideCharStr=0x7cac28e0
cchWideChar=0x00000200
lpMultiByteStr=0x25c91d00
cbMultiByte=0x00001904
The cbMultiByte
is 0x00001904
in our case, and this value comes from the offset 0x11BC
in our PoC file.
How is this value checked before use?
Let’s look at the code around msexcl40+0x1B7A1
:
loc_1001B7A1:
mov ecx, [esp+8+lpMultiByteStr]
mov edx, [esp+8+cchWideChar]
mov esi, edx
push ebx
mov bl, [ecx]
inc ecx
cmp eax, edx
cmovl esi, eax
cmp bl, 1
jnz short loc_1001B7D6
In our case, cchWideChar
is set to 0x200
at the parent call function. There is a comparison between cchWideChar
and cbMultiByte
with cmp eax, edx
:
eax=00001904 ebx=00006100 ecx=25c91d01 edx=00000200 esi=00000200 edi=7cac28e0
eip=7ca8b7af esp=00f6cdb4 ebp=00001908 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
msexcl40!ExcelExtractString+0x6f:
7ca8b7af 3bc2 cmp eax,edx
0:000> p
eax=00001904 ebx=00006100 ecx=25c91d01 edx=00000200 esi=00000200 edi=7cac28e0
eip=7ca8b7b1 esp=00f6cdb4 ebp=00001908 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
msexcl40!ExcelExtractString+0x71:
7ca8b7b1 0f4cf0 cmovl esi,eax
As eax
is greater than edx
, esi
won’t be changed. It will keep its original value with 0x200
.
When the program executes to msexcl40!ExcelExtractString+0xb8
:
0:000> g
Breakpoint 2 hit
eax=00000400 ebx=00006161 ecx=00000000 edx=7cac2ce0 esi=00000200 edi=7cac28e0
eip=7ca8b7f8 esp=00f6cdb8 ebp=00001908 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
msexcl40!ExcelExtractString+0xb8:
7ca8b7f8 66890c38 mov word ptr [eax+edi],cx ds:002b:7cac2ce0=1cfc
The offset(eax) is 0x400
,and the global variable pExcelRecordBuffer
is next to ExcelRecordTextBuffer
To conclude, the value at offset 0x11BC
in the PoC will be treated as the cbMultiByte
value in function ExcelExtractString
. It is treated as Format Record Length
, but the program failed to check it. The program will write to 0x400+ExcelRecordTextBuffer
, corrupt the pExcelRecordBuffer
.
Timeline:
- 2019-12-04 Vendor disclosure
- 2020-04-14 Vendor patched
Vendor Response
The vendor has acknowledged the issue and released an update to address it.
The vendor advisory can be found here: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2020-0889.