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); 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. |
Blog >