Talos Vulnerability Report


Adobe Acrobat Reader Thermometer use-after-free vulnerability

November 15, 2023
CVE Number



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
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.