CVE-2023-44336
A use-after-free vulnerability exists in the Thermometer Javascript object in Adobe Acrobat Reader 2023.001.20174. Specially crafted javascript code can exploit a use-after-free vulnerability, which can lead to memory corruption and arbitrary code execution. User would need to open a malicious file to trigger the vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Adobe Acrobat Reader 2023.001.20174
Acrobat Reader - https://acrobat.adobe.com/us/en/acrobat/pdf-reader.html
8.8 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-416 - Use After Free
Adobe Acrobat Reader is one of the most popular and feature-rich PDF readers on the market. It has a large user base and is usually a default PDF reader on systems. It also integrates into web browsers as a plugin for rendering PDFs. As such, tricking a user into visiting a malicious web page or sending a specially crafted email attachment can be enough to trigger this vulnerability.
There exists a vulnerability in the way Adobe Reader DC handles Thermometer
object which can lead to a use-after-free vulnerability.
When property thermometer
of App
object is accessed, getter is called and, if necessary (e.g. dead object), creates a new object of size 0x14
bytes inside function sub_101be9d0
in EScript.api
.
sub_101542ed
, which is called internally at [1], returns pointer to new heap block of size 0x14
. Pointer to offset 0x4
of this heap block is passed as an argument to function sub_101bede3
[2] which allocates heap memory of size 0xC
and saves the address at offset 0x4
of the 0x14
-sized heap memory. This heap memory is later used after it is freed.
// EScript.api sub_101be9d0
101beb41 6a14 push 0x14 {var_20}
101beb43 6a01 push 0x1 {var_24}
101beb45 e8a357f9ff call sub_101542ed // [1]
101beb4a 8bf8 mov edi, eax
101beb4c 8d4f04 lea ecx, [edi+0x4] // [2]
101beb4f 51 push ecx {var_28_3}
101beb50 e88e020000 call sub_101bede3 // [3] allocs 0xC heap block
After blur
event is dispatched to one of the fields in the proof-of-concept document, and once onBlur
event handler has changed the pageNum
property of active document and called app.thermometer.end()
, the 0xC
sized memory is freed while Acrobat reflects changes made by the Javascript code. However, the pointer to it, stored inside the 0x14
-sized block, is still not cleared (53650ff0
in the following debugger output).
0:000> dd 68c96fec
68c96fec 53650ff0 7128f020 00000000 00000000
68c96ffc d0d0d0d0 ???????? ???????? ????????
68c9700c ???????? ???????? ???????? ????????
68c9701c ???????? ???????? ???????? ????????
68c9702c ???????? ???????? ???????? ????????
68c9703c ???????? ???????? ???????? ????????
68c9704c ???????? ???????? ???????? ????????
68c9705c ???????? ???????? ???????? ????????
What Thermometer.end()
method does is it internally copies this pointer to a different location, possibly for internal operation each time it is called.
After the document rendering becomes idle and triggers another Javascript function (which basically calls Thermometer.begin()
and Thermometer.end()
), it will do this pointer copying, including the dangling pointer.
After all the Javascript code inside the document has been executed, Acrobat performs some operations, including copying internal pointers from previously copied location to another location [4] again in the following function (AcroRd32.dll
).
6013d3e8 int32_t* sub_6013d3e8(int32_t* arg1, int32_t arg2, int32_t* arg3)
6013d3e8 55 push ebp {__saved_ebp}
6013d3e9 8bec mov ebp, esp {__saved_ebp}
6013d3eb 8b4510 mov eax, dword [ebp+0x10 {arg3}] // dest
6013d3ee 56 push esi {__saved_esi}
6013d3ef 8b7508 mov esi, dword [ebp+0x8 {arg1}] // src
6013d3f2 eb10 jmp 0x6013d404
// Copy pointers
6013d3f4 8b0e mov ecx, dword [esi]
6013d3f6 8b5604 mov edx, dword [esi+0x4]
6013d3f9 8908 mov dword [eax], ecx
6013d3fb 895004 mov dword [eax+0x4], edx // [4]
6013d3fe 83c008 add eax, 0x8
6013d401 83c608 add esi, 0x8
6013d404 3b750c cmp esi, dword [ebp+0xc {arg2}]
6013d407 75eb jne 0x6013d3f4
6013d409 5e pop esi {__saved_esi}
6013d40a 5d pop ebp {__saved_ebp}
6013d40b c3 retn {__return_addr}
Later Acrobat dereferences this previously freed pointer [5], causing it to crash (AcroRd32.dll
).
601418a0 void sub_601418a0(int32_t* arg1)
601418a0 55 push ebp {__saved_ebp}
601418a1 8bec mov ebp, esp {__saved_ebp}
601418a3 57 push edi {__saved_edi}
601418a4 8b7d08 mov edi, dword [ebp+0x8 {arg1}]
601418a7 85ff test edi, edi
601418a9 7414 je 0x601418bf
601418ab 8b07 mov eax, dword [edi] // [5] use-after-free
601418ad 56 push esi {__saved_esi}
601418ae 6a01 push 0x1 {var_10}
601418b0 8b30 mov esi, dword [eax]
601418b2 8bce mov ecx, esi
601418b4 ff1598777661 call dword [__guard_dispatch_icall_fptr]
601418ba 8bcf mov ecx, edi
601418bc ffd6 call esi
601418be 5e pop esi {__saved_esi}
601418bf 5f pop edi {__saved_edi}
601418c0 5d pop ebp {__saved_ebp}
601418c1 c3 retn {__return_addr}
Following is the stack when the vulnerability is triggered:
eax=0e1b4314 ebx=00000000 ecx=70da18a0 edx=00100000 esi=70da18a0 edi=53650ff0
eip=70da18ab esp=004fee48 ebp=004fee4c iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
AcroRd32!AcroWinMainSandbox+0x27cb:
70da18ab 8b07 mov eax,dword ptr [edi] ds:002b:53650ff0=00000000
0:000> k
# ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 004fee4c 70e31a38 AcroRd32!AcroWinMainSandbox+0x27cb
01 004ff09c 70e31598 AcroRd32!DllCanUnloadNow+0x5a888
02 004ff0c4 70e3144f AcroRd32!DllCanUnloadNow+0x5a3e8
03 004ff0f4 70e1aab3 AcroRd32!DllCanUnloadNow+0x5a29f
04 004ff168 70e1a914 AcroRd32!DllCanUnloadNow+0x43903
05 004ff1a0 70d9f847 AcroRd32!DllCanUnloadNow+0x43764
06 004ff214 70d9f26f AcroRd32!AcroWinMainSandbox+0x767
07 004ff638 00ff1914 AcroRd32!AcroWinMainSandbox+0x18f
08 004ff9f0 0103c97a AcroRd32_exe!IsSandboxedProcess+0x1212c4
09 004ffa3c 770cfa29 AcroRd32_exe!AcroRd32IsBrokerProcess+0x1d49a
0a 004ffa4c 77217a9e KERNEL32!BaseThreadInitThunk+0x19
0b 004ffaa8 77217a6e ntdll!__RtlUserThreadStart+0x2f
0c 004ffab8 00000000 ntdll!_RtlUserThreadStart+0x1b
2023-07-03 - Vendor Disclosure
2023-11-14 - Vendor Patch Release
2023-11-15 - Public Release
Discovered by Jaewon Min and Aleksandar Nikolic of Cisco Talos.