php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #72928 Out of bound when verify signature of zip phar in phar_parse_zipfile
Submitted: 2016-08-23 07:53 UTC Modified: 2016-09-16 13:39 UTC
From: nguyenvuhoang199321 at gmail dot com Assigned: stas (profile)
Status: Closed Package: PHAR related
PHP Version: 5.6.25 OS: ALL
Private report: No CVE-ID: 2016-7414
 [2016-08-23 07:53 UTC] nguyenvuhoang199321 at gmail dot com
Description:
------------
There was a security code in phar_parse_zipfile
```
sig = (char *) emalloc(entry.uncompressed_filesize);
read = php_stream_read(fp, sig, entry.uncompressed_filesize);
if (read != entry.uncompressed_filesize) {
	php_stream_close(sigfile);
	efree(sig);
	PHAR_ZIP_FAIL("signature cannot be read");
}
mydata->sig_flags = PHAR_GET_32(sig);
if (FAILURE == phar_verify_signature(sigfile,
	php_stream_tell(sigfile),
	mydata->sig_flags,
	sig + 8,
	entry.uncompressed_filesize - 8,
	fname,
	&mydata->signature,
	&mydata->sig_len,
	error)
	) {
```
There are no checking *entry.uncompressed_filesize* attacker can create a signature.bin with size less than 8 and then this value is passed to *phar_verify_signature* as sig_len as you can see `entry.uncompressed_filesize - 8` as result sig_len is overflow.
And the third param is sig buffer as you can see `sig + 8`, because *entry.uncompressed_filesize* is less than 8 by default emalloc will return 16 bytes this result may lead to heap out of bound.

phar zip file : https://drive.google.com/file/d/0B0D1DYQpkA9Ud3I2OFlfeFRqbEU/view?usp=sharing

Test script:
---------------
<?php
	$phar = new PharData('phars/signature.zip');
	var_dump($phar);
?>

Actual result:
--------------
This debug step i will show the malicious parse phar zip.
Set breakpoint at line 419 in zip.c

[----------------------------------registers-----------------------------------]
RAX: 0x4
RBX: 0x13
RCX: 0x0
RDX: 0x1a3
RSI: 0xf2cc38 ("/home/vagrant/Sources_Ext/audit/src/php7.0-7.0.8/ext/phar/zip.c")
RDI: 0x4
RBP: 0x7fffffffa870 --> 0x7fffffffadb0 --> 0x7fffffffae50 --> 0x7fffffffaec0 --> 0x7fffffffaf50 --> 0x7fffffffb040 --> 0x7fffffffb090 --> 0x7fffffffb0c0 --> 0x7fffffffb100 --> 0x7fffffffb210 --> 0x7fffffffd510 --> 0x7fffffffe890 --> 0x7fffffffe9e0 --> 0xa1a0a0 (<__libc_csu_init>:	push   r15)
RSP: 0x7ffffffea600 --> 0x7fffffffafa0 --> 0x0
RIP: 0x6ed786 (<phar_parse_zipfile+7788>:	call   0x911568 <_emalloc>)
R8 : 0x0
R9 : 0xf2cc38 ("/home/vagrant/Sources_Ext/audit/src/php7.0-7.0.8/ext/phar/zip.c")
R10: 0x5
R11: 0x206
R12: 0x42c280 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffeac0 --> 0x2
R14: 0x7ffff3e14030 --> 0x7ffff3e7e040 --> 0x9a66aa (<ZEND_DO_FCALL_SPEC_HANDLER>:	push   rbp)
R15: 0x7ffff3e7e040 --> 0x9a66aa (<ZEND_DO_FCALL_SPEC_HANDLER>:	push   rbp)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x6ed777 <phar_parse_zipfile+7773>:	mov    edx,0x1a3
   0x6ed77c <phar_parse_zipfile+7778>:	lea    rsi,[rip+0x83f4b5]        # 0xf2cc38
   0x6ed783 <phar_parse_zipfile+7785>:	mov    rdi,rax
=> 0x6ed786 <phar_parse_zipfile+7788>:	call   0x911568 <_emalloc>
   0x6ed78b <phar_parse_zipfile+7793>:	mov    QWORD PTR [rbp-0x101d0],rax
   0x6ed792 <phar_parse_zipfile+7800>:	mov    eax,DWORD PTR [rbp-0x10170]
   0x6ed798 <phar_parse_zipfile+7806>:	mov    edx,eax
   0x6ed79a <phar_parse_zipfile+7808>:	mov    rcx,QWORD PTR [rbp-0x101d0]
Guessed arguments:
arg[0]: 0x4
arg[1]: 0xf2cc38 ("/home/vagrant/Sources_Ext/audit/src/php7.0-7.0.8/ext/phar/zip.c")
arg[2]: 0x1a3
arg[3]: 0x0
arg[4]: 0x0
[------------------------------------stack-------------------------------------]
0000| 0x7ffffffea600 --> 0x7fffffffafa0 --> 0x0
0008| 0x7ffffffea608 --> 0x7fffffffaeb0 --> 0x0
0016| 0x7ffffffea610 --> 0x0
0024| 0x7ffffffea618 --> 0x2900000000 ('')
0032| 0x7ffffffea620 --> 0x7ffff3e70088 ("/vagrant_extend/audit/phars/signature.zip")
0040| 0x7ffffffea628 --> 0x7ffff3e5fa00 --> 0x12bf720 --> 0x8d6fc6 (<php_stdiop_write>:	push   rbp)
0048| 0x7ffffffea630 --> 0x0
0056| 0x7ffffffea638 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00000000006ed786	419				sig = (char *) emalloc(entry.uncompressed_filesize);
gdb-peda$ p entry.uncompressed_filesize
$20 = 0x4

I create signature.bin with size is 4, after that i will step to phar_verify_signature and you will see param is passed to phar_verify_signature.

[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffafa0 --> 0x0
RBX: 0x10
RCX: 0x7ffff3e710a8 --> 0x4
RDX: 0x10
RSI: 0x0
RDI: 0x7ffff3e5fb40 --> 0x12bf720 --> 0x8d6fc6 (<php_stdiop_write>:	push   rbp)
RBP: 0x7ffffffea5d0 --> 0x7fffffffa870 --> 0x7fffffffadb0 --> 0x7fffffffae50 --> 0x7fffffffaec0 --> 0x7fffffffaf50 --> 0x7fffffffb040 --> 0x7fffffffb090 --> 0x7fffffffb0c0 --> 0x7fffffffb100 --> 0x7fffffffb210 --> 0x7fffffffd510 --> 0x7fffffffe890 --> 0x7fffffffe9e0 --> 0xa1a0a0 (<__libc_csu_init>:	push   r15)
RSP: 0x7ffffffea000 --> 0x7fffffffafa0 --> 0x0
RIP: 0x6e3c77 (<phar_verify_signature+85>:	mov    rax,QWORD PTR fs:0x28)
R8 : 0xfffffffc
R9 : 0x7ffff3e70088 ("/vagrant_extend/audit/phars/signature.zip")
R10: 0x4
R11: 0x246
R12: 0x7ffff3e710a8 --> 0x4
R13: 0x7ffff3e79120 --> 0x0
R14: 0x7ffff3e79118 --> 0x0
R15: 0xfffffffc
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x6e3c65 <phar_verify_signature+67>:	mov    QWORD PTR [rbp-0x5c8],rax
   0x6e3c6c <phar_verify_signature+74>:	mov    rax,QWORD PTR [rbp+0x20]
   0x6e3c70 <phar_verify_signature+78>:	mov    QWORD PTR [rbp-0x5d0],rax
=> 0x6e3c77 <phar_verify_signature+85>:	mov    rax,QWORD PTR fs:0x28
   0x6e3c80 <phar_verify_signature+94>:	mov    QWORD PTR [rbp-0x8],rax
   0x6e3c84 <phar_verify_signature+98>:	xor    eax,eax
   0x6e3c86 <phar_verify_signature+100>:	mov    rax,QWORD PTR [rbp-0x598]
   0x6e3c8d <phar_verify_signature+107>:	mov    edx,0x0
[------------------------------------stack-------------------------------------]
0000| 0x7ffffffea000 --> 0x7fffffffafa0 --> 0x0
0008| 0x7ffffffea008 --> 0x7ffff3e79118 --> 0x0
0016| 0x7ffffffea010 --> 0x7ffff3e79120 --> 0x0
0024| 0x7ffffffea018 --> 0x7ffff3e70088 ("/vagrant_extend/audit/phars/signature.zip")
0032| 0x7ffffffea020 --> 0x7ffff3e710a8 --> 0x4
0040| 0x7ffffffea028 --> 0x10fffffffc
0048| 0x7ffffffea030 --> 0x0
0056| 0x7ffffffea038 --> 0x7ffff3e5fb40 --> 0x12bf720 --> 0x8d6fc6 (<php_stdiop_write>:	push   rbp)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 11, phar_verify_signature (fp=0x7ffff3e5fb40, end_of_phar=0x0,
    sig_type=0x10, sig=0x7ffff3e710a8 "\004", sig_len=0xfffffffc,
    fname=0x7ffff3e70088 "/vagrant_extend/audit/phars/signature.zip",
    signature=0x7ffff3e79120, signature_len=0x7ffff3e79118, error=0x7fffffffafa0)
    at /home/vagrant/Sources_Ext/audit/src/php7.0-7.0.8/ext/phar/util.c:1484
1484	{

As you can see both value sig and sig_len may lead to heap out of bound

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-09-05 05:11 UTC] stas@php.net
-Assigned To: +Assigned To: stas
 [2016-09-05 05:11 UTC] stas@php.net
The fix is in security repo as 19484ab77466f99c78fc0e677f7e03da0584d6a2 and in https://gist.github.com/e091b2255c6d071e7be49828a5e39944

please verify
 [2016-09-05 06:50 UTC] nguyenvuhoang199321 at gmail dot com
well this bug is fixed
 [2016-09-06 00:11 UTC] stas@php.net
-CVE-ID: +CVE-ID: needed
 [2016-09-12 07:48 UTC] stas@php.net
-PHP Version: 7.0Git-2016-08-23 (Git) +PHP Version: 5.6.25
 [2016-09-13 04:04 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=223266e4e46b9188353db93771369078c2e94353
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 [2016-09-13 04:04 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-09-13 04:06 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=0bfb970f43acd1e81d11be1154805f86655f15d5
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 [2016-09-13 04:09 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=0bfb970f43acd1e81d11be1154805f86655f15d5
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 [2016-09-13 04:11 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=0bfb970f43acd1e81d11be1154805f86655f15d5
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 [2016-09-13 09:02 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=223266e4e46b9188353db93771369078c2e94353
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 [2016-09-15 09:30 UTC] tyrael@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=dd69327ad783ea93f1e0a9e358974c7b098f29cc
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 [2016-09-16 13:39 UTC] kaplan@php.net
-CVE-ID: needed +CVE-ID: 2016-7414
 [2016-10-17 10:08 UTC] bwoebi@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=223266e4e46b9188353db93771369078c2e94353
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 [2016-10-17 10:08 UTC] bwoebi@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=0bfb970f43acd1e81d11be1154805f86655f15d5
Log: Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 08:01:29 2024 UTC