# CVE-2021-1647: Windows Defender mpengine remote code execution

Heap overflow in Windows Defender mpengine ASProtect unpacker section-table parsing, exploited in the wild to bootstrap arbitrary read/write in SYSTEM context.

- Payout: Real-world hack
- Severity: high
- Program: Microsoft Windows Defender
- Credited: Maddie Stone, Project Zero
- Disclosed: 2021-01-12
- CVE: CVE-2021-1647
- Write-up quality: 9/10
- Original: https://github.com/googleprojectzero/0days-in-the-wild/blob/main/0day-RCAs/2021/CVE-2021-1647.md
- Library page: https://bugbountylibrary.com/r/p0%3ACVE-2021-1647
- Tags: domain:desktop impact:privesc impact:rce kind:incident platform:project-zero sev:high tech:windows technique:chained technique:source-review vuln:dos vuln:memory-corruption vuln:rce

**Target:** mpengine.dll ASProtect unpacker (CAsprotectDLLAndVersion::RetrieveVersionInfoAndCreateObjects)
**Root cause:** Section-table loop only checks next_sect_addr > sect_addr, not equality; duplicate virtual addresses cause 0-byte allocation for a section that later receives 0x3000 bytes during decompression, overflowing the heap buffer.
**Steps:**
1. Craft ASProtect-packed PE with section table `[(0,0),(0,0),(0x2000,0),(0x2000,0x3000)]`
2. Defender unpacks it; at 0x2000 first entry allocates 0 bytes, second equal-address entry is skipped without updating sect_sz
3. Decompression copies 0x3000 bytes into the 0-byte section, overflowing adjacent heap
4. Overflow overwrites first field of `lfind_switch` object allocated in `lfind_switch::switch_out`
5. Overwritten fields used as unchecked indices in `lfind_switch::switch_in`, producing a second OOB write
6. OOB write ORs the page-table length field in `VMM_context_t` (e.g. 0xC -> 0x3030C), enabling further OOB r/w and arbitrary read/write
**How found:** Project Zero analyzed the in-the-wild exploit sample; root cause identified by reading CAsprotectDLLAndVersion::RetrieveVersionInfoAndCreateObjects and noting the comparison lacks an equality check, then diffing against the patched version which adds an else/error branch.
**Exploitation:** Deliver crafted ASProtect-packed executable to a victim; Defender's emulator (running as SYSTEM, unsandboxed by default) unpacks it, triggering the overflow. Attacker uses primitive bootstrapping: original overflow corrupts lfind_switch object, whose unchecked indices yield a second OOB write that ORs VMM_context_t page-table length, expanding the mapped-page table to gain arbitrary read/write in the emulator process.
**Escalation:** Chained three OOB writes (section overflow -> lfind_switch index OOB -> VMM_context_t length corruption) to convert a constrained heap overflow into arbitrary read/write; emulator runs as SYSTEM outside sandbox, so no sandbox escape needed.
**Insight:** When auditing unpackers/parsers, look for monotonicity checks that use strict inequality on addresses or offsets: duplicate/equal values slip past and desynchronize allocation size from later copy size. Also check whether index fields in adjacent heap objects (like lfind_switch) are bounds-checked, since they turn a small overflow into a second primitive.
