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 (profile)
Status: Closed Package: PHAR related
PHP Version: 5.5.32 OS: Unix
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: manhluat at vnsecurity dot net
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 17:01:29 2024 UTC