Vulnerabilities > CVE-2018-3855 - Double Free vulnerability in Hyland Perceptive Document Filters 11.2.0.1732/11.4.0.2647

047910
CVSS 7.8 - HIGH
Attack vector
LOCAL
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
HIGH
Integrity impact
HIGH
Availability impact
HIGH
local
low complexity
hyland
CWE-415

Summary

In Hyland Perceptive Document Filters 11.4.0.2647 - x86/x64 Windows/Linux, a crafted OpenDocument document can lead to a SkCanvas object double free resulting in direct code execution.

Vulnerable Configurations

Part Description Count
Application
Hyland
2

Common Weakness Enumeration (CWE)

Seebug

bulletinFamilyexploit
description### Summary An exploitable stack-based buffer overflow exists in the DOC-to-HTML conversion functionality of the Hyland Perceptive Document Filters version 11.4.0.2647. A crafted .doc document can lead to a stack-based buffer, resulting in direct code execution. ### Tested Versions Perceptive Document Filters 11.4.0.2647 - x86/x64 Windows/Linux Perceptive Document Filters 11.2.0.1732 - x86/x64 Windows/Linux ### Product URLs https://www.hyland.com/en/perceptive#docfilters ### 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-121: Stack-based Buffer Overflow ### Details This vulnerability is present in the Hyland Document filter conversion, which is used for big data, eDiscovery, DLP, email archival, content management, business intelligence and intelligent capture services. It can convert common formats, such as Microsoft's document formats into more usable and easily viewed formats. There is a vulnerability in the conversion process of a .doc document to HTML. A specially crafted .doc file can lead to a stack-based buffer overflow and remote code execution. Let’s investigate this vulnerability. After we attempt to convert a malicious DOC using the Hyland library, we see the following state: ``` icewall@ubuntu:$ ./isys_doc2text --html -o /tmp/a ./storage/2fa87ae8d1beba2b25940dca4088afde^C isys_doc2text 11.2.0.1732 Copyright (c) 1988-2015 Perceptive Software [00000000] File type: Text (UTF8) (74); Capabilities: 0001 - /tmp/a <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> </head> <body> <p>[1] File type: Microsoft Word (25); Capabilities: 15 - ./storage/2fa87ae8d1beba2b25940dca4088afde <br /> </p> </body> </html>[00000000] Returned 201 characters [00000000] File type: Microsoft Word (25); Capabilities: 000f - ./storage/2fa87ae8d1beba2b25940dca4088afde Program received signal SIGSEGV, Segmentation fault. 0xf5603824 in intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*) () from ./libISYSreadershd.so (rr) bt 10 #0 0xf5603824 in intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*) () from ./libISYSreadershd.so #1 0xffffffff in ?? () #2 0xffffffff in ?? () #3 0xffffffff in ?? () #4 0xffffffff in ?? () #5 0xffffffff in ?? () #6 0xffffffff in ?? () #7 0xffffffff in ?? () #8 0xffffffff in ?? () #9 0xffffffff in ?? () (More stack frames follow...) gdb-peda$ context [----------------------------------registers-----------------------------------] EAX: 0xffffffff EBX: 0xf5a86aec --> 0x99e30c ECX: 0xffffff01 EDX: 0xffffff01 ESI: 0x83 EDI: 0xff8f4790 --> 0xffffffff EBP: 0xff8f45c8 --> 0xffffffff ESP: 0xff8f45c0 --> 0xffffffff EIP: 0xf5603824 (:Office::IOfficeShape::updateNumbering(long*, long*, int*)+68>: 0x5f5e0889) EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0xf560381c <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+60>: jl 0xf5603810 <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+48> 0xf560381e <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+62>: inc DWORD PTR [edi+ecx*4] 0xf5603821 <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+65>: mov eax,DWORD PTR [ebp+0xc] => 0xf5603824 <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+68>: mov DWORD PTR [eax],ecx 0xf5603826 <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+70>: pop esi 0xf5603827 <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+71>: pop edi 0xf5603828 <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+72>: pop ebp 0xf5603829 <intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*)+73>: ret [------------------------------------stack-------------------------------------] 0000| 0xff8f45c0 --> 0xffffffff 0004| 0xff8f45c4 --> 0xffffffff 0008| 0xff8f45c8 --> 0xffffffff 0012| 0xff8f45cc --> 0xffffffff 0016| 0xff8f45d0 --> 0xffffffff 0020| 0xff8f45d4 --> 0xffffffff 0024| 0xff8f45d8 --> 0xffffffff 0028| 0xff8f45dc --> 0xffffffff [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV ``` As we can see, stack data has been completely overwritten by value 0xFFFFFFFF inside the intermediate::Office::IOfficeShape::updateNumbering function. Showing this function in pseudo-code, it looks like this: ``` Line 1 _DWORD __cdecl intermediate::Office::IOfficeShape::updateNumbering(intermediate::Office::IOfficeShape *this, int *maxIndex, int *minIndex, int *array) Line 2 { Line 3 int _minIndexValue; // ecx Line 4 int _maxnIndexValue; // edx Line 5 int *v6; // eax Line 6 int result; // eax Line 7 int *v8; // eax Line 8 int v9; // edx Line 9 Line 10 _minIndexValue = *minIndex; Line 11 if ( *minIndex <= 10 ) Line 12 { Line 13 if ( _minIndexValue == -1 ) Line 14 { Line 15 _minIndexValue = 0; Line 16 *minIndex = 0; Line 17 } Line 18 } Line 19 else Line 20 { Line 21 _minIndexValue = 10; Line 22 *minIndex = 10; Line 23 } Line 24 _maxnIndexValue = *maxIndex; Line 25 if ( _minIndexValue < *maxIndex ) Line 26 { Line 27 if ( _maxnIndexValue != -1 ) Line 28 { Line 29 v6 = &array[_maxnIndexValue]; Line 30 do Line 31 { Line 32 *v6 = -1; Line 33 --_maxnIndexValue; Line 34 --v6; Line 35 } Line 36 while ( _minIndexValue < _maxnIndexValue ); Line 37 } Line 38 goto LABEL_7; Line 39 } Line 40 Line 41 (...) ``` The values of significant arguments are equal: ``` int minIndex = 0xffffff01 (-255) int maxIndex = 0x0 ``` With the arguments having the above mentioned values, we pass both checks at lines 25 and 27 and later assign a pointer to the first element of the array table to the v6 variable. Inside the loop at lines 30-36 just after the first iteration, the v6 pointer will be set to an address before the beginning of array, causing an out-of-bounds write at line 32, and will result in corruption of stack values. The loop for the following parameters will be executed 255 times. The vulnerability exists because the check at line 13 is not sufficient, and does not consider values under zero other than -1. The vulnerability would not occur if the check at line 24 would be done for unsigned integers. Tracking where the value of minIndex was set we land in the following place : ``` const intermediate::common::ITextStyle *__cdecl intermediate::odf::TextParagraphProperties::TextParagraphProperties (...) mov DWORD PTR [eax+0x64],0xffffff01 ``` So -255 value of minIndex (according of some getter function name it is exactly NumberingLevel) is a default value set inside the "Text Paragraph Properties" constructor. Further investigation showed that this default value is only overwritten if a particular paragraph has corresponding PAPX (Paragraph Property Exceptions) record, which contains sprm (Property Modifier) having a value of 0x260a. That sprm according to the MS-DOC format specification is sprmPIlvl. Also, looking at the call stack before the corruption: ``` gdb-peda$ bt #0 0xf56037e5 in intermediate::Office::IOfficeShape::updateNumbering(long*, long*, int*) () from ./libISYSreadershd.so #1 0xf5633bbe in intermediate::Office::Shape2003::addTextContentUnit(intermediate::Office::IOfficeTextItem*, intermediate::common::ITextContentUnit*, intermediate::common::ITextNumberingTable*, long*, int*) () from ./libISYSreadershd.so #2 0xf566ab76 in intermediate::odf::TextDocumentContent::createParagraph(std::vector<intermediate::common::ITextContentUnit*, std::allocator<intermediate::common::ITextContentUnit*> >&, int, int, bool, int, bool) () from ./libISYSreadershd.so #3 0xf566ba72 in intermediate::odf::TextDocumentContent::createParagraph(std::vector<intermediate::common::ITextContentUnit*, std::allocator<intermediate::common::ITextContentUnit*> >&, int, int, bool) () from ./libISYSreadershd.so #4 0xf566e1ed in intermediate::odf::TextDocumentContent::TextDocumentContent(reader::word97_2003::Document const&, intermediate::odf::TextDocumentPackages*, intermediate::odf::TextNumberingTable*) () from ./libISYSreadershd.so #5 0xf568b49d in intermediate::odf::TextDocumentPackagesImpl::Init(reader::word97_2003::Document const&, intermediate::odf::TextDocumentPackages*) () from ./libISYSreadershd.so #6 0xf568c047 in intermediate::odf::TextDocumentPackages::TextDocumentPackages(std::auto_ptr<reader::word97_2003::Document>) () from ./libISYSreadershd.so #7 0xf575cdf4 in ISYS_NS::LibraryHD::CDocument::openWord(IStorage*) () from ./libISYSreadershd.so #8 0xf575dfea in ISYS_NS::LibraryHD::CDocument::open(IGR_Stream*, int, wchar_t const*) () from ./libISYSreadershd.so #9 0xf57594d9 in ISYS_NS::LibraryHD::IGR_HDAPI_Open(IGR_Stream*, int, wchar_t const*, void**, wchar_t*) () from ./libISYSreadershd.so #10 0xf623f6d1 in ISYS_NS::exports::IGR_Open_File_FromStream(wchar_t const*, wchar_t const*, ISYS_NS::CStream*, bool, ISYS_NS::exports::Ext_Open_Options*, int, wchar_t const*, int*, int*, void**, int*, int, Error_Control_Block*) () from ./libISYSreaders.so #11 0xf624513c in ISYS_NS::exports::IGR_Open_Stream_Ex(IGR_Stream*, int, unsigned short const*, int*, int*, void**, Error_Control_Block*) () from ./libISYSreaders.so #12 0xf5f4b673 in IGR_Open_Stream_Ex () from ./libISYS11df.so #13 0x08050654 in processStream(std::string const&, tagTIGR_Stream*, bool, int, int, bool, std::ostream&, int, double) () #14 0x08054574 in processFile(std::string const&, int, int, bool, std::ostream&) () #15 0x080581f9 in main () #16 0xf5bbe637 in __libc_start_main (main=0x8057b90 <main>, argc=0x5, argv=0xff8fbc34, init=0x8069890 <__libc_csu_init>, fini=0x8069880 <__libc_csu_fini>, rtld_fini=0xf7fd2880 <_dl_fini>, stack_end=0xff8fbc2c) at ../csu/libc-start.c:291 #17 0x0804d6e1 in _start () ``` We can deduce that the paragraph is inside a shape object, and that is one of the crucial requirements to trigger the vulnerability. An attacker who provides a malicious .doc document for conversion to HTML could trigger this vulnerability, and potentially gain code execution on the system. ### Crash Information ``` Starting program: /home/icewall/bugs/Perceptive_11.4.2647/bin/linux/intel-32/isys_doc2text --html -o /tmp/a ./storage/2fa87ae8d1beba2b25940dca4088afde [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [1] File type: Microsoft Word (25); Capabilities: 15 - ./storage/2fa87ae8d1beba2b25940dca4088afde Program received signal SIGSEGV, Segmentation fault. 0xf516d174 in ?? () from ./libISYSreadershd.so (gdb) bt 10 #0 0xf516d174 in ?? () from ./libISYSreadershd.so #1 0xffffffff in ?? () #2 0xffffffff in ?? () #3 0xffffffff in ?? () #4 0xffffffff in ?? () #5 0xffffffff in ?? () #6 0xffffffff in ?? () #7 0xffffffff in ?? () #8 0xffffffff in ?? () #9 0xffffffff in ?? () (More stack frames follow...) gdb-peda$ context [----------------------------------registers-----------------------------------] EAX: 0xffffffff EBX: 0xf56b4f0c --> 0xa42fcc ECX: 0xffffff01 EDX: 0xffffff01 ESI: 0xa3 EDI: 0xffffade0 --> 0xffffffff EBP: 0xffffaa98 --> 0xffffffff ESP: 0xffffaa90 --> 0xffffffff EIP: 0xf516d174 (mov DWORD PTR [eax],ecx) EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0xf516d16c: jl 0xf516d160 0xf516d16e: inc DWORD PTR [edi+ecx*4] 0xf516d171: mov eax,DWORD PTR [ebp+0xc] => 0xf516d174: mov DWORD PTR [eax],ecx 0xf516d176: pop esi 0xf516d177: pop edi 0xf516d178: pop ebp 0xf516d179: ret [------------------------------------stack-------------------------------------] 0000| 0xffffaa90 --> 0xffffffff 0004| 0xffffaa94 --> 0xffffffff 0008| 0xffffaa98 --> 0xffffffff 0012| 0xffffaa9c --> 0xffffffff 0016| 0xffffaaa0 --> 0xffffffff 0020| 0xffffaaa4 --> 0xffffffff 0024| 0xffffaaa8 --> 0xffffffff 0028| 0xffffaaac --> 0xffffffff [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV ``` ### Timeline * 2018-03-16 - Vendor Disclosure * 2018-03-22 - Vendor patched * 2018-04-26 - Public Release
idSSV:97299
last seen2018-06-08
modified2018-05-17
published2018-05-17
reporterKnownsec
titleHyland Perceptive Document Filters DOC to HTML updateNumbering Code Execution Vulnerability(CVE-2018-3855)

Talos

idTALOS-2018-0538
last seen2019-05-29
published2018-04-26
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2018-0538
titleHyland Perceptive Document Filters DOC to HTML updateNumbering Code Execution Vulnerability