Talos Vulnerability Report

TALOS-2017-0300

Apache OpenOffice PPT PPTStyleSheet nLevel Code Execution Vulnerability

October 26, 2017
CVE Number

CVE-2017-12607

Summary

An exploitable out of bound write vulnerability exists in the PPTStyleSheet::PPTStyleSheet functionality of Apache OpenOffice. A specially crafted PPT file can cause an out of bound write resulting in arbitrary code execution. An attacker can send/provide a malicious PPT file to trigger this vulnerability.

Tested Versions

Apache OpenOffice 4.1.3 x64 Apache OpenOffice 4.1.3 x86

Product URLs

http://www.openoffice.org/

CVSSv3 Score

8.3 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H

Details

This vulnerability is present in the Apache OpenOffice (formerly OpenOffice.org) a free open source office suite.
A specially crafted PPT file can lead to an out of bound write and ultimately to remote code execution.

Let's investigate this vulnerability. After opening Impress with the malformed PPT file we see following state:

gdb-peda$ context
[----------------------------------registers-----------------------------------]
RAX: 0xb70 ('p\x0b')
RBX: 0x28a 
RCX: 0x7fffc2ef0fdc --> 0x800000000010000 
RDX: 0x7fffc2a4fd88 --> 0x64000020220000 ('')
RSI: 0x7fffc2a45170 --> 0x0 
RDI: 0x7fffc2ef0ff0 --> 0x800000000010000 
RBP: 0x28a 
RSP: 0x7fffffffa7b0 --> 0x1 
RIP: 0x7fffc2571dfc (mov    WORD PTR [rdi+0x10],ax)
R8 : 0x5140 ('@Q')
R9 : 0x0 
R10: 0x7fffc2a4f9c8 --> 0x7ffff09eca80 --> 0x7ffff07bfa64 (<_ZN16SotStorageStream7GetDataEPvm>: push   rbp)
R11: 0xc8 
R12: 0x0 
R13: 0x28a 
R14: 0x7fffc2a3f148 --> 0x7fffc2a77848 --> 0x7fffc2a413e8 --> 0x7b ('{')
R15: 0x7fffc2a4f9c8 --> 0x7ffff09eca80 --> 0x7ffff07bfa64 (<_ZN16SotStorageStream7GetDataEPvm>: push   rbp)
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7fffc2571df0:  mov    rax,QWORD PTR [rcx+0x8]
   0x7fffc2571df4:  mov    QWORD PTR [rdi+0x8],rax
   0x7fffc2571df8:  movzx  eax,WORD PTR [rcx+0x10]
=> 0x7fffc2571dfc:  mov    WORD PTR [rdi+0x10],ax
   0x7fffc2571e00:  mov    rax,QWORD PTR [rsp+0x28]
   0x7fffc2571e05:  movzx  r12d,r9b
   0x7fffc2571e09:  mov    r8d,ebx
   0x7fffc2571e0c:  mov    r9d,r12d
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffa7b0 --> 0x1 
0008| 0x7fffffffa7b8 --> 0x966f08 --> 0x7ffff7ffe480 --> 0x6db1b0 --> 0x7ffff7ffe1c8 --> 0x0 
0016| 0x7fffffffa7c0 --> 0x7fffffffb160 --> 0x1 
0024| 0x7fffffffa7c8 --> 0x7ffff7ed8808 --> 0x7fffc27ab310 --> 0x7fffc25730b0     
(<_ZNK19SdrPowerPointImport9ImportOLEElRK7GraphicRK9RectangleS5_il>:    push   r15)
0032| 0x7fffffffa7d0 --> 0x7fffffffb0b0 --> 0xfc9000f0000b10f 
0040| 0x7fffffffa7d8 --> 0x7fffc2a45170 --> 0x0 
0048| 0x7fffffffa7e0 --> 0x7ffff7ed9000 --> 0x10000000b 
0056| 0x7fffffffa7e8 --> 0x3e8a00000000 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ bt
#0  0x00007fffc2571dfc in ?? () from /opt/openoffice4/program/libmsfilter.so
#1  0x00007fffc2577c4d in SdrPowerPointImport::SdrPowerPointImport(PowerPointImportParam&, String const&) () from /opt/   
openoffice4/program/
libmsfilter.so
#2  0x00007fffc27c702e in ?? () from /opt/openoffice4/program/libsdfilt.so
#3  0x00007fffc27c74e9 in ?? () from /opt/openoffice4/program/libsdfilt.so
#4  0x00007fffc27ceafb in ImportPPT () from /opt/openoffice4/program/libsdfilt.so
#5  0x00007fffc326c4c8 in ?? () from /opt/openoffice4/program/../program/libsd.so
#6  0x00007fffc318884d in sd::DrawDocShell::ConvertFrom(SfxMedium&) () from /opt/openoffice4/program/../program/libsd.so
#7  0x00007ffff4ccc02f in SfxObjectShell::DoLoad(SfxMedium*) () from /opt/openoffice4/program/libsfx.so
#8  0x00007ffff4cf2202 in SfxBaseModel::load(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) 
() from /opt/
openoffice4/program/libsfx.so
#9  0x00007ffff4d47093 in ?? () from /opt/openoffice4/program/libsfx.so
#10 0x00007fffee2a6750 in ?? () from /opt/openoffice4/program/libfwk.so
#11 0x00007fffee2a707e in ?? () from /opt/openoffice4/program/libfwk.so
#12 0x00007fffee2619a0 in ?? () from /opt/openoffice4/program/libfwk.so
#13 0x00007fffee261c0e in ?? () from /opt/openoffice4/program/libfwk.so
#14 0x00007ffff5d38868 in 
comphelper::SynchronousDispatch::dispatch(com::sun::star::uno::Reference<com::sun::star::uno::XInterface> const&, 
rtl::OUString const&, rtl::OUString const&, int, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) 
() from /opt/
openoffice4/program/libcomphelpgcc3.so
#15 0x00007ffff77971a3 in ?? () from /opt/openoffice4/program/libsofficeapp.so
#16 0x00007ffff77a33a6 in ?? () from /opt/openoffice4/program/libsofficeapp.so
#17 0x00007ffff77831f0 in ?? () from /opt/openoffice4/program/libsofficeapp.so
#18 0x00007ffff7784d0a in ?? () from /opt/openoffice4/program/libsofficeapp.so
#19 0x00007ffff2ec6ab3 in ?? () from /opt/openoffice4/program/libvcl.so
#20 0x00007fffea8f9b27 in SalDisplay::DispatchInternalEvent() () from /opt/openoffice4/program/libvclplug_gen.so
#21 0x00007fffeabb63b4 in ?? () from /opt/openoffice4/program/libvclplug_gtk.so
#22 0x00007fffe9aed175 in g_main_dispatch (context=0x65ea80) at gmain.c:3154
#23 g_main_context_dispatch ([email protected]=0x65ea80) at gmain.c:3769
#24 0x00007fffe9aed4e8 in g_main_context_iterate ([email protected]=0x65ea80, [email protected]=0x0, 
[email protected]=0x1,   
self=<optimized out>) at gmain.c:3840
#25 0x00007fffe9aed58c in g_main_context_iteration (context=0x65ea80, may_block=0x0) at gmain.c:3901
#26 0x00007fffeabb61f0 in ?? () from /opt/openoffice4/program/libvclplug_gtk.so
#27 0x00007ffff2caa45f in ?? () from /opt/openoffice4/program/libvcl.so
#28 0x00007ffff2ca9667 in Application::Execute() () from /opt/openoffice4/program/libvcl.so
#29 0x00007ffff777e93e in ?? () from /opt/openoffice4/program/libsofficeapp.so
#30 0x00007ffff2cad7eb in ?? () from /opt/openoffice4/program/libvcl.so
#31 0x00007ffff2cad8b6 in SVMain() () from /opt/openoffice4/program/libvcl.so
#32 0x00007ffff77a5f8c in soffice_main () from /opt/openoffice4/program/libsofficeapp.so
#33 0x0000000000400f7b in main ()
#34 0x00007ffff6646f45 in __libc_start_main (main=0x400f70 <main>, argc=0x6, argv=0x7fffffffdf18, init=<optimized out>, 
fini=<optimized out>, rtld_fini=<optimized out>,     
stack_end=0x7fffffffdf08)
    at libc-start.c:287
#35 0x0000000000400eb9 in _start ()


let's check the write address `rdi+0x10`:

gdb-peda$ vmmap $rdi+0x10
Start              End                Perm  Name
0x00007fffc2ef1000 0x00007fffc3568000 r-xp  /opt/openoffice4/program/libsd.so

As we can see an attempt to write is made in an address range of the mapped file libsd.so, which results in an access violation because of the pages that contain this mapped file are set to read and execute permissions, but not write. To understand why this vulnerability appears, we will look at the vulnerable function in the source code:

filter\source\msfilter\svdfppt.cxx : 4343

PPTStyleSheet::PPTStyleSheet( const DffRecordHeader& rSlideHd, SvStream& rIn, SdrPowerPointImport& rManager,
                                const PPTTextCharacterStyleAtomInterpreter& /

    *rTxCFStyle*/, const PPTTextParagraphStyleAtomInterpreter& rTxPFStyle,
                                    const PPTTextSpecInfo& rTextSpecInfo ) :

Line 4373   DffRecordHeader* pEnvHeader = rManager.aDocRecManager.GetRecordHeader( PPT_PST_Environment );
Line 4374   if ( pEnvHeader )
Line 4375   {
Line 4376       pEnvHeader->SeekToContent( rIn );
Line 4377       DffRecordHeader aTxMasterStyleHd;
Line 4378       while ( rIn.Tell() < pEnvHeader->GetRecEndFilePos() )
Line 4379       {
Line 4380           rIn >> aTxMasterStyleHd;
Line 4381           if ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom )
Line 4382           {
Line 4383               sal_uInt16 nLevelAnz;
Line 4384               rIn >> nLevelAnz;
Line 4385
Line 4386               sal_uInt16 nLev = 0;
Line 4387               sal_Bool bFirst = sal_True;
Line 4388               bFoundTxMasterStyleAtom04 = sal_True;
Line 4389               while ( rIn.GetError() == 0 && rIn.Tell() < aTxMasterStyleHd.GetRecEndFilePos() && 
nLev < nLevelAnz )
Line 4390               {
Line 4391                   if ( nLev )
Line 4392                   {
Line 4393                       mpParaSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->maParaLevel[ nLev ] = 
mpParaSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->maParaLevel[ nLev - 1 ];
Line 4394                       mpCharSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->maCharLevel[ nLev ] = 
mpCharSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->maCharLevel[ nLev - 1 ];
Line 4395                   }
Line 4396                   mpParaSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->Read( rManager, rIn, sal_True, 
nLev, bFirst );
            (...)
Line 4412                   mpCharSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->Read( rIn, sal_True, nLev, 
bFirst );
Line 4413                   mpParaSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->UpdateBulletRelSize(  nLev, 
mpCharSheet[ TSS_TYPE_TEXT_IN_SHAPE ]->maCharLevel[ nLev ].mnFontHeight );
Line 4414                   bFirst = sal_False;
Line 4415                   nLev++;
            (...)
Line 4418           }
Line 4419           else
Line 4420               aTxMasterStyleHd.SeekToEndOfRecord( rIn );                                                  

First of all code in the while loop at Line 4378 searches for a PPTPSTTxMasterStyleAtom record ( [MS-PPT] 2.9.35 TextMasterStyleAtom ). It finds it in the file at offset 0x957c.

(gdb) p aTxMasterStyleHd 
$8 = {nRecVer = 0 '\000', nRecInstance = 4, nImpVerInst = 64, nRecType = 4003, nRecLen = 4294901870, nFilePos = 380}    

Next, we see that nLevelAnz is read at line 4384. According to documentation:

cLevels (2 bytes): An unsigned integer that specifies the number of style levels. It MUST be less than or equal to 0x0005.

but in our case its value is equal:

(gdb) n
4384                                    rIn >> nLevelAnz;
(gdb) p nLevelAnz
$9 = 65535 (0xffff)

We also see the following:

            PPTParaLevel    maParaLevel[ 5 ];
            and
            PPTCharLevel    maCharLevel[ 5 ];

The lack of enforcement of the constraint that nLevelAnz must be less than 5 results in the vulnerability. The variables maParaLevel and maCharLevel are written to at lines 4393-4394. Our invalid value will cause nLev to be bigger than 4 in the loop, which will result in an out of bound write. This can then lead to arbitrary code execution.

Crash Information

gdb-peda$ context
[----------------------------------registers-----------------------------------]
RAX: 0xb70 ('p\x0b')
RBX: 0x28a 
RCX: 0x7fffc2ef0fdc --> 0x800000000010000 
RDX: 0x7fffc2a4fd88 --> 0x64000020220000 ('')
RSI: 0x7fffc2a45170 --> 0x0 
RDI: 0x7fffc2ef0ff0 --> 0x800000000010000 
RBP: 0x28a 
RSP: 0x7fffffffa7b0 --> 0x1 
RIP: 0x7fffc2571dfc (mov    WORD PTR [rdi+0x10],ax)
R8 : 0x5140 ('@Q')
R9 : 0x0 
R10: 0x7fffc2a4f9c8 --> 0x7ffff09eca80 --> 0x7ffff07bfa64 (<_ZN16SotStorageStream7GetDataEPvm>: push   rbp)
R11: 0xc8 
R12: 0x0 
R13: 0x28a 
R14: 0x7fffc2a3f148 --> 0x7fffc2a77848 --> 0x7fffc2a413e8 --> 0x7b ('{')
R15: 0x7fffc2a4f9c8 --> 0x7ffff09eca80 --> 0x7ffff07bfa64 (<_ZN16SotStorageStream7GetDataEPvm>: push   rbp)
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7fffc2571df0:  mov    rax,QWORD PTR [rcx+0x8]
   0x7fffc2571df4:  mov    QWORD PTR [rdi+0x8],rax
   0x7fffc2571df8:  movzx  eax,WORD PTR [rcx+0x10]
=> 0x7fffc2571dfc:  mov    WORD PTR [rdi+0x10],ax
   0x7fffc2571e00:  mov    rax,QWORD PTR [rsp+0x28]
   0x7fffc2571e05:  movzx  r12d,r9b
   0x7fffc2571e09:  mov    r8d,ebx
   0x7fffc2571e0c:  mov    r9d,r12d
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffa7b0 --> 0x1 
0008| 0x7fffffffa7b8 --> 0x966f08 --> 0x7ffff7ffe480 --> 0x6db1b0 --> 0x7ffff7ffe1c8 --> 0x0 
0016| 0x7fffffffa7c0 --> 0x7fffffffb160 --> 0x1 
0024| 0x7fffffffa7c8 --> 0x7ffff7ed8808 --> 0x7fffc27ab310 --> 0x7fffc25730b0 
(<_ZNK19SdrPowerPointImport9ImportOLEElRK7GraphicRK9RectangleS5_il>:    push   r15)
0032| 0x7fffffffa7d0 --> 0x7fffffffb0b0 --> 0xfc9000f0000b10f 
0040| 0x7fffffffa7d8 --> 0x7fffc2a45170 --> 0x0 
0048| 0x7fffffffa7e0 --> 0x7ffff7ed9000 --> 0x10000000b 
0056| 0x7fffffffa7e8 --> 0x3e8a00000000 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ bt
#0  0x00007fffc2571dfc in ?? () from /opt/openoffice4/program/libmsfilter.so
#1  0x00007fffc2577c4d in SdrPowerPointImport::SdrPowerPointImport(PowerPointImportParam&, String const&) () from /opt/
openoffice4/program/libmsfilter.so
#2  0x00007fffc27c702e in ?? () from /opt/openoffice4/program/libsdfilt.so
#3  0x00007fffc27c74e9 in ?? () from /opt/openoffice4/program/libsdfilt.so
#4  0x00007fffc27ceafb in ImportPPT () from /opt/openoffice4/program/libsdfilt.so
#5  0x00007fffc326c4c8 in ?? () from /opt/openoffice4/program/../program/libsd.so
#6  0x00007fffc318884d in sd::DrawDocShell::ConvertFrom(SfxMedium&) () from /opt/openoffice4/program/../program/libsd.so
#7  0x00007ffff4ccc02f in SfxObjectShell::DoLoad(SfxMedium*) () from /opt/openoffice4/program/libsfx.so
#8  0x00007ffff4cf2202 in SfxBaseModel::load(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) 
() from /opt/openoffice4/program/libsfx.so
#9  0x00007ffff4d47093 in ?? () from /opt/openoffice4/program/libsfx.so
#10 0x00007fffee2a6750 in ?? () from /opt/openoffice4/program/libfwk.so
#11 0x00007fffee2a707e in ?? () from /opt/openoffice4/program/libfwk.so
#12 0x00007fffee2619a0 in ?? () from /opt/openoffice4/program/libfwk.so
#13 0x00007fffee261c0e in ?? () from /opt/openoffice4/program/libfwk.so
#14 0x00007ffff5d38868 in 
comphelper::SynchronousDispatch::dispatch(com::sun::star::uno::Reference<com::sun::star::uno::XInterface> const&, 
rtl::OUString const&, rtl::OUString const&, int, 
    com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) () from /opt/openoffice4/program/
libcomphelpgcc3.so
#15 0x00007ffff77971a3 in ?? () from /opt/openoffice4/program/libsofficeapp.so
#16 0x00007ffff77a33a6 in ?? () from /opt/openoffice4/program/libsofficeapp.so
#17 0x00007ffff77831f0 in ?? () from /opt/openoffice4/program/libsofficeapp.so
#18 0x00007ffff7784d0a in ?? () from /opt/openoffice4/program/libsofficeapp.so
#19 0x00007ffff2ec6ab3 in ?? () from /opt/openoffice4/program/libvcl.so
#20 0x00007fffea8f9b27 in SalDisplay::DispatchInternalEvent() () from /opt/openoffice4/program/libvclplug_gen.so
#21 0x00007fffeabb63b4 in ?? () from /opt/openoffice4/program/libvclplug_gtk.so
#22 0x00007fffe9aed175 in g_main_dispatch (context=0x65ea80) at gmain.c:3154
#23 g_main_context_dispatch ([email protected]=0x65ea80) at gmain.c:3769
#24 0x00007fffe9aed4e8 in g_main_context_iterate ([email protected]=0x65ea80, [email protected]=0x0, 
[email protected]=0x1, self=<optimized out>) at gmain.c:3840
#25 0x00007fffe9aed58c in g_main_context_iteration (context=0x65ea80, may_block=0x0) at gmain.c:3901
#26 0x00007fffeabb61f0 in ?? () from /opt/openoffice4/program/libvclplug_gtk.so
#27 0x00007ffff2caa45f in ?? () from /opt/openoffice4/program/libvcl.so
#28 0x00007ffff2ca9667 in Application::Execute() () from /opt/openoffice4/program/libvcl.so
#29 0x00007ffff777e93e in ?? () from /opt/openoffice4/program/libsofficeapp.so
#30 0x00007ffff2cad7eb in ?? () from /opt/openoffice4/program/libvcl.so
#31 0x00007ffff2cad8b6 in SVMain() () from /opt/openoffice4/program/libvcl.so
#32 0x00007ffff77a5f8c in soffice_main () from /opt/openoffice4/program/libsofficeapp.so
#33 0x0000000000400f7b in main ()
#34 0x00007ffff6646f45 in __libc_start_main (main=0x400f70 <main>, argc=0x6, argv=0x7fffffffdf18, init=<optimized out>, 
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf08)
    at libc-start.c:287
#35 0x0000000000400eb9 in _start ()
gdb-peda$ exploitable
Description: Access violation on destination operand
Short description: DestAv (9/29)
Hash: 0bbf6be05d7aaa5fd446172b8afe89c9.4e7dfbc3f1e3222a4c595e370f909d8b
Exploitability 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.

Other tags: AccessViolation (28/29)

Timeline

2017-03-29 - Vendor Disclosure
2017-10-26 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.