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