CVE-2016-1541
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.
libarchive 3.1.2
https://github.com/libarchive/libarchive
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
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.
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
2016-04-19 - Vendor Disclosure
2016-05-01 - Public Release
Discovered by Marcin ‘Icewall’ Noga of Cisco TALOS