Talos Vulnerability Report

TALOS-2016-0155

Libarchive zip zip_read_mac_metadata Code Execution Vulnerability

May 1, 2016
CVE Number

CVE-2016-1541

SUMMARY

An exploitable heap overflow vulnerability exists in the zip archive decompression functionality of libarchive. A specially crafted zip file can cause memory corruption leading to code execution. An attacker can send a malformed file to trigger this vulnerability.

TESTED VERSIONS

libarchive 3.1.2

PRODUCT URLS

https://github.com/libarchive/libarchive

CVSSv3 SCORE

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

DETAILS

Vulnerable code exists in zip support format module:

libarchive\archive_read_support_format_zip.c:
Line 2716   static int
Line 2717   zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
Line 2718       struct zip_entry *rsrc)
Line 2719   {
(...)
Line 2750   metadata = malloc((size_t)rsrc->uncompressed_size); // <--- NULL ALLOCATION
Line 2751   if (metadata == NULL) {
Line 2752       archive_set_error(&a->archive, ENOMEM,
Line 2753           "Can't allocate memory for Mac metadata");
Line 2754       return (ARCHIVE_FATAL);
Line 2755   }
(...)
Line 2766   remaining_bytes = (size_t)rsrc->compressed_size;
Line 2767   metadata_bytes = (size_t)rsrc->uncompressed_size;
Line 2768   mp = metadata;
Line 2769   eof = 0;
Line 2770   while (!eof && remaining_bytes) {
Line 2771       const unsigned char *p;
Line 2772       ssize_t bytes_avail;
Line 2773       size_t bytes_used;
Line 2774
Line 2775       p = __archive_read_ahead(a, 1, &bytes_avail);
Line 2776       if (p == NULL) {
Line 2777           archive_set_error(&a->archive,
Line 2778               ARCHIVE_ERRNO_FILE_FORMAT,
Line 2779               "Truncated ZIP file header");
Line 2780           ret = ARCHIVE_WARN;
Line 2781           goto exit_mac_metadata;
Line 2782       }
Line 2783       if ((size_t)bytes_avail > remaining_bytes)
Line 2784           bytes_avail = remaining_bytes;
Line 2785       switch(rsrc->compression) {
Line 2786       case 0:  /* No compression. */
Line 2787           memcpy(mp, p, bytes_avail);                 // <-- BUFFER OVERFLOW

Zip file created on Mac OSX can contain also special directory/files called resource fork : https://en.wikipedia.org/wiki/Resource_fork. In line 2750 we see that based on "uncompressed_size" field of resource entry is used for allocation of the "metadata" buffer. This value is not checked, so a zero sized buffer may be allocated.

Later on line 2787, the user controlled "compressed_size" field is copied into "mp" ("metadata") buffer. Depending on malloc implementation and heap state, malloc for size 0 will succeed and memory can be written outside the bounds of the undersized buffer. Attacker in this scenario can fully control amount and content of bytes used to overwrite.

CRASH INFORMATION

Valgrind Analysis:
==59137== Memcheck, a memory error detector
==59137== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==59137== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==59137== 
==59137== Invalid write of size 2
==59137==    at 0x402EED3: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==59137==    by 0x8080AE1: zip_read_mac_metadata (archive_read_support_format_zip.c:2795)
==59137==    by 0x8080F1F: archive_read_format_zip_seekable_read_header (archive_read_support_format_zip.c:2930)
==59137==    by 0x804E3C6: _archive_read_next_header2 (archive_read.c:645)
==59137==    by 0x804E47A: _archive_read_next_header (archive_read.c:683)
==59137==    by 0x8088A13: archive_read_next_header (archive_virtual.c:148)
==59137==    by 0x804A178: extract (ext.c:55)
==59137==    by 0x804A271: main (ext.c:83)
==59137==  Address 0x4459ae0 is 0 bytes after a block of size 0 alloc'd
==59137==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==59137==    by 0x808095C: zip_read_mac_metadata (archive_read_support_format_zip.c:2758)
==59137==    by 0x8080F1F: archive_read_format_zip_seekable_read_header (archive_read_support_format_zip.c:2930)
==59137==    by 0x804E3C6: _archive_read_next_header2 (archive_read.c:645)
==59137==    by 0x804E47A: _archive_read_next_header (archive_read.c:683)
==59137==    by 0x8088A13: archive_read_next_header (archive_virtual.c:148)
==59137==    by 0x804A178: extract (ext.c:55)
==59137==    by 0x804A271: main (ext.c:83)
==59137== 
==59137== Invalid write of size 1
==59137==    at 0x402F04B: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==59137==    by 0x8080AE1: zip_read_mac_metadata (archive_read_support_format_zip.c:2795)
==59137==    by 0x8080F1F: archive_read_format_zip_seekable_read_header (archive_read_support_format_zip.c:2930)
==59137==    by 0x804E3C6: _archive_read_next_header2 (archive_read.c:645)
==59137==    by 0x804E47A: _archive_read_next_header (archive_read.c:683)
==59137==    by 0x8088A13: archive_read_next_header (archive_virtual.c:148)
==59137==    by 0x804A178: extract (ext.c:55)
==59137==    by 0x804A271: main (ext.c:83)
==59137==  Address 0x4459b92 is not stack'd, malloc'd or (recently) free'd

TIMELINE

2016-04-19 - Vendor Disclosure
2016-05-01 - Public Release

Credit

Discovered by Marcin ‘Icewall’ Noga of Cisco TALOS