Blog‎ > ‎

CVE-2015-2331: ZIP Integer Overflow Root Cause Analysis

posted Apr 1, 2015, 12:52 AM by Emmanuel Law   [ updated Apr 1, 2015, 3:23 AM]
I was fuzzing PHP zip extension and found the first crash on the 28th day. Sure took me a while.

The vulnerability is an integer overflow when parsing Zip64 on zip_dirent.c:113:

else if ((cd->entry=(struct zip_entry *)malloc(sizeof(*(cd->entry))*(size_t)nentry)) == NULL) {

nentry is obtained from the zip file.  On my x64, sizeof(*(cd->entry)) = 0x20 bytes long. Thus when nentry > 0x7FFFFFFFFFFFFFF, this will results in an integer overflow and malloc will allocate less memory then required.

Further down in zip_dirent.c:119

for (i=0; i<nentry; i++)	_zip_entry_init(cd->entry+i);

_zip_entry_init() will enter a loop to write stuff on the allocated memory. This goes on and on until it overwrites the allocated memory on the heap. 

The most likely reason it took 28 days of fuzzing to find this is because of zip_open.c:113

    /* number of cdir-entries on this disk */    i = _zip_read2(&cdp);    /* number of cdir-entries */    nentry = _zip_read2(&cdp);    if (nentry != i) {	_zip_error_set(error, ZIP_ER_NOZIP, 0);

i = total number of entries in the central directory on this disk
nentry = total number of entries in the central directory

Random bit flipping will need to flip the both the i and nentry field to the same overflow values before going down the crash path.

After reporting this bug, I realized that it has a wider implication as this is a bug in libzip.  PHP is naturally affected as it has a embedded (and modified) version of libzip in it's code.

Full bug report can be found here.