php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #71498 Out-of-Bound Read in phar_parse_zipfile()
Submitted: 2016-02-02 16:48 UTC Modified: 2016-03-02 06:38 UTC
From: manhluat at vnsecurity dot net Assigned: stas
Status: Closed Package: PHAR related
PHP Version: 5.5.32 OS: Unix
Private report: No CVE-ID:
 [2016-02-02 16:48 UTC] manhluat at vnsecurity dot net
Description:
------------
There is a flaw was found in PHAR's phar_parse_zipfile() function.


--------------------------------
ext/phar/zip.c:

int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, char **error) /* {{{ */
{
	phar_zip_dir_end locator;
	char buf[sizeof(locator) + 65536];
...
	while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
		if (!memcmp(p + 1, "K\5\6", 3)) {
			memcpy((void *)&locator, (void *) p, sizeof(locator));
			if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
				/* split archives not handled */
				php_stream_close(fp);
				if (error) {
					spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
				}
				return FAILURE;
			}
...

--------------------------------

Sizeof(buf) equals 0x10016 (0x16 (sizeof[locator]) plus 65536)

The above code block tries to determine where is "PK\x05\x06" in buf. it is actually "End of central directory record" structure of zip file (https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html). Then it copies 0x16 bytes  from there to `phar_zip_dir_end locator`. 

What if "PK\x05\x06" signature is located at end of `buf` variable, it will read out-of-bound `buf` variable to copy to `locator`.

You can see details of debugging below.

* Note:
- PHP5 and PHP7 latest version are vulnerable.
- Works on Linux, Mac, Windows as well. I think
- It is possible to memory leak, crash, etc.


`poc.zip` can be downloaded here: https://drive.google.com/file/d/0B4qNn6UEDAR-V2ptcGlUR01DTjA/view?usp=sharing





Test script:
---------------

<?php 
$p = new PharData($argv[1]);
?>

Actual result:
--------------
You can see that I print out `p`,`locator`,`buf`,.. to let you imagine the stack layout. Finally, `locator` contains some pointer, memory, blah blah.







gdb-peda$ r
Starting program: /root/test/php-7.0.2/sapi/cli/php ./php-test/zip.php ./php-test/reproduce/poc.zip
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7ffffffe9440 ('b' <repeats 200 times>...)
RCX: 0x0 
RDX: 0x0 
RSI: 0x19 
RDI: 0x7b ('{')
RBP: 0x7fffffff9452 --> 0x3100000006054b50 
RSP: 0x7ffffffe8230 --> 0x0 
RIP: 0x50d28f (<phar_parse_zipfile+1167>:       movsx  ax,BYTE PTR [rbp+0x7])
R8 : 0x46 ('F')
R9 : 0x8e 
R10: 0x0 
R11: 0x0 
R12: 0x10016 
R13: 0x7ffff6474300 --> 0xdd8e80 --> 0x606090 (<php_stdiop_write>:      mov    rax,QWORD PTR [rdi+0x8])
R14: 0x0 
R15: 0x7ffff6474300 --> 0xdd8e80 --> 0x606090 (<php_stdiop_write>:      mov    rax,QWORD PTR [rdi+0x8])
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x50d283 <phar_parse_zipfile+1155>:  mov    BYTE PTR [rsp+0x60],al
   0x50d287 <phar_parse_zipfile+1159>:  movzx  eax,BYTE PTR [rbp+0x15]
   0x50d28b <phar_parse_zipfile+1163>:  mov    BYTE PTR [rsp+0x50],al
=> 0x50d28f <phar_parse_zipfile+1167>:  movsx  ax,BYTE PTR [rbp+0x7]
   0x50d294 <phar_parse_zipfile+1172>:  shl    eax,0x8
   0x50d297 <phar_parse_zipfile+1175>:  or     ax,r11w
   0x50d29b <phar_parse_zipfile+1179>:  jne    0x50d3c0 <phar_parse_zipfile+1472>
   0x50d2a1 <phar_parse_zipfile+1185>:  shl    ecx,0x8
[------------------------------------stack-------------------------------------]
0000| 0x7ffffffe8230 --> 0x0 
0008| 0x7ffffffe8238 --> 0x0 
0016| 0x7ffffffe8240 --> 0x0 
0024| 0x7ffffffe8248 --> 0x0 
0032| 0x7ffffffe8250 --> 0x7fffffffacf0 --> 0x0 
0040| 0x7ffffffe8258 --> 0x7ffff6471098 ("/root/test/php-test/reproduce/poc.zip")
0048| 0x7ffffffe8260 --> 0x0 
0056| 0x7ffffffe8268 --> 0x25 ('%')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, phar_parse_zipfile (fp=fp@entry=0x7ffff6474300, fname=fname@entry=0x7ffff6471098 "/root/test/php-test/reproduce/poc.zip", fname_len=fname_len@entry=0x25, alias=alias@entry=0x0, alias_len=alias_len@entry=0x0, 
    pphar=pphar@entry=0x7fffffffabe8, error=error@entry=0x7fffffffacf0) at /root/test/php-7.0.2/ext/phar/zip.c:204
204                             if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
gdb-peda$ print p
$12 = 0x7fffffff9452 "PK\005\006"
gdb-peda$ print p+0x16
$13 = 0x7fffffff9468 "\350\253\377\377\377\177"
gdb-peda$ print buf+0x10016
$14 = 0x7fffffff9456 ""
gdb-peda$ x/20gx $rbp+0x4 <--- locator
0x7fffffff9456: 0x7b198e4631000000      0x7ffff6474300a65d
0x7fffffff9466: 0x7fffffffabe80000      0x7fffffff96c00000
0x7fffffff9476: 0x7ffff64710980000      0x0000000004000000
0x7fffffff9486: 0x0000000000010000      0x7ffff64743000000
0x7fffffff9496: 0x00000051b0e20000      0x7fffffffacf00000
0x7fffffff94a6: 0x0000000000000000      0x0000000000000000
0x7fffffff94b6: 0x7fffffff96d20000      0x0000000000000000
0x7fffffff94c6: 0x0000000000000000      0x7fffffffacf00000
0x7fffffff94d6: 0x0000000000000000      0x7fffffff96a00000
0x7fffffff94e6: 0x7ffff64710980000      0x7fffffff96500000
gdb-peda$ 

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-02-17 16:48 UTC] manhluat at vnsecurity dot net
ping
 [2016-02-22 00:53 UTC] stas@php.net
fix in security repo as a6fdc5bb27b20d889de0cd29318b3968aabb57bd and in https://gist.github.com/acc83406aada4617a35d - please verify.
 [2016-02-22 00:53 UTC] stas@php.net
-Assigned To: +Assigned To: stas
 [2016-02-22 00:57 UTC] stas@php.net
-PHP Version: 5.6.17 +PHP Version: 5.5.32
 [2016-03-02 06:39 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=a6fdc5bb27b20d889de0cd29318b3968aabb57bd
Log: Fix bug #71498: Out-of-Bound Read in phar_parse_zipfile()
 [2016-03-02 06:39 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-03-02 06:56 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=a6fdc5bb27b20d889de0cd29318b3968aabb57bd
Log: Fix bug #71498: Out-of-Bound Read in phar_parse_zipfile()
 [2016-03-02 07:12 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=a6fdc5bb27b20d889de0cd29318b3968aabb57bd
Log: Fix bug #71498: Out-of-Bound Read in phar_parse_zipfile()
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Thu Jun 22 22:01:38 2017 UTC