Results

Fortinet Inc.

01/11/2019 | Press release | Distributed by Public on 01/11/2019 13:34

Microsoft Windows JET Engine Msrd3x Code Execution Vulnerability

Threat Analysis from FortiGuard Labs

In September 2018, Fortinet's FortiGuard Labs researcher Honggang Ren discovered a code execution vulnerability in Windows JET Engine Msrd3x40 and reported it to Microsoft by following Fortinet's responsible disclosure process. On patch Tuesday of January 2019, Microsoft released a Security Bulletin that contains the fix for this vulnerability and identifies it as CVE-2019-0538.

The vulnerable DLL msrd3x40 is a component of all supported Windows versions from Windows 7 to Windows 10. The vulnerability we reported can be triggered with a crafted mdb file. When the mdb PoC file is parsed, a heap corruption occurs due to freeing an invalid heap address. This could result in a code execution exploit.

In this blog, we want to share our detailed analysis of this vulnerability.

Analysis

There are two methods for reproducing this vulnerability.

Method 1:

By loading the PoC file with an Excel oledb external data source using the parameter below, you can see Excel crash. The PoC file can be located in any local or smb share.

Figure 1. Input PoC.mdb

Method 2:

In Windows 10, you can execute 'cscript.exe trigger.vbs' in the command window.

Figure 2. The trigger1.vbs script

Following is the call stack when the crash occurs.

Figure 3. Call stack when crash occurs

From the above call stack output, we can see that the crash occurs in the function 'msrd3x40!free'. Let's enable the cscript.exe full page heap via the command: 'gflags /p /enable cscript.exe /full'.

Then, let's check the cause of the heap memory free failure in the heap memory address. The memory is in MEM_RESERVE state as follows:

Figure 4. Free invalid memory

By reverse engineering and tracing, we can see that the crafted mdb falsely causes the call of msrd3x40.dll because the crafted mdb file header version field is 0. The normal version should be 1. The normal mdb file has the program enter the header decryption code. However, due to the crafted mdb file version field being 0, the crafted mdb file doesn't have the header decryption completed in msjet40.dll.

Figure 5. Comparing with the crafted mdb version and taking wrong branch

So the crafted mdb file results then in going to function msjet40!ErrOpenForeignDatabase+0x65 and calling msrd3x40.dll!ErrIsamOpenDatabase. But handling the normal mdb file would not call the msrd3x40.dll. So from here, the crafted mdb file results in it taking the wrong code branch.

Figure 6. Incorrect version results in calling msrd3x40.dll

The DLL msrd3x40.dll decrypts the crafted mdb header. The data at the offset 0x42 is originally 0x86. After the RC4 decryption of the mdb header, it causes the data at the offset 0x42 to become 0. So another code branch is taken. See following code:

Figure 7. Compare the decrypted mdb header crafted byte in msrd3x40.dll

By now, the invalid heap memory address has still not been generated. By further reverse engineering and tracing, we find that the multiply factor used to generate the invalid heap memory is obtained from following code:

Figure 8. Key multiply factor variable is obtained in msrd3x40.dll

After the above Database::AssignUserNumber function is run, the key multiply factor variable [esi+6ch] equals 0x100.

Next, let's trace the invalid heap memory generation, as follows:

Figure 9. Invalid heap memory address generation in msrd3x40.dll

In the function, [ecx+6c] is the previously obtained key multiply factor0x100. Here, dx=0x1. After assigning the value, [ecx+eax*2+194h] is actually assigned to word 0 due to an overflow, where the word is actually the low word of the freed invalid memory address. That is to say, before calling Database::MarkCorrupt function, the target object heap pointer is correct. After assigning value 0x1 word to the above memory address, however, the invalid heap pointer is generated. This results in freeing the invalid pointer and code execution condition.

From the above analysis, we can see the root cause of the vulnerability is the malformed mdb version value 0x00, which causes the program to take the wrong branch, and the data at the crafted mdb file offset 0x42 is 0x86 and the data at offset 0x600-0x7ff all equal 0. This results in a multiply factor being created with a 0x100 value. In next function call, the low word of the target heap address is overwritten with 1 due to the multiply factor and an invalid heap address is generated. When the invalid heap address is freed, it results in a crash. Successful exploitation of this vulnerability could lead to remote code execution.

Solution

All users of vulnerable versions of the Microsoft Windows Server are encouraged to upgrade to the latest Windows version. Additionally, organizations that have deployed Fortinet IPS solutions have been protected from this vulnerability since Oct 12, 2018 with the following signature:

MS.JET.Database.Engine.Msrd3x.Remote.Code.Execution

More details about this zero-day discovery can be found here.

Learn more about FortiGuard Labs and the FortiGuard Security Services portfolio. Sign up for our weekly FortiGuard Threat Brief.

Know your vulnerabilities - get the facts about your network security. A Fortinet Cyber Threat Assessment can help you better understand: Security and Threat Prevention, User Productivity, and Network Utilization and Performance.

Read about the FortiGuard Security Rating Service, which provides security audits and best practices.