Vulnerabilities > CVE-2017-2971 - Improper Restriction of Operations within the Bounds of a Memory Buffer vulnerability in Adobe products

047910
CVSS 9.3 - CRITICAL
Attack vector
NETWORK
Attack complexity
MEDIUM
Privileges required
NONE
Confidentiality impact
COMPLETE
Integrity impact
COMPLETE
Availability impact
COMPLETE

Summary

Adobe Acrobat Reader versions 15.020.20042 and earlier, 15.006.30244 and earlier, 11.0.18 and earlier have an exploitable heap overflow vulnerability in the JPEG decoder routine. Successful exploitation could lead to arbitrary code execution.

Vulnerable Configurations

Part Description Count
Application
Adobe
247
OS
Apple
1
OS
Microsoft
1

Common Attack Pattern Enumeration and Classification (CAPEC)

  • Buffer Overflow via Environment Variables
    This attack pattern involves causing a buffer overflow through manipulation of environment variables. Once the attacker finds that they can modify an environment variable, they may try to overflow associated buffers. This attack leverages implicit trust often placed in environment variables.
  • Overflow Buffers
    Buffer Overflow attacks target improper or missing bounds checking on buffer operations, typically triggered by input injected by an attacker. As a consequence, an attacker is able to write past the boundaries of allocated buffer regions in memory, causing a program crash or potentially redirection of execution as per the attackers' choice.
  • Client-side Injection-induced Buffer Overflow
    This type of attack exploits a buffer overflow vulnerability in targeted client software through injection of malicious content from a custom-built hostile service.
  • Filter Failure through Buffer Overflow
    In this attack, the idea is to cause an active filter to fail by causing an oversized transaction. An attacker may try to feed overly long input strings to the program in an attempt to overwhelm the filter (by causing a buffer overflow) and hoping that the filter does not fail securely (i.e. the user input is let into the system unfiltered).
  • MIME Conversion
    An attacker exploits a weakness in the MIME conversion routine to cause a buffer overflow and gain control over the mail server machine. The MIME system is designed to allow various different information formats to be interpreted and sent via e-mail. Attack points exist when data are converted to MIME compatible format and back.

Seebug

bulletinFamilyexploit
description### Summary A use of uninitialized memory vulnerability exists in JPEG image file format decoding code of Adobe Acrobat Reader which ultimately leads to a heap-based buffer overflow which can be abused to achieve remote code execution. A specially crafted PDF file with an embedded JPEG can trigger this vulnerability when opened on a victim computer. ### Tested Versions Adobe Acrobat Reader DC 2015.020.20039 ### Product URLs https://get.adobe.com/reader/ ### CVSSv3 Score 8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H ### CWE CWE-457 - Use of Uninitialized Variable ### Details Adobe Acrobat Reader is the most popular and most feature-rich PDF reader. It has a big user base, is usually a default PDF reader on systems and 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 JPEG decoder and parser which can result in the use of two 4 byte integer values which are previously uninitialized. The use of these two uninitialized variables leads to further process corruptions as can be seen in the following crash context: ``` (760.11d8): C++ EH exception - code e06d7363 (first chance) (760.11d8): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Adobe\Acrobat Reader DC\Reader\AcroRd32.dll - eax=25489fdc ebx=254df000 ecx=00001fff edx=00001fff esi=25487fdd edi=254df000 eip=03e9f26d esp=0012d7b4 ebp=0012d7dc iopl=0 nv up ei pl nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010217 MSVCR120!memcpy+0x2a: 03e9f26d f3a4 rep movs byte ptr es:[edi],byte ptr [esi] ``` The above crash occurs with Page Heap enabled. The crash is due to and out of bounds write in a `memcpy` call. This particular `memcopy` call is made inside a function starting at 600D25A3. The following disassembly shows the relevant parts: ``` .text:600D25EA .text:600D25EA loc_600D25EA: .text:600D25EA mov ecx, [edi] [1] .text:600D25EC cmp ecx, esi .text:600D25EE jge short loc_60 ... .text:600D260F loc_600D260F: ; Size .text:600D260F push ecx .text:600D2610 push edx ; Src .text:600D2611 push ebx ; Dst .text:600D2612 call memcpy [2] ... .text:600D2617 .text:600D2617 loc_600D2617: .text:600D2617 mov eax, [edi] .text:600D2619 add esp, 0Ch .text:600D261C add [edi+4], eax .text:600D261F add ebx, eax [3] .text:600D2621 sub esi, eax [4] .text:600D2623 and dword ptr [edi], 0 .text:600D2626 jmp short loc_600D2637 ... .text:600D2637 .text:600D2637 loc_600D2637: .text:600D2637 test esi, esi [5] .text:600D2639 jnz short loc_600D25EA ``` At [1] we enter a loop. At [2] a `memcpy` call occurs, size being 0x1fff in case of our testcase. At [3] destination pointer is increased and at [4] `esi`, which serves as a boundary condition for this loop, is decreased. At [5] it is tested for 0 and the code jumps back if that’s not the case. If we examine the starting value of `esi` we can see that it is unusually big: ``` 1:009> g Breakpoint 0 hit eax=17619024 ebx=1786e001 ecx=00000044 edx=17618fe0 esi=00000045 edi=17618f54 eip=600d2612 esp=0012d908 ebp=0012d924 iopl=0 nv up ei ng nz na po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000283 AcroRd32_60000000!CTJPEGWriter::CTJPEGWriter+0x24aa1: 600d2612 e8592bf7ff call AcroRd32_60000000+0x45170 (60045170) 1:009> g (9d0.518): C++ EH exception - code e06d7363 (first chance) Breakpoint 0 hit eax=25267fdc ebx=25289f01 ecx=00001ffe edx=25265fde esi=5a5a57ff edi=25265f94 eip=600d2612 esp=0012d7c0 ebp=0012d7dc iopl=0 nv up ei ng nz na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000287 AcroRd32_60000000!CTJPEGWriter::CTJPEGWriter+0x24aa1: 600d2612 e8592bf7ff call AcroRd32_60000000+0x45170 (60045170) *** ERROR: Symbol file could not be found. Defaulted to export symbols for c:\Program Files\Adobe\Acrobat Reader DC\Reader\AGM.dll - 1:009> r esi esi=5a5a57ff ``` Since in each round of the loop, `esi` gets decreased by only 0x1fff, the destination buffer for the memcpy call will get increased outside of its allocated space causing a heap-based buffer overflow. Tracing back the origin of the particular value is `esi` through the call stack gets us to the following code in the function starting at 605AC8C2 : ``` .text:605AC9F0 mov eax, [ebx+4] [1] .text:605AC9F3 mov ecx, [eax+0C8h] .text:605AC9F9 lea edx, [eax+0BCh] [2] .text:605AC9FF lea edi, [eax+0B4h] .text:605ACA05 push edx .text:605ACA06 push edi .text:605ACA07 push dword ptr [edx] [3] .text:605ACA09 mov eax, [ecx] .text:605ACA0B push dword ptr [edi] .text:605ACA0D call dword ptr [eax+4] ``` At [1], a pointer is read into `eax`, at [2] an address is copied into `edx` and contents from it get pushed to the stack at [3]. This can be observed in the following debugging output: ``` 605ac9ff 8db8b4000000 lea edi,[eax+0B4h] 1:009> dd edx 24a86f74 81818180 c0c0c0c0 00000190 24a2ffd8 24a86f84 00000000 00000000 00000000 c0c0c0c0 24a86f94 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 24a86fa4 c0c0c0c0 00000001 00800000 00000000 24a86fb4 01000000 c0c0c000 60e21a34 00000000 24a86fc4 00000000 c0c00000 c0c0c0c0 00000000 24a86fd4 00000000 c0c0c0c0 c0c0c0c0 c0c0c0c0 24a86fe4 c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0 1:009> t eax=24a86eb8 ebx=25d89ff0 ecx=24a2ffd8 edx=24a86f74 esi=0012d8e0 edi=24a86f6c eip=605aca05 esp=0012d8c0 ebp=0012d920 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 AcroRd32_60000000!AX_PDXlateToHostEx+0x214130: 605aca05 52 push edx 1:009> t eax=24a86eb8 ebx=25d89ff0 ecx=24a2ffd8 edx=24a86f74 esi=0012d8e0 edi=24a86f6c eip=605aca06 esp=0012d8bc ebp=0012d920 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 AcroRd32_60000000!AX_PDXlateToHostEx+0x214131: 605aca06 57 push edi 1:009> t eax=24a86eb8 ebx=25d89ff0 ecx=24a2ffd8 edx=24a86f74 esi=0012d8e0 edi=24a86f6c eip=605aca07 esp=0012d8b8 ebp=0012d920 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 AcroRd32_60000000!AX_PDXlateToHostEx+0x214132: 605aca07 ff32 push dword ptr [edx] ds:0023:24a86f74=81818180 1:009> t eax=24a86eb8 ebx=25d89ff0 ecx=24a2ffd8 edx=24a86f74 esi=0012d8e0 edi=24a86f6c eip=605aca09 esp=0012d8b4 ebp=0012d920 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 AcroRd32_60000000!AX_PDXlateToHostEx+0x214134: 605aca09 8b01 mov eax,dword ptr [ecx] ds:0023:24a2ffd8=60e33a70 1:009> t eax=60e33a70 ebx=25d89ff0 ecx=24a2ffd8 edx=24a86f74 esi=0012d8e0 edi=24a86f6c eip=605aca0b esp=0012d8b4 ebp=0012d920 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 AcroRd32_60000000!AX_PDXlateToHostEx+0x214136: 605aca0b ff37 push dword ptr [edi] ds:0023:24a86f6c=c0c0c0c0 1:009> t eax=60e33a70 ebx=25d89ff0 ecx=24a2ffd8 edx=24a86f74 esi=0012d8e0 edi=24a86f6c eip=605aca0d esp=0012d8b0 ebp=0012d920 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 AcroRd32_60000000!AX_PDXlateToHostEx+0x214138: 605aca0d ff5004 call dword ptr [eax+4] ds:0023:60e33a74=60207647 ``` The value from `edx` is a result of previous arithmetic operations on an uninitialized memory and after further arithmetic gets its final value as `esi` at the time of the crashing `memcpy` call. If we examine the allocation from which the uninitialized variable use stems from we can see that it was allocated with a call to `malloc`: ``` 1:009> !heap -p -a 24a86eb8 address 24a86eb8 found in _DPH_HEAP_ROOT @ 1b61000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 248936b4: 24a86eb8 148 - 24a86000 2000 ? AcroRd32_60000000!CTJPEGThrowException+249d88 11248e89 verifier!AVrfDebugPageHeapAllocate+0x00000229 77f8628e ntdll!RtlDebugAllocateHeap+0x00000030 77f4a6cb ntdll!RtlpAllocateHeap+0x000000c4 77f15d20 ntdll!RtlAllocateHeap+0x0000023a 043bed43 MSVCR120!malloc+0x00000049 [f:\dd\vctools\crt\crtw32\heap\malloc.c @ 92] 601eee39 AcroRd32_60000000!CTJPEGWriter::CTJPEGWriter+0x001412c8 601ee3c2 AcroRd32_60000000!CTJPEGWriter::CTJPEGWriter+0x00140851 601ee2ab AcroRd32_60000000!CTJPEGWriter::CTJPEGWriter+0x0014073a 601ed1df AcroRd32_60000000!CTJPEGWriter::CTJPEGWriter+0x0013f66e 601ea98a AcroRd32_60000000!CTJPEGWriter::CTJPEGWriter+0x0013ce19 ``` A possible solution for this issue could be to change the call to `calloc` instead. When Page Heap is disabled, we can observe that the same memory area contains zeros which leads to different results of arithmetic operations (all being zeros) which wouldn’t cause a crash. As has been seen with previous Reader exploits, the heap can be groomed in a specific way so that the uninitialized memory falls under attackers control which could then end up controlling the heap buffer overflow size directly. With further heap layout control this can lead to successful exploitation and remote code execution. ### Timeline * 2016-12-14 - Vendor Disclosure * 2017-01-20 - Public Release ### CREDIT * Discovered by Aleksandar Nikolic of Cisco Talos.
idSSV:96584
last seen2017-11-19
modified2017-09-26
published2017-09-26
reporterRoot
titleAdobe Acrobat Reader DC jpeg decoder Remote Code Execution Vulnerability(CVE-2017-2971)

Talos

idTALOS-2016-0259
last seen2019-05-29
published2017-01-20
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2016-0259
titleAdobe Acrobat Reader DC jpeg decoder Remote Code Execution Vulnerability