Background PHP has the built-in Phar & PharData functionality since 5.3.0. These are used to manipulate the following archive types: tar,zip & phar. I found this vulnerability through fuzzing. Technical Detail This is a standard BOF in phar_set_inode() @ phar_internal.h: static inline void phar_set_inode(phar_entry_info *entry TSRMLS_DC) /* {{{ */{ char tmp[MAXPATHLEN]; int tmp_len; tmp_len = entry->filename_len + entry->phar->fname_len; memcpy(tmp, entry->phar->fname, entry->phar->fname_len); memcpy(tmp + entry->phar->fname_len, entry->filename, entry->filename_len); entry->inode = (unsigned short)zend_get_hash_value(tmp, tmp_len);} The vulnerability occurs because it didn't check that tmp_len is < MAXPATHLEN. On my x64bits ubuntu MAXPATHLEN=0x1000. Exploiting the vulnerability is trivial since attacker controls entry->filename and entry->filename_len. The only thing to note is that since tmp_len is below tmp[] on the stack, when overwriting tmp_len, it needs to ensure that the value being overwritten with is within reasonable limits, otherwise it would crash when zend_get_hash_value() is called. There are multiple pathways to trigger this:
I've found that the easiest (read: boring) way to trigger it was via ZIP. The more interesting path would be via Tar for the following reasons:
Even though it validates the checksum (line 116), as long as the file ends with .tar (line 118), it would always pass the validation. Cheers PHP for being so lenient ;)
POC for exploits can be downloaded here. Written for:
Bug report can be found here |
Blog >