}
可以看到error_log函数的核心就是 php_stream_open_wrapper()函数,问题也就出在保存错误信息的文件这一步,看下这个函数的语法:
php_stream * php_stream_open_wrapper ( char * path, char * mode, int options, char ** opened )
php_stream_open_wrapper() opens a stream on the file, URL or other wrapped resource specified by path.
r
Open text file for reading. The stream is positioned at the beginning of the file.
r+
Open text file for reading and writing. The stream is positioned at the beginning of the file.
w
Truncate the file to zero length or create text file for writing. The stream is positioned at the beginning of the file.
w+
Open text file for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.
a
Open for writing. The file is created if it does not exist. The stream is positioned at the end of the file.
a+
Open text file for reading and writing. The file is created if it does not exist. The stream is positioned at the end of the file.
error_log函数里定义了a选项,就是检查当保存错误信息文件不存在时创建一个,到这都没问题,关键是后面:
IGNORE_URL | ENFORCE_SAFE_MODE | REPORT_ERRORS
如果定义了一个IGNORE_URL那么将关闭后面的SAFE_MODE 开关,这样如果把错误信息写成代码,后面加上如prefix://../../的URL,则代码被写入到一个PHP文件时就已经绕过了SAFE_MODE 的限制,再访问保存错误信息的文件则代码被顺利无限制的执行了.
归根结底漏洞产生于php_stream_open_wrapper()函数,然后被嵌套调用了.
还有一个以前的的copy函数bypass漏洞
$temp=tempnam($tymczas, "cx");
if(copy("compress.zlib://".$file, $temp)){
$handle = fopen($temp, "r");
$tekst = fread($handle, filesize($temp));
fclose($handle);
通过这样一段利用代码再指定一个$file就可以绕过安全模式读取任何文件了
漏洞的存在都是互相映射的,应用层的漏洞在底层也会出现,就象上面这些逻辑类的,那应用层最容易疏忽的过滤不严的漏洞在底层会出现吗?当然!看看tempnam()函数中的一段核心代码:
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg1, &arg2) ==
FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(arg1);
convert_to_string_ex(arg2);
if (php_check_open_basedir(Z_STRVAL_PP(arg1) TSRMLS_CC)) {
RETURN_FALSE;
}
d = estrndup(Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1));
strlcpy(p, Z_STRVAL_PP(arg2), sizeof(p));