# CVE-2021-1647: Windows Defender mpengine remote code execution
2
-
*Maddie Stone*
2
+
*Maddie Stone,ProjectZero*
3
3
4
4
## The Basics
5
5
skipped 63 lines
69
69
2. The two fields that were overwritten in the object pointed to by the `lfind_switch` object are used as indices in `lfind_switch::switch_in`. Due to no bounds checking on these indices, another out-of-bounds write can occur.
70
70
3. The out of bounds write in step 2 performs an `or` operation on the field in the `VMM_context_t` struct (the virtual memory manager within Windows Defender) that stores the length of a table that tracks the virtual mapped pages. This field usually equals the number of pages mapped * 2. By performing the 'or' operations, the value in the that field is increased (for example from 0x0000000C to 0x0003030c. When it's increased, it allows for an additional out-of-bounds read & write, used for modifying the memory management struct to allow for arbitrary r/w.
71
71
72
+
The second step of overwriting the `lfind_switch` struct is likely done because the `VMM_context_t` struct is very far from the buffer that is originally overflowed (0x3C0000+ in my test). Overwriting this amount of memory would likely make the exploit less stable.
73
+
72
74
**Exploit flow:**
73
75
74
76
The exploit uses "primitive bootstrapping" to to use the original buffer overflow to cause two additional out-of-bounds writes to ultimately gain arbitrary read/write.
skipped 20 lines
95
97
**Ideas to kill the bug class:**
96
98
97
99
* Building `mpengine.dll` with ASAN enabled should allow for this bug class to be caught.
98
-
* Open sourcing unpackers could allow more folks to find issues in this code, which could potentially detect issues like this more readily.
100
+
* Rust. A memory safe language could potentially protect against these types of memory corruption vulnerabilities.
99
101
100
102
**Ideas to mitigate the exploit flow:**
101
103
102
-
* Adding bounds checking to anywhere indices are used. For example, if there hadbeen bounds checkingwhenusing indices in `lfind_switch::switch_in`,itwould have prevented the 2nd out-of-bounds write which allowed this exploit to modify the `VMM_context_t` structure.
104
+
* Ifpossible,adding bounds checking to anywhere indices are used. For example, is there awaytoadd bounds checktowhen indices areusedin `lfind_switch::switch_in`.Itcould havemaybe prevented the 2nd out-of-bounds write which allowed this exploit to modify the `VMM_context_t` structure.Thiswouldbedependentontheattackernotbeingabletooverwritethebounds.
103
105
104
106
**Other potential improvements:**
105
107
106
-
It appears that by default the Windows Defender emulator runs outside of a sandbox. In 2018, there was this [article](https://www.microsoft.com/security/blog/2018/10/26/windows-defender-antivirus-can-now-run-in-a-sandbox/) that Windows Defender Antivirus can now run in a sandbox. The article states that when sandboxing is enabled, you will see a content process `MsMpEngCp.exe` running in addition to `MsMpEng.exe`. By default, on Windows 10 machines, I only see `MsMpEng.exe` running as `SYSTEM`. Sandboxing the anti-malware emulator by default, would make this vulnerability more difficult to exploit because a sandbox escape would then be required in addition to this vulnerability.
108
+
*It appears that by default the Windows Defender emulator runs outside of a sandbox. In 2018, there was this [article](https://www.microsoft.com/security/blog/2018/10/26/windows-defender-antivirus-can-now-run-in-a-sandbox/) that Windows Defender Antivirus can now run in a sandbox. The article states that when sandboxing is enabled, you will see a content process `MsMpEngCp.exe` running in addition to `MsMpEng.exe`. By default, on Windows 10 machines, I only see `MsMpEng.exe` running as `SYSTEM`. Sandboxing the anti-malware emulator by default, would make this vulnerability more difficult to exploit because a sandbox escape would then be required in addition to this vulnerability.
109
+
* Open sourcing unpackers could allow more folks to find issues in this code, which could potentially detect issues like this more readily.
110
+
* It did not appear that this code had been extensively fuzzed. If this is the case, incorporating fuzz-testing into the software development lifecycle could help catch these types of issues.