php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #73035 Out of bound when verify signature of tar phar in phar_parse_tarfile
Submitted: 2016-09-06 21:02 UTC Modified: 2016-09-13 04:03 UTC
From: nguyenvuhoang199321 at gmail dot com Assigned: stas
Status: Closed Package: PHAR related
PHP Version: 5.6.25 OS: ALL
Private report: No CVE-ID:
 [2016-09-06 21:02 UTC] nguyenvuhoang199321 at gmail dot com
Description:
------------
There was a security code in phar_parse_tarfile
```
if (FAILURE == phar_verify_signature(fp, php_stream_tell(fp) - size - 512, myphar->sig_flags, buf + 8, size - 8, fname, &myphar->signature, &myphar->sig_len, error)) {
	if (error) {
		char *save = *error;
		spprintf(error, 4096, "phar error: tar-based phar \"%s\" signature cannot be verified: %s", fname, save);
		efree(save);
		}
	goto bail;
}
```
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.

tarfile : https://drive.google.com/open?id=0B0D1DYQpkA9UVkV1Q0tTeGpVYk0

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

Actual result:
--------------
This debug steps I will show the malicious parse phar tarfile.
Set breakpoint at line 266 in tar.c
[----------------------------------registers-----------------------------------]
RAX: 0x4
RBX: 0x0
RCX: 0x0
RDX: 0xb ('\x0b')
RSI: 0xc ('\x0c')
RDI: 0x7fffffffa6ec ("00000000004")
RBP: 0x7fffffffa8b0 --> 0x7fffffffae00 --> 0x7fffffffaea0 --> 0x7fffffffaf10 --> 0x7fffffffafa0 --> 0x7fffffffb090 --> 0x7fffffffb0e0 --> 0x7fffffffb110 --> 0x7fffffffb150 --> 0x7fffffffb260 --> 0x7fffffffd560 --> 0x7fffffffe8e0 --> 0x7fffffffea30 --> 0xa1a0a0 (<__libc_csu_init>:  	push   r15)
RSP: 0x7fffffffa400 --> 0x7fffffffaff0 --> 0x0
RIP: 0x6e67b5 (<phar_parse_tarfile+1101>:      	cmp    DWORD PTR [rbp-0x468],0x0)
R8 : 0xf2b910 ("/home/vagrant/Sources_Ext/audit/src/php7.0-7.0.8/ext/phar/tar.c")
R9 : 0xf4
R10: 0x180
R11: 0x7ffff67e2730 --> 0xfffda400fffda12f
R12: 0x42c280 (<_start>:       	xor    ebp,ebp)
R13: 0x7fffffffeb10 --> 0x2
R14: 0x7ffff3e14030 --> 0x7ffff3e7d040 --> 0x9a66aa (<ZEND_DO_FCALL_SPEC_HANDLER>:     	push   rbp)
R15: 0x7ffff3e7d040 --> 0x9a66aa (<ZEND_DO_FCALL_SPEC_HANDLER>:	push   rbp)
EFLAGS: 0x297 (CARRY PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x6e67a3 <phar_parse_tarfile+1083>: 	mov    DWORD PTR [rbp-0x3f0],eax
   0x6e67a9 <phar_parse_tarfile+1089>: 	mov    eax,DWORD PTR [rbp-0x3f0]
   0x6e67af <phar_parse_tarfile+1095>: 	mov    DWORD PTR [rbp-0x47c],eax
=> 0x6e67b5 <phar_parse_tarfile+1101>: 	cmp    DWORD PTR [rbp-0x468],0x0
   0x6e67bc <phar_parse_tarfile+1108>: 	jne    0x6e67fd <phar_parse_tarfile+1173>
   0x6e67be <phar_parse_tarfile+1110>: 	mov    rax,QWORD PTR [rbp-0x438]
   0x6e67c5 <phar_parse_tarfile+1117>: 	movzx  eax,BYTE PTR [rax+0x9c]
   0x6e67cc <phar_parse_tarfile+1124>: 	cmp    al,0x67
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffa400 --> 0x7fffffffaff0 --> 0x0
0008| 0x7fffffffa408 --> 0x7fffffffaf00 --> 0x0
0016| 0x7fffffffa410 --> 0x0
0024| 0x7fffffffa418 --> 0x2900000000 ('')
0032| 0x7fffffffa420 --> 0x7ffff3e75018 ("/vagrant_extend/audit/phars/signature.tar")
0040| 0x7fffffffa428 --> 0x7ffff3e5fa00 --> 0x12bf720 --> 0x8d6fc6 (<php_stdiop_write>:	push   rbp)
0048| 0x7fffffffa430 --> 0x4f665eff8
0056| 0x7fffffffa438 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
270    			if (!old && (hdr->typeflag == TAR_GLOBAL_HDR || hdr->typeflag == TAR_FILE_HDR)) {
gdb-peda$ p size
$3 = 0x4
You see here size is only 4 bytes. 
Set breakpoint before phar_verify_signature at line 304, and then continue
[----------------------------------registers-----------------------------------]
RAX: 0x7ffff3e5fa00 --> 0x12bf720 --> 0x8d6fc6 (<php_stdiop_write>:    	push   rbp)
RBX: 0x7fffffffa678 ("gnature.bin")
RCX: 0x7fffffffa678 ("gnature.bin")
RDX: 0x10
RSI: 0x0
RDI: 0x7ffff3e5fa00 --> 0x12bf720 --> 0x8d6fc6 (<php_stdiop_write>:    	push   rbp)
RBP: 0x7fffffffa8b0 --> 0x7fffffffae00 --> 0x7fffffffaea0 --> 0x7fffffffaf10 --> 0x7fffffffafa0 --> 0x7fffffffb090 --> 0x7fffffffb0e0 --> 0x7fffffffb110 --> 0x7fffffffb150 --> 0x7fffffffb260 --> 0x7fffffffd560 --> 0x7fffffffe8e0 --> 0x7fffffffea30 --> 0xa1a0a0 (<__libc_csu_init>:  	push   r15)
RSP: 0x7fffffffa3e0 --> 0x7ffff3e79120 --> 0x0
RIP: 0x6e6a0e (<phar_parse_tarfile+1702>:      	call   0x6e3c22 <phar_verify_signature>)
R8 : 0xfffffffc
R9 : 0x7ffff3e75018 ("/vagrant_extend/audit/phars/signature.tar")
R10: 0x7ffff6794150 (<__strncmp_sse42+3728>:   	pslldq xmm2,0x1)
R11: 0x0
R12: 0x10
R13: 0x7ffff3e79120 --> 0x0
R14: 0x7ffff3e79118 --> 0x0
R15: 0xfffffffc
EFLAGS: 0x212 (carry parity ADJUST zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x6e6a05 <phar_parse_tarfile+1693>: 	mov    rcx,rbx
   0x6e6a08 <phar_parse_tarfile+1696>: 	mov    edx,r12d
   0x6e6a0b <phar_parse_tarfile+1699>: 	mov    rdi,rax
=> 0x6e6a0e <phar_parse_tarfile+1702>: 	call   0x6e3c22 <phar_verify_signature>
   0x6e6a13 <phar_parse_tarfile+1707>: 	add    rsp,0x20
   0x6e6a17 <phar_parse_tarfile+1711>: 	cmp    eax,0xffffffff
   0x6e6a1a <phar_parse_tarfile+1714>: 	jne    0x6e6a9a <phar_parse_tarfile+1842>
   0x6e6a1c <phar_parse_tarfile+1716>: 	cmp    QWORD PTR [rbp-0x4b0],0x0
Guessed arguments:
arg[0]: 0x7ffff3e5fa00 --> 0x12bf720 --> 0x8d6fc6 (<php_stdiop_write>: 	push   rbp)
arg[1]: 0x0
arg[2]: 0x10
arg[3]: 0x7fffffffa678 ("gnature.bin")
arg[4]: 0xfffffffc
arg[5]: 0x7ffff3e75018 ("/vagrant_extend/audit/phars/signature.tar")
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffa3e0 --> 0x7ffff3e79120 --> 0x0
0008| 0x7fffffffa3e8 --> 0x7ffff3e79118 --> 0x0
0016| 0x7fffffffa3f0 --> 0x7fffffffaff0 --> 0x0
0024| 0x7fffffffa3f8 --> 0x6e69cb (<phar_parse_tarfile+1635>:  	mov    rdx,rax)
0032| 0x7fffffffa400 --> 0x7fffffffaff0 --> 0x0
0040| 0x7fffffffa408 --> 0x7fffffffaf00 --> 0x0
0048| 0x7fffffffa410 --> 0x0
0056| 0x7fffffffa418 --> 0x2900000000 ('')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00000000006e6a0e     	305    				if (FAILURE == phar_verify_signature(fp, php_stream_tell(fp) - size - 512, myphar->sig_flags, buf + 8, size - 8, fname, &myphar->signature, &myphar->sig_len, error)) {

As you can see because siglen is calculated by subtract size by 8 so as result this value is negative number in signed int or large int number in unsigned int. This mistake may lead to heap out of bound




Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-09-12 04:27 UTC] stas@php.net
Looks like the same as #72928 but for tar.
 [2016-09-12 04:30 UTC] nguyenvuhoang199321 at gmail dot com
Ok this is the same issue :) but happened in tar parsing
 [2016-09-12 04:38 UTC] stas@php.net
-PHP Version: 7.0.10 +PHP Version: 5.6.25 -Assigned To: +Assigned To: stas
 [2016-09-12 04:38 UTC] stas@php.net
The fix is in security repo as 75ebf471ff46ec6e5ee279b3650c11d51ebaf9e3 and in https://gist.github.com/87af366f29a5a5733f06389a3dfb5e60

please verify
 [2016-09-12 06:30 UTC] nguyenvuhoang199321 at gmail dot com
well bug is fixed thank :)
 [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=f5a9592ad8d2b60cabbaff00662477528ecefb48
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 [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=c5f34c9eca28769a3cc385501ee55bf153028dc4
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 [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=c5f34c9eca28769a3cc385501ee55bf153028dc4
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 [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=c5f34c9eca28769a3cc385501ee55bf153028dc4
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 [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=f5a9592ad8d2b60cabbaff00662477528ecefb48
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 [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=71a6cff185e26d2806b551d4022e766421d3b275
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 [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=f5a9592ad8d2b60cabbaff00662477528ecefb48
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 [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=c5f34c9eca28769a3cc385501ee55bf153028dc4
Log: Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Wed Feb 22 20:01:42 2017 UTC