Talos Vulnerability Report

TALOS-2016-0208

AntennaHouse DMC HTMLFilter Doc_GetFontTable Code Execution Vulnerability

May 4, 2017
CVE Number

CVE-2016-8383

Summary

An exploitable heap corruption vulnerability exists in the Doc_GetFontTable functionality of AntennaHouse DMC HTMLFilter. A specially crafted doc file can cause a heap corruption resulting in arbitrary code execution. An attacker can send/provide malicious doc file to trigger this vulnerability.

Tested Versions

AntennaHouse DMC HTMLFilter shipped with MarkLogic 8.0-5.5

1415cbc784f05db0e9db424636df581a  libdhf_comm.so
81db1b55e18a0cb70a78410147f50b9c  libdhf_htmlif.so
fb1a22fa08c986ec3614284f4e912b0a  libdhf_rdoc.so
b2622da4ce1aa7fa4aac10ee7d3407cf  libdhf_rppt.so
1eabb31236c675f9856a7d001b339334  libdhf_rxls.so
d716dd77c8e9ee88df435e74fad687e6  libdhf_whtml.so
15b0acc464fba28335239f722a62037f  libdmc_comm.so
4ae366fbd4540dd4c750e6679eb63dd4  libdmc_conf.so
84009641f744d88fd1737d59b7c71ab1  libdmc_dtct.so

Product URLs

https://www.antennahouse.com/antenna1/

CVSSv3 Score

8.3 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H CVSSv3 Calculator: https://www.first.org/cvss/calculator/3.0

Details

This vulnerability is present in the AntennaHouse DMC HTMLFilter which is used among others to convert doc files to (x)html form. This product is mainly used by MarkLogic for doc document conversions as part of their web based document search and rendering engine. A specially crafted DOC file can lead to an heap corruption and ultimately to remote code execution.

Let’s investigate this vulnerability. After execution the doc to html converter with malformed doc file as an input we can easily observe a couple of flaws using Valgrind:

icewall@ubuntu:~/bugs/cvtofc$ valgrind ./convert config_doc
==4844== Memcheck, a memory error detector
==4844== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4844== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4844== Command: ./convert config_doc
==4844== 
input=/home/icewall/bugs/cvtofc/config_doc/toconv.doc
output=/home/icewall/bugs/cvtofc/config_doc/conv.html
type=1
info.options='0'
Return from GetFileInfo=0
HtmlInfo.GroupName=UTF-8
HtmlInfo.DefLangName=English
HtmlInfo.bBigEndian=0
HtmlInfo.options=0
HtmlInfo.SheetId=0
HtmlInfo.SlideId=0
HtmlInfo.lpFunc=(nil)
HtmlInfo.szImageFolder=
==4844== Invalid write of size 1
==4844==    at 0x63838A6: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351ce8 is 0 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid read of size 1
==4844==    at 0x63838B2: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351ce8 is 0 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 1
==4844==    at 0x63838D4: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351ce9 is 1 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 1
==4844==    at 0x63838E6: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351cea is 2 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 1
==4844==    at 0x63838F8: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351ceb is 3 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 1
==4844==    at 0x638390A: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351cec is 4 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 1
==4844==    at 0x6383917: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351ced is 5 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 2
==4844==    at 0x638392F: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351cee is 6 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 1
==4844==    at 0x6383949: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351cf0 is 8 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 1
==4844==    at 0x6383961: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351cf1 is 9 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 2
==4844==    at 0x6383A24: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351cf2 is 10 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid write of size 2
==4844==    at 0x63839D5: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x43520f2 is 18 bytes after a block of size 8 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42E588B: initStruct (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42E2E0C: initLimit (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DEEE9: loadHex (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DF417: isBaseSet (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DFE59: xmlReadXML (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DED8F: cconvLoadRule (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x4038C06: _init (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x400ED16: call_init.part.0 (dl-init.c:64)
==4844==    by 0x400EE43: call_init (dl-init.c:36)
==4844==    by 0x400EE43: _dl_init (dl-init.c:126)
==4844==    by 0x400110E: ??? (in /lib/i386-linux-gnu/ld-2.19.so)
==4844== 
==4844== Invalid read of size 1
==4844==    at 0x6383A9B: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x4351ce8 is 0 bytes after a block of size 0 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x6383826: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844== 
==4844== Invalid read of size 2
==4844==    at 0x6383AA0: Doc_GetFontTable (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x635CF4C: SimReadText (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x6342C7E: DHF_ROpen (in /home/icewall/bugs/cvtofc/libdhf_rdoc.so)
==4844==    by 0x4039765: FilterToHtml (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc/convert)
==4844==  Address 0x43520f2 is 18 bytes after a block of size 8 alloc'd
==4844==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4844==    by 0x42DACB1: DMC_malloc (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42E588B: initStruct (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42E2E0C: initLimit (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DEEE9: loadHex (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DF417: isBaseSet (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DFE59: xmlReadXML (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x42DED8F: cconvLoadRule (in /home/icewall/bugs/cvtofc/libdmc_comm.so)
==4844==    by 0x4038C06: _init (in /home/icewall/bugs/cvtofc/libdhf_htmlif.so)
==4844==    by 0x400ED16: call_init.part.0 (dl-init.c:64)
==4844==    by 0x400EE43: call_init (dl-init.c:36)
==4844==    by 0x400EE43: _dl_init (dl-init.c:126)
==4844==    by 0x400110E: ??? (in /lib/i386-linux-gnu/ld-2.19.so)

We see in the first couple lines of the Valgrind output thatthe Doc_GetFontTable function argument passed to malloc is equal to 0:

`Address 0x4351ce8 is 0 bytes after a block of size 0 alloc'd`

That’s the root cause of these OOB writes that we could observe above. Ok, we know where the problem is, let’s take a glance at the pseudo code of this function and investigate the origin of the malloc argument.

The pseudo code of this function looks like this:

Line 1 signed int __cdecl Doc_GetFontTable(struct_a1_1 *a1)
Line 2 {
Line 3   int v1; // eax@2
Line 4   int v2; // eax@5
Line 5   signed int result; // eax@7
Line 6   void *v4; // eax@11
Line 7   int v5; // esi@16
Line 8   unsigned __int8 v6; // al@16
Line 9   unsigned __int16 v7; // cx@17
Line 10  signed int v8; // [esp+Ch] [ebp-2Ch]@1
Line 11  char v9; // [esp+11h] [ebp-27h]@1
Line 12  unsigned __int16 v10; // [esp+12h] [ebp-26h]@1
Line 13  int v11; // [esp+14h] [ebp-24h]@1
Line 14  int v12; // [esp+18h] [ebp-20h]@1
Line 15  unsigned int v13; // [esp+1Ch] [ebp-1Ch]@16
Line 16  unsigned int v14; // [esp+20h] [ebp-18h]@11
Line 17  unsigned int v15; // [esp+24h] [ebp-14h]@1
Line 18  unsigned int v16; // [esp+28h] [ebp-10h]@1
Line 19
Line 20  v16 = 0;
Line 21  v15 = 0;
Line 22  v12 = a1->dword38EC;
Line 23  v11 = 0;
Line 24  v10 = 0;
Line 25  v9 = 0;
Line 26  v8 = 0;
Line 27  if ( a1->dword10 )
Line 28  {
Line 29    v1 = a1->dword12C;
Line 30    if ( *(_DWORD *)(v1 + 324) )
Line 31    {
Line 32      v15 = ReadBuf(a1->dword10, *(_DWORD *)(a1->dword12C + 320), *(_DWORD *)(v1 + 324));
Line 33      goto LABEL_10;
Line 34    }
Line 35    return 1;
Line 36  }
Line 37  if ( a1->dword1C )
Line 38  {
Line 39    v2 = a1->dword12C;
Line 40    if ( *(_DWORD *)(v2 + 324) )
Line 41    {
Line 42      v15 = DMC_malloc(*(_DWORD *)(v2 + 324));
Line 43      if ( !v15 )
Line 44        return 25;
Line 45      DMC_FileSeek(a1->dword1C, *(_DWORD *)(a1->dword12C + 320), 0);
Line 46      DMC_FileRead(v15, 1, *(_DWORD *)(a1->dword12C + 324), a1->dword1C);
Line 47      goto LABEL_10;
Line 48    }
Line 49    return 1;
Line 50  }
Line 51LABEL_10:
Line 52  result = 25;
Line 53  if ( v15 )
Line 54  {
Line 55    v16 = v15;
Line 56    v14 = v15 + *(_DWORD *)(a1->dword12C + 324);
Line 57    a1->dword38A4 = Doc_GetDWord(v15, v12);
Line 58    v16 += 4;
Line 59    v4 = (void *)DMC_malloc(1038 * a1->dword38A4);
Line 60    a1->fontTable = v4;
Line 61    if ( v4 )
Line 62    {
Line 63      memset(a1->fontTable, 0, 1038 * a1->dword38A4);
Line 64      while ( v16 < v14 )
Line 65      {
Line 66        v5 = 1038 * v11;
Line 67        *((_BYTE *)a1->fontTable + 1038 * v11) = Doc_GetBYTE(v16++);
Line 68        v13 = v16 + *((unsigned __int8 *)a1->fontTable + 1038 * v11);
Line 69        v6 = Doc_GetBYTE(v16++);
Line 70        *((_BYTE *)a1->fontTable + v5 + 1) = v6 & 3;
Line 71        *((_BYTE *)a1->fontTable + v5 + 2) = (unsigned __int8)(v6 & 4) >> 2;
Line 72        *((_BYTE *)a1->fontTable + v5 + 3) = (unsigned __int8)(v6 & 8) >> 3;
Line 73        *((_BYTE *)a1->fontTable + v5 + 4) = (unsigned __int8)(v6 & 0x70) >> 4;
Line 74        *((_BYTE *)a1->fontTable + v5 + 5) = v6 >> 7;
Line 75        *(_WORD *)((char *)a1->fontTable + v5 + 6) = Doc_GetWord(v16, v12);
Line 76        v16 += 2;
Line 77        *((_BYTE *)a1->fontTable + v5 + 8) = Doc_GetBYTE(v16++);
Line 78        *((_BYTE *)a1->fontTable + v5 + 9) = Doc_GetBYTE(v16);
Line 79        v16 += 35;

We see that in line 32 some data is read from file and assign to v15 pointer. First 128 bytes of that buffer:

(rr) hexdump 0x9761dc8 128
0x09761dc8 : 00 00 00 00 47 0e 90 01 00 00 02 02 06 03 05 04   ....G...........
0x09761dd8 : 05 02 03 04 03 00 00 00 00 00 00 00 00 00 00 00   ................
0x09761de8 : 00 00 00 00 01 00 00 00 00 00 00 00 54 00 69 00   ............T.i.
0x09761df8 : 6d 00 65 00 73 00 20 00 4e 00 65 00 77 00 20 00   m.e.s. .N.e.w. .
0x09761e08 : 52 00 6f 00 6d 00 61 00 6e 00 00 00 35 06 90 01   R.o.m.a.n...5...
0x09761e18 : 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x09761e28 : 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 80   ................
0x09761e38 : 00 00 00 00 53 00 79 00 6d 00 62 00 6f 00 6c 00   ....S.y.m.b.o.l.

At line 57, the first DWORD from this buffer is read and assigned to the a1->dword38A4 field. Next at line 59, the value of that field is used as an argument to malloc.

From the buffer dump we can see that the first DWORD is equal 0. That explains everything: the value from the file is passed directly as an argument to malloc.

In our case it’s equal 0 which causes the result of the multiplication to also be 0. This is not the only bad scenario: this could also lead to an integer overflow, leading to the same results which is heap corruption.

Let’s see how many bytes are available in a buffer malloced with the argument 0.

[-------------------------------------code-------------------------------------]
   0xf72c181b:  sub    eax,edx
   0xf72c181d:  shl    eax,1
   0xf72c181f:  mov    DWORD PTR [esp],eax
=> 0xf72c1822:  call   0xf727ff8c <DMC_malloc@plt>
   0xf72c1827:  mov    DWORD PTR [edi+0x38a0],eax
   0xf72c182d:  add    esp,0x10
   0xf72c1830:  test   eax,eax
   0xf72c1832:  jne    0xf72c1854
Guessed arguments:
arg[0]: 0x0 
[------------------------------------stack-------------------------------------]
0000| 0xffced770 --> 0x0 
0004| 0xffced774 --> 0x0 
0008| 0xffced778 --> 0x164 
0012| 0xffced77c --> 0xf72c16d6 --> 0xaec3815b 
0016| 0xffced780 --> 0xf72e2a84 --> 0x6698c 
0020| 0xffced784 --> 0x9761fba --> 0x0 
0024| 0xffced788 --> 0xffced7b8 --> 0xffceef58 --> 0xffceef88 --> 0xffceefb8 --> 0xffcef398 --> 0xffcff708 --> 0x0 
0028| 0xffced78c --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
(rr) 
[----------------------------------registers-----------------------------------]
EAX: 0x9714268 --> 0xf761b460 --> 0xf761b458 --> 0xf761b450 --> 0x9761f28 --> 0x68 ('h')
EBX: 0xf72e2a84 --> 0x6698c 
ECX: 0xf761b420 --> 0x0 
EDX: 0x9714268 --> 0xf761b460 --> 0xf761b458 --> 0xf761b450 --> 0x9761f28 --> 0x68 ('h')
ESI: 0x0 
EDI: 0x9757d10 --> 0x0 
EBP: 0xffced7b8 --> 0xffceef58 --> 0xffceef88 --> 0xffceefb8 --> 0xffcef398 --> 0xffcff708 --> 0x0 
ESP: 0xffced770 --> 0x0 
EIP: 0xf72c1827 --> 0x38a08789
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xf72c181d:  shl    eax,1
   0xf72c181f:  mov    DWORD PTR [esp],eax
   0xf72c1822:  call   0xf727ff8c <DMC_malloc@plt>
=> 0xf72c1827:  mov    DWORD PTR [edi+0x38a0],eax
   0xf72c182d:  add    esp,0x10
   0xf72c1830:  test   eax,eax
   0xf72c1832:  jne    0xf72c1854
   0xf72c1834:  cmp    DWORD PTR [ebp-0x14],0x0
[------------------------------------stack-------------------------------------]
0000| 0xffced770 --> 0x0 
0004| 0xffced774 --> 0x0 
0008| 0xffced778 --> 0x164 
0012| 0xffced77c --> 0xf72c16d6 --> 0xaec3815b 
0016| 0xffced780 --> 0xf72e2a84 --> 0x6698c 
0020| 0xffced784 --> 0x9761fba --> 0x0 
0024| 0xffced788 --> 0xffced7b8 --> 0xffceef58 --> 0xffceef88 --> 0xffceefb8 --> 0xffcef398 --> 0xffcff708 --> 0x0 
0028| 0xffced78c --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
(rr) print malloc_usable_size($eax)
$149 = 0x14

So that means we have 0x14 bytes available for use. From line 64 to line 79 we see a while loop with a lot of writes into a1->fontTable. The range of these write operations is much bigger than the allocated buffer capacity which leads to heap corruption.

Crash Information

Starting program: /home/icewall/bugs/cvtofc/convert config_doc
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
input=/home/icewall/bugs/cvtofc/config_doc/toconv.doc
output=/home/icewall/bugs/cvtofc/config_doc/conv.html
type=1
info.options='0'
Return from GetFileInfo=0
HtmlInfo.GroupName=UTF-8
HtmlInfo.DefLangName=English
HtmlInfo.bBigEndian=0
HtmlInfo.options=0
HtmlInfo.SheetId=0
HtmlInfo.SlideId=0
HtmlInfo.lpFunc=(nil)
HtmlInfo.szImageFolder=
*** Error in `/home/icewall/bugs/cvtofc/convert': free(): invalid next size (fast): 0x08054480 ***

Program received signal SIGABRT, Aborted.
[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0x12d8 
ECX: 0x12d8 
EDX: 0x6 
ESI: 0x63 ('c')
EDI: 0xf7f08000 --> 0x1aada8 
EBP: 0xfffeaff8 --> 0xf7f08420 --> 0x0 
ESP: 0xfffead34 --> 0xfffeaff8 --> 0xf7f08420 --> 0x0 
EIP: 0xf7fdace0 (pop    ebp)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xf7fdacdc:  nop
   0xf7fdacdd:  nop
   0xf7fdacde:  int    0x80
=> 0xf7fdace0:  pop    ebp
   0xf7fdace1:  pop    edx
   0xf7fdace2:  pop    ecx
   0xf7fdace3:  ret    
   0xf7fdace4:  int3
[------------------------------------stack-------------------------------------]
0000| 0xfffead34 --> 0xfffeaff8 --> 0xf7f08420 --> 0x0 
0004| 0xfffead38 --> 0x6 
0008| 0xfffead3c --> 0x12d8 
0012| 0xfffead40 --> 0xf7d8b687 (xchg   ebx,edi)
0016| 0xfffead44 --> 0xf7f08000 --> 0x1aada8 
0020| 0xfffead48 --> 0xfffeade4 --> 0x0 
0024| 0xfffead4c --> 0xf7d8eab3 (mov    edx,DWORD PTR gs:0x8)
0028| 0xfffead50 --> 0x6 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGABRT
0xf7fdace0 in ?? ()
gdb-peda$ bt
#0  0xf7fdace0 in ?? ()
#1  0xf7dd04ba in malloc_printerr (action=<optimized out>, str=0xf7ec2e5c "free(): invalid next size (fast)", ptr=0x8054480) at malloc.c:4996
#2  0xf7dd112d in _int_free (av=0xf7f08420 <main_arena>, p=<optimized out>, have_lock=0x0) at malloc.c:3840
#3  0xf7cdbcd6 in DMC_free () from ./libdmc_comm.so
#4  0xf7cbe5c3 in FreeBuf () from ./libdhf_rdoc.so
#5  0xf7cc08e4 in Doc_Free () from ./libdhf_rdoc.so
#6  0xf7c8c22d in SimReadText () from ./libdhf_rdoc.so
#7  0xf7c6cc7f in DHF_ROpen () from ./libdhf_rdoc.so
#8  0xf7fd4766 in FilterToHtml () from ./libdhf_htmlif.so
#9  0xf7fd3afc in DHF_GetHtml_V11 () from ./libdhf_htmlif.so
#10 0x08049af8 in main ()
#11 0xf7d76af3 in __libc_start_main (main=0x8049730 <main>, argc=0x2, argv=0xffffd124, init=0x8049f70 <__libc_csu_init>, fini=0x8049f60 <__libc_csu_fini>, rtld_fini=0xf7feb160 <_dl_fini>, 
    stack_end=0xffffd11c) at libc-start.c:287
#12 0x08048ad1 in _start ()

gdb-peda$ exploitable -m
Warning: machine string printing is deprecated and may be removed in a future release.
EXCEPTION_FAULTING_ADDRESS:0x000000000012d8
EXCEPTION_CODE:0x6
FAULTING_INSTRUCTION:pop    ebp
MAJOR_HASH:33caf8673bdc21cb3af70d774abb6a6c
MINOR_HASH:8c348e78f980b542ffb23c540c3930ad
STACK_DEPTH:11
STACK_FRAME:[vdso]+0x0
STACK_FRAME:/lib/i386-linux-gnu/libc-2.19.so!malloc_printerr+0x0
STACK_FRAME:/lib/i386-linux-gnu/libc-2.19.so!_int_free+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/libdmc_comm.so!DMC_free+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/libdhf_rdoc.so!FreeBuf+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/libdhf_rdoc.so!Doc_Free+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/libdhf_rdoc.so!SimReadText+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/libdhf_rdoc.so!DHF_ROpen+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/libdhf_htmlif.so!FilterToHtml+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/libdhf_htmlif.so!DHF_GetHtml_V11+0x0
STACK_FRAME:/home/icewall/bugs/cvtofc/convert!main+0x0
INSTRUCTION_ADDRESS:0x000000f7fdace0
INVOKING_STACK_FRAME:0
DESCRIPTION:Heap error
SHORT_DESCRIPTION:HeapError (15/29)
OTHER_RULES:AbortSignal (27/29)
CLASSIFICATION:EXPLOITABLE
EXPLANATION:The target's backtrace indicates that libc has detected a heap error or that the target was executing a heap function when it stopped. This could be due to heap corruption, passing a bad pointer to a heap function such as free(), etc. Since heap errors might include buffer overflows, use-after-free situations, etc. they are generally considered exploitable.
Description: Heap error
Short description: HeapError (15/29)
Hash: 33caf8673bdc21cb3af70d774abb6a6c.8c348e78f980b542ffb23c540c3930ad
Exploitability Classification: EXPLOITABLE
Explanation: The target's backtrace indicates that libc has detected a heap error or that the target was executing a heap function when it stopped. This could be due to heap corruption, passing a bad pointer to a heap function such as free(), etc. Since heap errors might include buffer overflows, use-after-free situations, etc. they are generally considered exploitable.
Other tags: AbortSignal (27/29)

Timeline

2016-10-10 - Vendor Disclosure
2017-05-04 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.