GaRY's Blog

Beginning is always beautiful

PHP 5.2.0 session.save_path safe_mode and open_basedir bypass

这个漏洞让我想起来以前发现的一个php的小问题。想想用在这里倒是很适用:

唯一让我感兴趣的是 , 在测试session相关函数的时候 . 发现通过修改cookie里的session_id可以在session目录下写新文件并控制文件名为 " sess_ " + $session_id  这样的形式 . 如果能再控制一个写到session_data的变量 , 或许能有所作用 . ( $session_id  有字符限制 , 只允许大小写字母 , 还有 " - " " , " 字符 . 并且不能超过php所在系统的文件名长度限制)

同样的
, 如果我已经得到了一个webshell , 利用session_save_path以及session_set_save_handler , 我们可以在允许的任意目录里以进程的权限写任意文件 , 并没有文件名和内容上的任何限制 . 也许这个能在disable了file相关function时能有用 . PHP - 5.0 . 4版本前的session_save_path甚至能绕过open_basedir在任意有权限的地方写文件


  Topic : PHP 5.2.0 session.save_path safe_mode and open_basedir bypass
  SecurityAlert Id : 43
  SecurityRisk : High
  Remote Exploit : No
  Local Exploit : Yes
  Exploit Given : No
  Credit : Maksymilian Arciemowicz
  Date : 8.12.2006

  Affected Software :  PHP 5.2.0


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

[PHP 5.2.0 session.save_path safe_mode and open_basedir bypass]


Author: Maksymilian Arciemowicz (SecurityReason)
Date:
- - Written: 02.10.2006
- - Public: 08.12.2006
SecurityAlert Id: 43
CVE: CVE-2006-6383
SecurityRisk: High
Affected Software: PHP 5.2.0
Advisory URL: http://securityreason.com/achievement_securityalert/43
Vendor: http://www.php.net

- --- 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.

A nice introduction to PHP by Stig Sather Bakken can be found at
http://www.zend.com/zend/art/intro.php on the Zend website. Also, much of the PHP Conference
Material is freely available.

Session support in PHP consists of a way to preserve certain data across subsequent accesses.
This enables you to build more customized applications and increase the appeal of your web
site.

A visitor accessing your web site is assigned a unique id, the so-called session id. This is
either stored in a cookie on the user side or is propagated in the URL.

session.save_path defines the argument which is passed to the save handler. If you choose the
default files handler, this is the path where the files are created. Defaults to /tmp. See
also session_save_path().

There is an optional N argument to this directive that determines the number of directory
levels your session files will be spread around in. For example, setting to '5;/tmp' may end
up creating a session file and location like
/tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If . In order to use N you must create
all of these directories before use. A small shell script exists in ext/session to do this,
it's called mod_files.sh. Also note that if N is used and greater than 0 then automatic
garbage collection will not be performed, see a copy of php.ini for further information.
Also, if you use N, be sure to surround session.save_path in "quotes" because the
separator (;) is also used for comments in php.ini.

- --- 1. session.save_path safe mode and open basedir bypass ---
session.save_path can be set in ini_set(), session_save_path() function. In session.save_path
there must be path where you will save yours tmp file. But syntax for session.save_path can
be:

[/PATH]

OR

[N;/PATH]

N - can be a string.

EXAMPLES:

1 .   session_save_path ( " /DIR/WHERE/YOU/HAVE/ACCESS " )

2 .   session_save_path ( " 5;/DIR/WHERE/YOU/HAVE/ACCESS " )

and

3 . session_save_path ( " /DIR/WHERE/YOU/DONT/HAVE/ACCESS\0;/DIR/WHERE/YOU/HAVE/ACCESS " )

- -1477-1493--- Code from PHP520 ext/session/session.c [START]
PHP_FUNCTION( session_save_path )
{
zval 
**
p_name;
int ac 
=
 ZEND_NUM_ARGS();
char 
*
old;

if  (ac  <   0   ||  ac  >   1   ||  zend_get_parameters_ex(ac ,   & p_name)  ==
 FAILURE)
WRONG_PARAM_COUNT;

old 
=
 estrdup(PS(save_path));

if  (ac  ==   1
) {
convert_to_string_ex(p_name);
zend_alter_ini_entry(
" session.save_path " ,   sizeof ( " session.save_path " ) ,

Z_STRVAL_PP(p_name)
,  Z_STRLEN_PP(p_name) ,  PHP_INI_USER ,  PHP_INI_STAGE_RUNTIME);
}

RETVAL_STRING(old
,   0
);
}
- -1477-1493--- Code from PHP520 ext/session/session.c [END]

Values are set to hash_memory (but before that, safe_mode and open_basedir check this
value).
And if you are starting session (for example session_start()), that value from
session.save_path is checked by function PS_OPEN_FUNC(files).

- -242-300--- Code from PHP520 ext/session/mod_files.c [START]
PS_OPEN_FUNC(files)
{
ps_files 
*
data;
const  char  * p ,   *
last;
const  char  * argv[ 3
];
int argc 
=   0
;
size_t dirdepth 
=   0
;
int filemode 
=   0600
;

if  ( * save_path  ==   ' \0 '
) {
/*  if save path is an empty string, determine the temporary dir  */

save_path 
=  php_get_temporary_directory();
}

/*  split up input parameter  */

last 
=  save_path;
=   strchr (save_path ,   ' ; '
);
while
 (p) {
argv[argc
++ =
 last;
last 
=   ++
p;
=   strchr (p ,   ' ; '
);
if  (argc  >   1 break
;
}
argv[argc
++ =
 last;

if  (argc  >   1
) {
errno 
=   0
;
dirdepth 
=  (size_t) strtol(argv[ 0 ] ,   NULL ,   10
);
if  (errno  ==
 ERANGE) {
php_error(
E_WARNING ,
 
" The first parameter in session.save_path is invalid "
);
return
 FAILURE;
}
}

if  (argc  >   2
) {
errno 
=   0
;
filemode 
=  strtol(argv[ 1 ] ,   NULL ,   8
);
if  (errno  ==  ERANGE  ||  filemode  <   0   ||  filemode  >   07777
) {
php_error(
E_WARNING ,
 
" The second parameter in session.save_path is invalid "
);
return
 FAILURE;
}
}
save_path 
=  argv[argc  -   1
];

data 
=  emalloc( sizeof ( *
data));
memset(data
,   0 ,   sizeof ( *
data));

data
-> fd  =   - 1
;
data
-> dirdepth  =
 dirdepth;
data
-> filemode  =
 filemode;
data
-> basedir_len  =   strlen
(save_path);
data
-> basedir  =  estrndup(save_path ,  data ->
basedir_len);

PS_SET_MOD_DATA(data);

return
 SUCCESS;
}
- -242-300--- Code from PHP520 ext/session/mod_files.c [END]

Because in session.save_path there is a NULL byte before ";", strchr() doesn't see
";" and path is /DIR/WHERE/YOU/DONT/HAVE/ACCESS.

Problem exists because safe_mode and open_basedir check what is after ;. And it is needed to
set correct path after ";".

- --- 2. How to fix ---
http://cvs.php.net/viewcvs.cgi/php-src/NEWS

- --- 3. Greets ---

For: sp3x
and
l5x, p_e_a, lorddav, pi3

- --- 4. Contact ---
Author: SecurityReason.Com [ Maksymilian Arciemowicz ( cXIb8O3 ) ]
Email: cxib [at] securityreason [dot] com
GPG: http://securityreason.com/key/Arciemowicz.Maksymilian.gpg

Regards
SecurityReason

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (FreeBSD)

iD8DBQFFedKL3Ke13X/fTO4RAms1AKCTSc8CNZmHWhXvOdjtTBcIgdHTuwCgkvrz
9KnewH0rOVFfmPRx2f1x5W4=
=YAP9
-----END PGP SIGNATURE-----

posted on 2006-12-09 12:10 wofeiwo 阅读(1083) 评论(0)  编辑 收藏 引用 网摘 所属分类: PHP corePHP security


只有注册用户登录后才能发表评论。
网站导航:

导航

<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

统计

留言簿(10)

随笔分类(90)

随笔档案(61)

搜索

最新随笔

最新评论