在这里推荐下自己的博客,支持友链互换,Back's Blog
本次防御从代码层面出发, 尽量从多个角度进行防御。不足之处请指出。谢谢。
黑名单检测防御
首先看下dvwa的远程文件包含页面源码(low级别)。
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
?>
可以看到没有经过任何的加固,远程文件包含利用的最大特点显而易见,就是http和https协议。
我们先进行漏洞利用,简单复现。远程文件包含需要在php.ini中打开allow_url_include。
这里我已经打开了allow_url_include
本地写好了一个测试文件。简单点。
进行远程文件包含测试,因为在本地测试,所以写在了同一个虚拟机下(懒得多开)
成功包含远程文件
这里进行加固,使用黑名单进行检测,若包含的代码中包含http、https则报错,并且退出执行。
加固之后代码如下
<?php
$file = $_GET[ 'page' ];
$black = array("https","http");
if(!in_array($file,$black)){
echo "危险操作!";
exit;
}
?>
进行远程文件包含测试
黑名单中,不仅可以添加协议,也可以添加敏感信息。如passwd、shadow、hosts等等,以进行防御本地文件包含。
str_replace()函数替换防御
加固代码如下,这里仅写了http用以测试
<?php
$file = $_GET[ 'page' ];
$file = str_replace("http","",$file);
?>
加固成功
但是这种加固是及其不安全的,因为str_replace()函数有一个特性,即仅会检测一次。如果我们构造出hthttptp这样的参数,它会替换掉中间的http,然后左右剩下的ht 和 tp 仍会构成一个新的http。
而str_replace()不会再次对此进行检测。从而达到绕过的目的。如下测试图。
过滤其他的诸如 https、http:// 等同样可以绕过。
不过对单字符就没办法了。因为只有一个字符,无法构造合成。如下
<?php
$file = $_GET[ 'page' ];
$file = str_replace("h","",$file);
?>
原则上没有什么问题,但是不建议如此过滤。不仅容易误伤,还容易造成其他错误。
strstr函数过滤防御
直接上代码吧。懒得多BB了。
<?php
$file = $_GET[ 'page' ];
if(strstr($file,"http")==true){
echo "危险操作";
exit;
}
?>
strstr()函数主要是进行了一个检测,没有对参数本身进行更改,所以不存在hthttptp的这种情况出现。
然后这里进行判断, 如果存在http则echo “危险操作”,并退出执行。
如果不退出,会是怎样的情景?看一下、我这里修改了下1.txt内容
可以看到,虽然输出危险操作,但是仍然将内容进行了执行并输出。
你以为这样就是安全的吗?
不,strstr()函数还有一个问题所在,就是它区分大小写。什么意思?就是小写过滤,但是大写不过滤。如下
应对措施也简单,将获得到的参数进行小写转换。使用strtolower()函数。
$file = strtolower($file);
如此即可
白名单检测防御
这种防御方法,即指定可包含文件,其他均不允许。此种方法和Impossible级别一样,只不过添加远程文件即可。
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
关于远程文件包含的主要加固方式,还是关闭php.ini中的allow_url_include()比较安全。
如果必须开启的话,要从代码层面进行加固。多层防护,一定要检测你所使用的加固函数是否可以绕过,以及相应的加固措施。