Talos Vulnerability Report

TALOS-2017-0302

Lexmark Perceptive Document Filters XLS ShapeHLink Information Disclosure Vulnerability

April 18, 2017
CVE Number

CVE-2017-2806

Summary

An exploitable arbitrary read exists in the XLS parsing of the Lexmark Perspective Document Filters conversion functionality. A crafted XLS document can lead to a arbitrary read resulting in memory disclosure. The vulnerability was confirmed on versions 11.3.0.2228 and 11.3.0.2400

Tested Versions

Lexmark Perceptive Document Filters 11.3.0.2228 Lexmark Perceptive Document Filters 11.3.0.2400

Product URLs

http://www.lexmark.com/en_us/partners/enterprise-software/technology-partners/oem-technologies/document-filters.html

CVSSv3 Score

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

CWE

CWE-125 - Out-of-bounds Read

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 services. This product is mainly used by MarkLogic for document conversions as part of their web based document search and rendering. It can convert common formats such as Microsoft’s document formats into more useable and easily viewed formats. There is a vulnerability in the parsing and conversion of XLS documents. A specially crafted XLS file can lead to an arbitrary read and ultimately memory disclosure.

Let’s investigate this vulnerability. After the Lexmark library attempts to read metadata from the malicious file, we see the following state:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff3818fdb in intermediate::Office::extract4BytesFromStringIt(char const**) () from ./libISYSreadershd.so
(gdb) peda_active 
gdb-peda$ context
[----------------------------------registers-----------------------------------]
RAX: 0x3133701 
RBX: 0x6ac3d0 --> 0x7ffff3f21210 --> 0x7ffff385c3f0 (<intermediate::Office::ShapeHLink::~ShapeHLink()>:	mov    QWORD PTR [rsp-0x8],rbp)
RCX: 0x3133700 
RDX: 0x3133702 
RSI: 0xa80000 
RDI: 0x7ffffffecfd8 --> 0x3133700 
RBP: 0x6ac458 --> 0xaaefbeadde000002 
RSP: 0x7ffffffecfa8 --> 0x7ffff38310df (cdqe)
RIP: 0x7ffff3818fdb (movzx  r8d,BYTE PTR [rcx])
R8 : 0x9c 
R9 : 0x7ffff69417b8 --> 0x6b7b80 --> 0x0 
R10: 0x6c00000067 ('g')
R11: 0x7ffff670a550 --> 0xfffcb240fffcabbe 
R12: 0xffad 
R13: 0x696fc0 --> 0x7ffff3f0b4f0 --> 0x7ffff35fb9c0 (<reader::excel97_2003::Sheet::~Sheet()>:	mov    QWORD PTR [rsp-0x10],rbp)
R14: 0x6ac3d0 --> 0x7ffff3f21210 --> 0x7ffff385c3f0 (<intermediate::Office::ShapeHLink::~ShapeHLink()>:	mov    QWORD PTR [rsp-0x8],rbp)
R15: 0x7ffff79c23f8 --> 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff3818fd0 <intermediate::Office::extract4BytesFromStringIt(char const**)>:	mov    rcx,QWORD PTR [rdi]
   0x7ffff3818fd3:	lea    rax,[rcx+0x1]
   0x7ffff3818fd7:	lea    rdx,[rcx+0x2]
=> 0x7ffff3818fdb:	movzx  r8d,BYTE PTR [rcx]
   0x7ffff3818fdf:	mov    QWORD PTR [rdi],rax
   0x7ffff3818fe2:	movzx  eax,BYTE PTR [rcx+0x1]
   0x7ffff3818fe6:	mov    QWORD PTR [rdi],rdx
   0x7ffff3818fe9:	lea    rdx,[rcx+0x3]
[------------------------------------stack-------------------------------------]
0000| 0x7ffffffecfa8 --> 0x7ffff38310df (cdqe)
0008| 0x7ffffffecfb0 --> 0x7ffffffecff0 --> 0x6a9e00 --> 0x7ffff3f09010 --> 0x7ffff352edf0 (<common::IRenderable::SetZIndex(int)>:	mov    DWORD PTR [rdi+0x8],esi)
0016| 0x7ffffffecfb8 --> 0x20 (' ')
0024| 0x7ffffffecfc0 --> 0x20 (' ')
0032| 0x7ffffffecfc8 --> 0x6ac3e8 --> 0x7ffff79c23f8 --> 0x0 
0040| 0x7ffffffecfd0 --> 0x696fc0 --> 0x7ffff3f0b4f0 --> 0x7ffff35fb9c0 (<reader::excel97_2003::Sheet::~Sheet()>:	mov    QWORD PTR [rsp-0x10],rbp)
0048| 0x7ffffffecfd8 --> 0x3133700 
0056| 0x7ffffffecfe0 --> 0x6a9e00 --> 0x7ffff3f09010 --> 0x7ffff352edf0 (<common::IRenderable::SetZIndex(int)>:	mov    DWORD PTR [rdi+0x8],esi)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ bt
#0  0x00007ffff3818fdb in intermediate::Office::extract4BytesFromStringIt(char const**) () from ./libISYSreadershd.so
#1  0x00007ffff38310df in intermediate::Office::ShapeHLink::ShapeHLink(std::string const&) () from ./libISYSreadershd.so
#2  0x00007ffff35f0497 in reader::excel97_2003::Sheet::parseImageObject(intermediate::common::ExcelDrawing*, reader::escher::MsofbtSpContainer*) () from ./libISYSreadershd.so
#3  0x00007ffff35f1224 in reader::excel97_2003::Sheet::parseDrawingObjects(intermediate::common::ExcelDrawing*, reader::escher::MsofbtSpContainer*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>) () from ./libISYSreadershd.so
#4  0x00007ffff35f141e in reader::excel97_2003::Sheet::parseObject(intermediate::common::ExcelDrawing*, reader::escher::IMsoObject*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>) () from ./libISYSreadershd.so
#5  0x00007ffff35f2c7c in reader::excel97_2003::Sheet::Commit(ISYS_NS::CDataReader&) () from ./libISYSreadershd.so
#6  0x00007ffff357ff52 in reader::excel97_2003::Workbook::Workbook(ISYS_NS::CStream*, IStorage*, wchar_t const*, bool) () from ./libISYSreadershd.so
#7  0x00007ffff399adca in ISYS_NS::LibraryHD::CDocument::openExcel(ISYS_NS::CStream*, IStorage*, bool) () from ./libISYSreadershd.so
#8  0x00007ffff399c2cf in ISYS_NS::LibraryHD::CDocument::open(IGR_Stream*, int, wchar_t const*) () from ./libISYSreadershd.so
#9  0x00007ffff3994d4a in ISYS_NS::LibraryHD::IGR_HDAPI_Open(IGR_Stream*, int, wchar_t const*, void**, wchar_t*) () from ./libISYSreadershd.so
#10 0x00007ffff61a22cb in ?? () from ./libISYSreaders.so
#11 0x00007ffff61a6307 in ?? () from ./libISYSreaders.so
#12 0x00007ffff7bcdb1b in IGR_Open_Stream_Ex () from ./libISYS11df.so
#13 0x00000000004091e0 in processStream(IGR_Stream*, long long&, ToXHTML&, std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >&) ()
#14 0x000000000040ab7b in processFile(std::string, std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >&) ()
#15 0x000000000040b7a0 in main ()
#16 0x00007ffff65a4f45 in __libc_start_main (main=0x40b0b0 <main>, argc=0x2, argv=0x7fffffffdf58, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf48)
	at libc-start.c:287
#17 0x00000000004089e9 in _start ()

As we can see in the function extract4BytesFromStringIt an access violation occurred during a read from a very specific address rcx == 0x3133700. The address from where these 4 bytes are extracted are fully controlled by attacker. Let’s look at where this value comes from. We return to the place where rcx was set:

gdb-peda$ 
[----------------------------------registers-----------------------------------]
RAX: 0x2a8729c 
RBX: 0x6ac3d0 --> 0x7ffff3f21210 --> 0x7ffff385c3f0 (<intermediate::Office::ShapeHLink::~ShapeHLink()>:	mov    QWORD PTR [rsp-0x8],rbp)
RCX: 0x6ac464 --> 0xd3d3d3d3d3d3d3d3 
RDX: 0x2000000 
RSI: 0xa80000 
RDI: 0x7ffffffecfd8 --> 0x6ac464 --> 0xd3d3d3d3d3d3d3d3 
RBP: 0x6ac458 --> 0xaaefbeadde000002 
RSP: 0x7ffffffecfb0 --> 0x7ffffffecff0 --> 0x6a9e00 --> 0x7ffff3f09010 --> 0x7ffff352edf0 (<common::IRenderable::SetZIndex(int)>:	mov    DWORD PTR [rdi+0x8],esi)
RIP: 0x7ffff383125f (add    QWORD PTR [rsp+0x28],rax)
R8 : 0x9c 
R9 : 0x7ffff69417b8 --> 0x6b7b80 --> 0x0 
R10: 0x6c00000067 ('g')
R11: 0x7ffff670a550 --> 0xfffcb240fffcabbe 
R12: 0xffad 
R13: 0x696fc0 --> 0x7ffff3f0b4f0 --> 0x7ffff35fb9c0 (<reader::excel97_2003::Sheet::~Sheet()>:	mov    QWORD PTR [rsp-0x10],rbp)
R14: 0x6ac3d0 --> 0x7ffff3f21210 --> 0x7ffff385c3f0 (<intermediate::Office::ShapeHLink::~ShapeHLink()>:	mov    QWORD PTR [rsp-0x8],rbp)
R15: 0x7ffff79c23f8 --> 0x0
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff3831253:	lea    rdi,[rsp+0x28]
   0x7ffff3831258:	call   0x7ffff34f2178 <intermediate::Office::extract4BytesFromStringIt(char const**)@plt>
   0x7ffff383125d:	cdqe   
=> 0x7ffff383125f:	add    QWORD PTR [rsp+0x28],rax
   0x7ffff3831264:	jmp    0x7ffff38310c6
   0x7ffff3831269:	lea    rdi,[rsp+0x28]
   0x7ffff383126e:	call   0x7ffff34f2178 <intermediate::Office::extract4BytesFromStringIt(char const**)@plt>
   0x7ffff3831273:	mov    rbx,QWORD PTR [rsp+0x28]
gdb-peda$ telescope $rsp+0x28 1
0000| 0x7ffffffecfd8 --> 0x6ac464 --> 0xd3d3d3d3d3d3d3d3 
gdb-peda$ ni
gdb-peda$ telescope $rsp+0x28 1
0000| 0x7ffffffecfd8 --> 0x3133700 

looking in the file for value the 0x2a8729c we can find it at offset 0x6D82. It points to data inside the complexData field of the OfficeArtRGFOPTE record type (described in section 2.3.1 of the Office Drawing Binary File Format. Looking at the constructor name we can easily guess that the object which the currently library was parsing is related with a hyperlink. Indeed, it is wrongly parsing the Hyperlink Object structure (defined in section 2.3.7.1 of the Office Common Data Types and Objects Structures: The Hyperlink object has, among others, 2 string fields, dispalyName and targetFrameName. Both fields have variable lengths. The Perceptive Filter library reads the read string length from the file without extra checks and adds it to displayName pointer to find the location of targetFrameName. This lack of value sanitization leads to an arbitrary memory read and can result in memory disclosure.

Crash Information

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x3133701 
RBX: 0x6ac3d0 --> 0x7ffff3f21210 --> 0x7ffff385c3f0 (<intermediate::Office::ShapeHLink::~ShapeHLink()>:	mov    QWORD PTR [rsp-0x8],rbp)
RCX: 0x3133700 
RDX: 0x3133702 
RSI: 0xa80000 
RDI: 0x7ffffffecfd8 --> 0x3133700 
RBP: 0x6ac458 --> 0xaaefbeadde000002 
RSP: 0x7ffffffecfa8 --> 0x7ffff38310df (cdqe)
RIP: 0x7ffff3818fdb (movzx  r8d,BYTE PTR [rcx])
R8 : 0x9c 
R9 : 0x7ffff69417b8 --> 0x6b7b80 --> 0x0 
R10: 0x6c00000067 ('g')
R11: 0x7ffff670a550 --> 0xfffcb240fffcabbe 
R12: 0xffad 
R13: 0x696fc0 --> 0x7ffff3f0b4f0 --> 0x7ffff35fb9c0 (<reader::excel97_2003::Sheet::~Sheet()>:	mov    QWORD PTR [rsp-0x10],rbp)
R14: 0x6ac3d0 --> 0x7ffff3f21210 --> 0x7ffff385c3f0 (<intermediate::Office::ShapeHLink::~ShapeHLink()>:	mov    QWORD PTR [rsp-0x8],rbp)
R15: 0x7ffff79c23f8 --> 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff3818fd0 <intermediate::Office::extract4BytesFromStringIt(char const**)>:	mov    rcx,QWORD PTR [rdi]
   0x7ffff3818fd3:	lea    rax,[rcx+0x1]
   0x7ffff3818fd7:	lea    rdx,[rcx+0x2]
=> 0x7ffff3818fdb:	movzx  r8d,BYTE PTR [rcx]
   0x7ffff3818fdf:	mov    QWORD PTR [rdi],rax
   0x7ffff3818fe2:	movzx  eax,BYTE PTR [rcx+0x1]
   0x7ffff3818fe6:	mov    QWORD PTR [rdi],rdx
   0x7ffff3818fe9:	lea    rdx,[rcx+0x3]
[------------------------------------stack-------------------------------------]
0000| 0x7ffffffecfa8 --> 0x7ffff38310df (cdqe)
0008| 0x7ffffffecfb0 --> 0x7ffffffecff0 --> 0x6a9e00 --> 0x7ffff3f09010 --> 0x7ffff352edf0 (<common::IRenderable::SetZIndex(int)>:	mov    DWORD PTR [rdi+0x8],esi)
0016| 0x7ffffffecfb8 --> 0x20 (' ')
0024| 0x7ffffffecfc0 --> 0x20 (' ')
0032| 0x7ffffffecfc8 --> 0x6ac3e8 --> 0x7ffff79c23f8 --> 0x0 
0040| 0x7ffffffecfd0 --> 0x696fc0 --> 0x7ffff3f0b4f0 --> 0x7ffff35fb9c0 (<reader::excel97_2003::Sheet::~Sheet()>:	mov    QWORD PTR [rsp-0x10],rbp)
0048| 0x7ffffffecfd8 --> 0x3133700 
0056| 0x7ffffffecfe0 --> 0x6a9e00 --> 0x7ffff3f09010 --> 0x7ffff352edf0 (<common::IRenderable::SetZIndex(int)>:	mov    DWORD PTR [rdi+0x8],esi)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00007ffff3818fdb in intermediate::Office::extract4BytesFromStringIt(char const**) () from ./libISYSreadershd.so
gdb-peda$ exploitable -m
Warning: machine string printing is deprecated and may be removed in a future release.
EXCEPTION_FAULTING_ADDRESS:0x00000003133700
EXCEPTION_CODE:0xb
FAULTING_INSTRUCTION:movzx  r8d,BYTE PTR [rcx]
MAJOR_HASH:435211badab532edaeeaf65b62cabc34
MINOR_HASH:dd8a6e134c95f47c9f18aac4b3c591c2
STACK_DEPTH:16
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!intermediate::Office::extract4BytesFromStringIt(char const**)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!intermediate::Office::ShapeHLink::ShapeHLink(std::string const&)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!reader::excel97_2003::Sheet::parseImageObject(intermediate::common::ExcelDrawing*, reader::escher::MsofbtSpContainer*)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!reader::excel97_2003::Sheet::parseDrawingObjects(intermediate::common::ExcelDrawing*, reader::escher::MsofbtSpContainer*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!reader::excel97_2003::Sheet::parseObject(intermediate::common::ExcelDrawing*, reader::escher::IMsoObject*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>*, std::_List_const_iterator<reader::excel97_2003::BiffTxo*>)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!reader::excel97_2003::Sheet::Commit(ISYS_NS::CDataReader&)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!reader::excel97_2003::Workbook::Workbook(ISYS_NS::CStream*, IStorage*, wchar_t const*, bool)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!ISYS_NS::LibraryHD::CDocument::openExcel(ISYS_NS::CStream*, IStorage*, bool)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!ISYS_NS::LibraryHD::CDocument::open(IGR_Stream*, int, wchar_t const*)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreadershd.so!ISYS_NS::LibraryHD::IGR_HDAPI_Open(IGR_Stream*, int, wchar_t const*, void**, wchar_t*)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreaders.so+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYSreaders.so+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/libISYS11df.so!IGR_Open_Stream_Ex+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/convert!processStream(IGR_Stream*, long long&, ToXHTML&, std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >&)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/convert!processFile(std::string, std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >&)+0x0
STACK_FRAME:/home/icewall/bugs/cvtisys_86/convert!main+0x0
INSTRUCTION_ADDRESS:0x007ffff3818fdb
INVOKING_STACK_FRAME:0
DESCRIPTION:Access violation on source operand
SHORT_DESCRIPTION:SourceAv (26/29)
OTHER_RULES:AccessViolation (28/29)
CLASSIFICATION:UNKNOWN
EXPLANATION:The target crashed on an access violation at an address matching the source operand of the current instruction. This likely indicates a read access violation.
Description: Access violation on source operand
Short description: SourceAv (26/29)
Hash: 435211badab532edaeeaf65b62cabc34.dd8a6e134c95f47c9f18aac4b3c591c2
Exploitability Classification: UNKNOWN
Explanation: The target crashed on an access violation at an address matching the source operand of the current instruction. This likely indicates a read access violation.
Other tags: AccessViolation (28/29)

Timeline

2017-04-05 - Vendor Disclosure
2017-04-18 - Public Release

Credit

Discovered by Marcin ‘Icewall’ Noga of Cisco Talos.