CVE-2017-9806
An exploitable out of bound write vulnerability exists in the WW8Fonts::WW8Fonts functionality of Apache OpenOffice 4.1.3. A specially crafted doc file can cause an out of bound write potentially resulting in arbitrary code execution. An attacker can send/provide a malicious doc file to trigger this vulnerability.
Apache OpenOffice 4.1.3
8.3 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
This vulnerability is present in Apache OpenOffice (formerly OpenOffice.org), a free open source office suite. A specially crafted DOC file can lead to an out of bound write and ultimately to remote code execution.
Let’s investigate this vulnerability. After OpenOffice Writer opens the malformed doc file we see the following state:
gdb-peda$ context
[———————————-registers———————————–]
EAX: 0xa9788010 –> 0x30003
EBX: 0xa9c16000 –> 0x2a1b30
ECX: 0x28 (‘(‘)
EDX: 0x3
ESI: 0xffff
EDI: 0xa96a800c –> 0xffff0000
EBP: 0xbfffd578 –> 0xbfffd778 –> 0xbfffd9a8 –> 0xbfffda48 –> 0xbfffdab8 –> 0xbfffdb78 –> 0xbfffdbf8 –> 0xbfffddd8 –> 0xbfffdea8 –> 0xbfffdf68 –> 0xbfffe018 –>
0xbfffe058 –> 0xbfffe0e8 –> 0xbfffe138 –> 0xbfffe1f8 –> 0xbfffe378 –> 0xbfffe3d8 –> 0xbfffe6c8 –> 0xbfffe718 –> 0xbfffe738 –> 0xbfffe758 –> 0xbfffe778 –>
0xbfffe818 –> 0xbfffe848 –> 0xbfffe898 –> 0xbfffe8c8 –> 0xbfffe8e8 –> 0x823f4b0 –> 0x2
ESP: 0xbfffd500 –> 0x10
EIP: 0xa9b5cdf7 (<WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1649>: mov WORD PTR [eax],dx)
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[————————————-code————————————-]
0xa9b5cdef <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1641>: add esp,0x10
0xa9b5cdf2 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1644>: mov edx,eax
0xa9b5cdf4 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1646>: mov eax,DWORD PTR [ebp-0x2c]
=> 0xa9b5cdf7 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1649>: mov WORD PTR [eax],dx
0xa9b5cdfa <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1652>: add DWORD PTR [ebp-0x2c],0x2
0xa9b5cdfe <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1656>: add BYTE PTR [ebp-0x53],0x2
0xa9b5ce02 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1660>: jmp 0xa9b5cddb <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1621>
0xa9b5ce04 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1662>: mov eax,DWORD PTR [ebp-0x30]
[————————————stack————————————-]
0000| 0xbfffd500 –> 0x10
0004| 0xbfffd504 –> 0xa9c22110 –> 0xa96a800c –> 0xffff0000
0008| 0xbfffd508 –> 0xa96a8008 –> 0xffff
0012| 0xbfffd50c –> 0xa9768000 –> 0x0
0016| 0xbfffd510 –> 0xffffffff
0020| 0xbfffd514 –> 0xa9cea310 –> 0x8
0024| 0xbfffd518 –> 0xa9c21f58 –> 0xb4b526a0 –> 0xb4b15a6a (<SotStorageStream::GetData(void,
unsigned long)>: push ebp)
0028| 0xbfffd51c –> 0xa9c22110 –> 0xa96a800c –> 0xffff0000
[——————————————————————————]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ bt 1
#0 0xa9b5cdf7 in WW8Fonts::WW8Fonts (this=0xa9c22110, rSt=…, rFib=…) at /storage/aoo-
4.1.3/main/sw/source/filter/ww8/ww8scan.cxx:6571
(More stack frames follow…)
gdb-peda$ info line *$pc
Line 6571 of “/storage/aoo-4.1.3/main/sw/source/filter/ww8/ww8scan.cxx” starts at address 0xa9b5cde4
<WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1630> and ends at 0xa9b5cdfa
<WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1652>.
gdb-peda$ list *$pc
0xa9b5cdf7 is in WW8Fonts::WW8Fonts(SvStream&, WW8Fib&) (/storage/aoo-
4.1.3/main/sw/source/filter/ww8/ww8scan.cxx:6571).
6566 sal_uInt8 nLength = sizeof( pVer8->szFfn ) / sizeof( SVBT16 );
6567 nLength = std::min( nLength, sal_uInt8( pVer8->cbFfnM1+1 ) );
6568 for( sal_uInt16 pTmp = pVer8->szFfn;
6569 nLen < nLength; ++pTmp, nLen+=2 )
6570 {
6571 pTmp = SVBT16ToShort( *(SVBT16)pTmp );
6572 }
6573 }
6574 #endif // defined __WW8_NEEDS_COPY
6575
So we see that write access violation appeared in the WW8Fonts::WW8Fonts
constructor. The definition of this function is located in file /storage/aoo-4.1.3/main/sw/source/filter/ww8/ww8scan.cxx:6571
.
Checking the pTmp
pointer value we see:
gdb-peda$ p pTmp
$25 = (sal_uInt16 *) 0xa9788010
gdb-peda$ vmmap 0xa9788010
Start End Perm Name
0xa9788000 0xa9823000 r-xp /storage/aoo-
4.1.3/main/instsetoo_native/unxlngi6.pro/Apache_OpenOffice/installed/install/en-
US/openoffice4/program/libunoxml.so
When an attempt to write to the address pointed to by the pTmp
pointer, we encounter an access violation will because it points to mapped libunoxml.so
library.
Looking at source code we see (the lines here have different numbers than the lines in the original source code):
1 WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
2 : pFontA(0), nMax(0)
3 {
4 // sal_uInt16 nMax;
5 (...)
6 rSt.Seek( rFib.fcSttbfffn );
7
8 sal_Int32 nFFn = rFib.lcbSttbfffn - 2;
9
10 // allocate Font Array
11 sal_uInt8* pA = new sal_uInt8[ nFFn ];
12 memset(pA, 0, nFFn);
13 WW8_FFN* p = (WW8_FFN*)pA;
14
15 ww::WordVersion eVersion = rFib.GetFIBVersion();
16
17 if( eVersion >= ww::eWW8 )
18 {
19 // bVer8: read the count of strings in nMax
20 rSt >> nMax;
21 }
22
23 (...)
24 WW8_FFN_Ver8* pVer8 = (WW8_FFN_Ver8*)pA;
25 sal_uInt8 c2;
26 for(sal_uInt16 i=0; i<nMax; ++i, ++p)
27 {
28
29 (...)
30 sal_uInt8 nLen = 0x28;
31 sal_uInt8 nLength = sizeof( pVer8->szFfn ) / sizeof( SVBT16 );
32 nLength = std::min( nLength, sal_uInt8( pVer8->cbFfnM1+1 ) );
33 for( sal_uInt16* pTmp = pVer8->szFfn;
34 nLen < nLength; ++pTmp, nLen+=2 )
35 {
36 *pTmp = SVBT16ToShort( *(SVBT16*)pTmp );
37 }
38 (...)
39 // Zeiger auf Ursprungsarray einen Font nach hinten setzen
40 pVer8 = (WW8_FFN_Ver8*)( ((sal_uInt8*)pVer8) + pVer8->cbFfnM1 + 1 );
41 }
The loop at line 26
is based on nMax
value. Each time at the end of this loop (at line 40
) pVer8
pointer is set to new location based on the cbFfnM1
field value.
pVer8
is a pointer to a dynamically allocated buffer, which is allocated at line 11
, with a size equal to rFib.lcbSttbfffn - 2
. As we can see there is no check to see whether
after first iteration pVer8
is pointing outside buffer range or not. That situation leads to out of bound read/writes in certain places and finally can lead to remote code execution.
A dump of some important fields:
gdb-peda$ p rFib.lcbSttbfffn
$30 = 0xb6
gdb-peda$ p rFib.fcSttbfffn
$31 = 0x501
gdb-peda$ p nMax
$32 = 0xffff
gdb-peda$ p eVersion
$33 = ww::eWW8
gdb-peda$ p *(WW8_FFN_Ver8*)pA
$38 = {
<WW8_FFN_BASE> = {
cbFfnM1 = 0x0,
prg = 0x0,
fTrueType = 0x0,
ff = 0x0,
wWeight = 0xffff,
chs = 0x0,
ibszAlt = 0x0
[----------------------------------registers-----------------------------------]
EAX: 0xa9788010 --> 0x30003
EBX: 0xa9c16000 --> 0x2a1b30
ECX: 0x28 ('(')
EDX: 0x3
ESI: 0xffff
EDI: 0xa96a800c --> 0xffff0000
EBP: 0xbfffd578 --> 0xbfffd778 --> 0xbfffd9a8 --> 0xbfffda48 --> 0xbfffdab8 --> 0xbfffdb78 --> 0xbfffdbf8 -->
0xbfffddd8 --> 0xbfffdea8 --> 0xbfffdf68 --> 0xbfffe018 -->
0xbfffe058 --> 0xbfffe0e8 --> 0xbfffe138 --> 0xbfffe1f8 --> 0xbfffe378 --> 0xbfffe3d8 --> 0xbfffe6c8 --> 0xbfffe718
--> 0xbfffe738 --> 0xbfffe758 --> 0xbfffe778 -->
0xbfffe818 --> 0xbfffe848 --> 0xbfffe898 --> 0xbfffe8c8 --> 0xbfffe8e8 --> 0x823f4b0 --> 0x2
ESP: 0xbfffd500 --> 0x10
EIP: 0xa9b5cdf7 (<WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1649>: mov WORD PTR [eax],dx)
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0xa9b5cdef <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1641>: add esp,0x10
0xa9b5cdf2 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1644>: mov edx,eax
0xa9b5cdf4 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1646>: mov eax,DWORD PTR [ebp-0x2c]
=> 0xa9b5cdf7 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1649>: mov WORD PTR [eax],dx
0xa9b5cdfa <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1652>: add DWORD PTR [ebp-0x2c],0x2
0xa9b5cdfe <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1656>: add BYTE PTR [ebp-0x53],0x2
0xa9b5ce02 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1660>: jmp 0xa9b5cddb
<WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1621>
0xa9b5ce04 <WW8Fonts::WW8Fonts(SvStream&, WW8Fib&)+1662>: mov eax,DWORD PTR [ebp-0x30]
[------------------------------------stack-------------------------------------]
0000| 0xbfffd500 --> 0x10
0004| 0xbfffd504 --> 0xa9c22110 --> 0xa96a800c --> 0xffff0000
0008| 0xbfffd508 --> 0xa96a8008 --> 0xffff
0012| 0xbfffd50c --> 0xa9768000 --> 0x0
0016| 0xbfffd510 --> 0xffffffff
0020| 0xbfffd514 --> 0xa9cea310 --> 0x8
0024| 0xbfffd518 --> 0xa9c21f58 --> 0xb4b526a0 --> 0xb4b15a6a (<SotStorageStream::GetData(void*,
unsigned long)>: push ebp)
0028| 0xbfffd51c --> 0xa9c22110 --> 0xa96a800c --> 0xffff0000
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ exploitable
Description: Access violation on destination operand
Short description: DestAv (9/29)
Hash: 35ea22a685538a48f0dc54bae45e3da2.afc0f1decc0f689aa835fa8a3e7bfbc3
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)
gdb-peda$ bt
#0 0xa9b5cdf7 in WW8Fonts::WW8Fonts (this=0xa9c22110, rSt=..., rFib=...) at /storage/aoo-
4.1.3/main/sw/source/filter/ww8/ww8scan.cxx:6571
#1 0xa9ae4b57 in SwWW8ImplReader::CoreLoad (this=0xabc86c0c, pGloss=0x0, rPos=...) at /storage/aoo-
4.1.3/main/sw/source/filter/ww8/ww8par.cxx:4390
#2 0xa9ae8606 in SwWW8ImplReader::LoadThroughDecryption (this=0xabc86c0c, rPaM=..., pGloss=0x0) at
/storage/aoo-4.1.3/main/sw/source/filter/ww8/ww8par.cxx:5163
#3 0xa9ae94dd in SwWW8ImplReader::LoadDoc (this=0xabc86c0c, rPaM=..., pGloss=0x0) at /storage/aoo-
4.1.3/main/sw/source/filter/ww8/ww8par.cxx:5430
#4 0xa9ae976a in WW8Reader::Read (this=0xa9cdff84, rDoc=..., rBaseURL=..., rPam=...) at /storage/aoo-
4.1.3/main/sw/source/filter/ww8/ww8par.cxx:5499
#5 0xaaa4d71e in SwReader::Read (this=0xa9c1e2b4, rOptions=...) at /storage/aoo-
4.1.3/main/sw/source/filter/basflt/shellio.cxx:189
#6 0xaab67bc1 in SwDocShell::ConvertFrom (this=0xacafe034, rMedium=...) at /storage/aoo-
4.1.3/main/sw/source/ui/app/docsh.cxx:258
#7 0xb7243e0f in SfxObjectShell::DoLoad (this=0xacafe034, pMed=0xa9cf4e90) at /storage/aoo-
4.1.3/main/sfx2/source/doc/objstor.cxx:753
#8 0xb728bcfc in SfxBaseModel::load (this=0xabb98ad4, seqArguments=...) at /storage/aoo-
4.1.3/main/sfx2/source/doc/sfxbasemodel.cxx:1878
#9 0xb7342be9 in SfxFrameLoader_Impl::load (this=0xabb7758c, rArgs=..., _rTargetFrame=...) at
/storage/aoo-4.1.3/main/sfx2/source/view/frmload.cxx:607
#10 0xae5786d8 in framework::LoadEnv::impl_loadContent (this=0xaf31e964) at /storage/aoo-
4.1.3/main/framework/source/loadenv/loadenv.cxx:1205
#11 0xae574e16 in framework::LoadEnv::startLoading (this=0xaf31e964) at /storage/aoo-
4.1.3/main/framework/source/loadenv/loadenv.cxx:433
#12 0xae505c67 in framework::LoadDispatcher::impl_dispatch (this=0xaf31e918, rURL=..., lArguments=...,
xListener=...) at /storage/aoo-4.1.3/main/framework/source/
dispatch/loaddispatcher.cxx:165
#13 0xae5059a8 in framework::LoadDispatcher::dispatchWithReturnValue (this=0xaf31e918, rURL=...,
lArguments=...) at /storage/aoo-4.1.3/main/framework/source/dispatch/
loaddispatcher.cxx:102
#14 0xb782d5f4 in comphelper::SynchronousDispatch::dispatch (xStartPoint=..., sURL=..., sTarget=...,
nFlags=0x0, lArguments=...) at /storage/aoo-4.1.3/main/comphelper/
source/misc/synchronousdispatch.cxx:81
#15 0xb7d753f4 in desktop::DispatchWatcher::executeDispatchRequests (this=0xad4129a8,
aDispatchRequestsList=..., bNoTerminate=0x0) at /storage/aoo-4.1.3/main/desktop/
source/app/dispatchwatcher.cxx:333
#16 0xb7d83108 in desktop::OfficeIPCThread::ExecuteCmdLineRequests (aRequest=...) at /storage/aoo-
4.1.3/main/desktop/source/app/officeipcthread.cxx:993
#17 0xb7d562b4 in desktop::Desktop::OpenClients () at /storage/aoo-
4.1.3/main/desktop/source/app/app.cxx:3204
#18 0xb7d51dfd in desktop::Desktop::OpenClients_Impl (this=0xbfffed88) at /storage/aoo-
4.1.3/main/desktop/source/app/app.cxx:2536
#19 0xb7d51db1 in desktop::Desktop::LinkStubOpenClients_Impl (pThis=0xbfffed88, pCaller=0x0) at
/storage/aoo-4.1.3/main/desktop/source/app/app.cxx:2532
#20 0xb5b07fc4 in Link::Call (this=0xae90c2ec, pCaller=0x0) at /storage/aoo-
4.1.3/main/solver/413/unxlngi6.pro/inc/tools/link.hxx:135
#21 0xb5efa9a1 in ImplHandleUserEvent (pSVEvent=0xacafa0f8) at /storage/aoo-
4.1.3/main/vcl/source/window/winproc.cxx:1996
#22 0xb5efbc22 in ImplWindowFrameProc (pWindow=0xae90e1d4, nEvent=0x16, pEvent=0xacafa0f8) at
/storage/aoo-4.1.3/main/vcl/source/window/winproc.cxx:2568
#23 0xb20e0fd5 in SalFrame::CallCallback (this=0xaf321a60, nEvent=0x16, pEvent=0xacafa0f8) at
/storage/aoo-4.1.3/main/vcl/inc/salframe.hxx:281
#24 0xb20f4c25 in SalDisplay::DispatchInternalEvent (this=0xb22b4008) at /storage/aoo-
4.1.3/main/vcl/unx/generic/app/saldisp.cxx:2231
#25 0xb22582f4 in GtkXLib::userEventFn (data=0xb24c9308) at /storage/aoo-
4.1.3/main/vcl/unx/gtk/app/gtkdata.cxx:817
#26 0xb225820e in call_userEventFn (data=0xb24c9308) at /storage/aoo-
4.1.3/main/vcl/unx/gtk/app/gtkdata.cxx:790
#27 0xb1799610 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0
#28 0xb179cd9b in g_main_context_dispatch () from /lib/i386-linux-gnu/libglib-2.0.so.0
#29 0xb179d189 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0
#30 0xb179d254 in g_main_context_iteration () from /lib/i386-linux-gnu/libglib-2.0.so.0
#31 0xb22584e2 in GtkXLib::Yield (this=0xb24c9308, bWait=0x1, bHandleAllCurrentEvents=0x0) at
/storage/aoo-4.1.3/main/vcl/unx/gtk/app/gtkdata.cxx:869
#32 0xb2103187 in X11SalInstance::Yield (this=0xb2cec290, bWait=0x1, bHandleAllCurrentEvents=0x0) at
/storage/aoo-4.1.3/main/vcl/unx/generic/app/salinst.cxx:278
#33 0xb5b19e67 in ImplYield (i_bWait=0x1, i_bAllEvents=0x0) at /storage/aoo-
4.1.3/main/vcl/source/app/svapp.cxx:476
#34 0xb5b15a93 in Application::Yield (i_bAllEvents=0x0) at /storage/aoo-
4.1.3/main/vcl/source/app/svapp.cxx:510
#35 0xb5b15a2c in Application::Execute () at /storage/aoo-4.1.3/main/vcl/source/app/svapp.cxx:453
#36 0xb7d5051a in desktop::Desktop::Main (this=0xbfffed88) at /storage/aoo-
4.1.3/main/desktop/source/app/app.cxx:2232
#37 0xb5b20296 in ImplSVMain () at /storage/aoo-4.1.3/main/vcl/source/app/svmain.cxx:196
#38 0xb5b20423 in SVMain () at /storage/aoo-4.1.3/main/vcl/source/app/svmain.cxx:237
#39 0xb7d8543a in soffice_main () at /storage/aoo-4.1.3/main/desktop/source/app/sofficemain.cxx:45
#40 0x08048df5 in sal_main () at main.c:31
#41 0x08048ddb in main (argc=0x6, argv=0xbfffeea4) at main.c:30
#42 0xb798a637 in __libc_start_main (main=0x8048dbb <main>, argc=0x6, argv=0xbfffeea4, init=0x80493a0
<__libc_csu_init>, fini=0x8049400 <__libc_csu_fini>,
rtld_fini=0xb7fea780 <_dl_fini>, stack_end=0xbfffee9c) at ../csu/libc-start.c:291
#43 0x08048ce1 in _start ()
2017-03-16 - Vendor Disclosure
2017-10-26 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.