Vulnerabilities > CVE-2016-4336 - Out-of-bounds Write vulnerability in Lexmark Perceptive Document Filters

047910
CVSS 9.8 - CRITICAL
Attack vector
NETWORK
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
HIGH
Integrity impact
HIGH
Availability impact
HIGH
network
low complexity
lexmark
CWE-787
critical

Summary

An exploitable out-of-bounds write exists in the Bzip2 parsing of the Lexmark Perspective Document Filters conversion functionality. A crafted Bzip2 document can lead to a stack-based buffer overflow causing an out-of-bounds write which under the right circumstance could potentially be leveraged by an attacker to gain arbitrary code execution.

Vulnerable Configurations

Part Description Count
Application
Lexmark
1

Common Weakness Enumeration (CWE)

Seebug

bulletinFamilyexploit
description### Description An exploitable out of bounds write exists in the Bzip2 parsing of the Perspective Document Filters conversion functionality. A crafted Bzip2 document can lead to a stack based buffer overflow causing an out of bounds write which under the right circumstance could potentially be leveraged by an attacker to gain arbitrary code execution. ### Tested Versions Lexmark Perceptive Document Filters ### Product URLs http://www.lexmark.com/en_us/partners/enterprise-software/technology-partners/oem-technologies/document-filters.html ### CVSSv3 Score 7.3 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L ### Details This vulnerability is present in the Lexmark Document filter parsing which is used for big data, eDiscovery, DLP, email archival, content management, business intelligence and intelligent capture. This product is mainly used by MarkLogic for document conversions in there rendering. It can convert common formats such as Microsoft's document formats into more useable and easily viewed formats. This converter also handles files inside of a compressed format for further use cases. There is a vulnerability in the parsing and conversion of a Bzip2 document. A specially crafted Bzip2 file can lead to an out of bounds write and potentially to remote code execution. The number of bits to be read in from the next sequence of parsing is directly controlled by the user as shown here: ``` compress_object = *(struct_v1 **)(a1 + 80); result = getbits(a1, compress_object->dword4C); v3 = result; ... result = 0LL; compress_object->counter = v3; } return result; ``` Running this with a debugger we can see the value assigned to our counter. ``` RAX: 0x0 RBX: 0x7ffff7f55010 --> 0x7ffff7f95186 --> 0x130883c184b0480c RCX: 0x101 RDX: 0x101 RSI: 0x101 RDI: 0x6617c0 --> 0x0 RBP: 0x7ffff7f55010 --> 0x7ffff7f95186 --> 0x130883c184b0480c RSP: 0x7ffffffedb40 --> 0x7e000000db RIP: 0x7ffff496e0a5 (<next_code+373>: mov DWORD PTR [rbp+0x50],esi) R8 : 0x7ffff7f55010 --> 0x7ffff7f95186 --> 0x130883c184b0480c R9 : 0x0 R10: 0x22 ('"') R11: 0x246 R12: 0x6617c0 --> 0x0 R13: 0x7ffff64f4ca0 --> 0x10100000101 R14: 0x661880 --> 0xff R15: 0x6617c0 --> 0x0 EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x7ffff496e09d <next_code+365>: sub eax,0x1 0x7ffff496e0a0 <next_code+368>: mov DWORD PTR [rbp+0x48],eax 0x7ffff496e0a3 <next_code+371>: xor eax,eax => 0x7ffff496e0a5 <next_code+373>: mov DWORD PTR [rbp+0x50],esi 0x7ffff496e0a8 <next_code+376>: jmp 0x7ffff496dfc9 <next_code+153> 0x7ffff496e0ad <next_code+381>: mov rax,QWORD PTR [rbp+0x30060] 0x7ffff496e0b4 <next_code+388>: mov edx,DWORD PTR [rbp+0x54] 0x7ffff496e0b7 <next_code+391>: mov BYTE PTR [rax],dl ``` Notice the value of ESI, 0x101, being written to RBP (compressed_object) + 0x50 which is the counter variable inside of the object. This becomes important for the next part of the vulnerability. This read in counter value is then used in a loop that is effectively a memset of the compressed objects buffer. This loop writes null bytes into the buffer until the counter is less than 255. The problem arises in that the counter object never changes. The counter relies on multiple fields inside of the compressed object but none of these change the value of the counter causing an infinite loop. ``` while ( v3 > 255 )//v3 = 0x101 { v10 = compress_object->write_value; //NULL *v10 = compress_object->array[v3]; v3 = *(_WORD *)&compress_object->array[2 * v3 + 0x10000]; compress_object->array_index = v10 + 1; } ``` As can be seen below the array access to change v3 always returns the current value of v3 causing this to turn into an infinite loop with the array continually being incremented. ``` [----------------------------------registers-----------------------------------] RAX: 0x7ffff7f8507a --> 0x0 RBX: 0x7ffff7f55010 --> 0x7ffff7f95186 --> 0x130883c184b0480c RCX: 0x101 RDX: 0x0 RSI: 0x101 RDI: 0x6617c0 --> 0x0 RBP: 0x7ffff7f55010 --> 0x7ffff7f95186 --> 0x130883c184b0480c RSP: 0x7ffffffedb40 --> 0x7e000000db RIP: 0x7ffff496e03e (<next_code+270>: mov rax,QWORD PTR [rbp+0x30060]) R8 : 0x7ffff7f55010 --> 0x7ffff7f95186 --> 0x130883c184b0480c R9 : 0x0 R10: 0x22 ('"') R11: 0x246 R12: 0x6617c0 --> 0x0 R13: 0x7ffff64f4ca0 --> 0x10100000101 R14: 0x661880 --> 0xff R15: 0x6617c0 --> 0x0 EFLAGS: 0x293 (CARRY parity ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x7ffff496e02f <next_code+255>: mov QWORD PTR [rbp+0x30060],rax 0x7ffff496e036 <next_code+262>: cmp edx,0xff 0x7ffff496e03c <next_code+268>: jg 0x7ffff496e012 <next_code+226> => 0x7ffff496e03e <next_code+270>: mov rax,QWORD PTR [rbp+0x30060] 0x7ffff496e045 <next_code+277>: mov DWORD PTR [rbp+0x54],edx 0x7ffff496e048 <next_code+280>: mov BYTE PTR [rax],dl 0x7ffff496e04a <next_code+282>: add rax,0x1 0x7ffff496e04e <next_code+286>: mov QWORD PTR [rbp+0x30060],rax ``` First loop through notice RDX = 0 which will be written into the stack buffer. Going a few steps further we can see where RDX gets reassigned. ``` RAX: 0x7ffff7f85079 --> 0x0 RBX: 0x7ffff7f55010 --> 0x7ffff7f95187 --> 0x2a130883c184b048 RCX: 0x101 RDX: 0x101 RSI: 0x102 RDI: 0x6617c0 --> 0x0 RBP: 0x7ffff7f55010 --> 0x7ffff7f95187 --> 0x2a130883c184b048 RSP: 0x7ffffffedb40 --> 0x7e000000db RIP: 0x7ffff496e02b (<next_code+251>: add rax,0x1) R8 : 0x7ffff7f55010 --> 0x7ffff7f95187 --> 0x2a130883c184b048 R9 : 0x0 R10: 0x22 ('"') R11: 0x246 R12: 0x6617c0 --> 0x0 R13: 0x7ffff64f4ca0 --> 0x10100000101 R14: 0x661880 --> 0xff000000ff R15: 0x6617c0 --> 0x0 EFLAGS: 0x212 (carry parity ADJUST zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x7ffff496e01c <next_code+236>: movzx edx,BYTE PTR [rcx+rbp*1+0x5c] 0x7ffff496e021 <next_code+241>: mov BYTE PTR [rax],dl 0x7ffff496e023 <next_code+243>: movzx edx,WORD PTR [rbp+rcx*2+0x1005c] => 0x7ffff496e02b <next_code+251>: add rax,0x1 0x7ffff496e02f <next_code+255>: mov QWORD PTR [rbp+0x30060],rax ``` Directly after RDX gets assigned the value from the compressed objects array, we note that RDX still is equal to 0x101. This is going to cause an issue due to the fact that the stack buffer continuously gets incremented and there is no way for the loop to exit. The array continues to get incremented until it runs into unmapped memory which then throws the out of bounds memory access exception. ``` Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x7ffff7fe0000 RBX: 0x7ffff7f55010 --> 0x7ffff7f95187 --> 0x0 RCX: 0x101 RDX: 0x0 RSI: 0x102 RDI: 0x6617c0 --> 0x0 RBP: 0x7ffff7f55010 --> 0x7ffff7f95187 --> 0x0 RSP: 0x7ffffffedb40 --> 0x7e000000db RIP: 0x7ffff496e021 (<next_code+241>: mov BYTE PTR [rax],dl) R8 : 0x7ffff7f55010 --> 0x7ffff7f95187 --> 0x0 R9 : 0x0 R10: 0x22 ('"') R11: 0x246 R12: 0x6617c0 --> 0x0 R13: 0x7ffff64f4ca0 --> 0x10100000101 R14: 0x661880 --> 0xff000000ff R15: 0x6617c0 --> 0x0 EFLAGS: 0x10212 (carry parity ADJUST zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x7ffff496e012 <next_code+226>: movsxd rcx,edx 0x7ffff496e015 <next_code+229>: mov rax,QWORD PTR [rbp+0x30060] 0x7ffff496e01c <next_code+236>: movzx edx,BYTE PTR [rcx+rbp*1+0x5c] => 0x7ffff496e021 <next_code+241>: mov BYTE PTR [rax],dl 0x7ffff496e023 <next_code+243>: movzx edx,WORD PTR [rbp+rcx*2+0x1005c] 0x7ffff496e02b <next_code+251>: add rax,0x1 0x7ffff496e02f <next_code+255>: mov QWORD PTR [rbp+0x30060],rax 0x7ffff496e036 <next_code+262>: cmp edx,0xff ``` ### Crash Information ``` EXCEPTION_FAULTING_ADDRESS:0x007ffff7fe0000 EXCEPTION_CODE:0xb FAULTING_INSTRUCTION:mov BYTE PTR [rax],dl MAJOR_HASH:b0aaec1471bbd86d7e818f1ebd111c6f MINOR_HASH:b74fe16d6a33042541ff3552757b4e72 STACK_DEPTH:14 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSshared.so!next_code+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSshared.so!compress_filter_read+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSshared.so!__archive_read_filter_ahead+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSshared.so!bzip2_reader_bid+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSshared.so!archive_read_open1+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSreaders.so!ISYS_NS CLibArchiveReader openArchive()+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSreaders.so!ISYS_NS CLibArchiveReader LoadDocument2(ISYS_NS CISYSSource const*, ISYS_NS tag_ReaderContext*)+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSreaders.so!ISYS_NS CISYSReader Prepare(ISYS_NS CStream*, ISYS_NS CISYSSource const*, ISYS_NS tag_ReaderContext*)+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSreaders.so!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*)+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYSreaders.so!ISYS_NS exports IGR_Open_Stream_Ex(IGR_Stream*, int, unsigned short const*, int*, int*, void**, Error_Control_Block*)+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/libISYS11df.so!IGR_Open_Stream_Ex+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/convert!processStream(IGR_Stream*, long long&, ToXHTML&, std basic_ostringstream<char, std char_traits<char>, std allocator<char> >&)+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/convert!processFile(std string, std basic_ostringstream<char, std char_traits<char>, std allocator<char> >&)+0x0 STACK_FRAME:/home/t/Downloads/cvtisys/cvtisys/convert!main+0x0 INSTRUCTION_ADDRESS:0x007ffff496e021 INVOKING_STACK_FRAME:0 DESCRIPTION:Access violation on destination operand SHORT_DESCRIPTION:DestAv (8/22) OTHER_RULES:AccessViolation (21/22) CLASSIFICATION:EXPLOITABLE EXPLANATION:The target crashed on an access violation at an address matching the destination operand of the instruction. This likely indicates a write access violation, which means the attacker may control the write address and/or value. ``` ### Exploit Proof-of-Concept Ensure library path is setup correctly and run the convert application with the trigger passed in as the first argument. ### Timeline * 2016-05-19 - Vendor Disclosure * 2016-08-06 - Public Release
idSSV:96680
last seen2017-11-19
modified2017-10-13
published2017-10-13
reporterRoot
titleLexMark Perceptive Document Filters Bzip2 Convert Out of Bounds Write Vulnerability(CVE-2016-4336)

Talos

idTALOS-2016-0173
last seen2019-05-29
published2016-08-06
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2016-0173
titleLexMark Perceptive Document Filters Bzip2 Convert Out of Bounds Write Vulnerability