文件包含就是将一个文件包含进来,为了方便开发,避免重复写多处都要使用的代码。而一般再CTF中看到?file=xxxx的时候就要下意识想到文件包含。 文件包含有两种,一个是本地文件,另一个是远程文件包含。

本地文件包含

本地文件包含呢需要了解一些经常用到的文件路径,如下:

/flag //flag路径

/etc/passwd //Linux存放用户名的文件

/home/xxx/.bash_history /用户命令记录

/var/log/auth.log //ssh日志

在题目中呢就可以将这些路径带进去尝试,但要先判断它的代码是什么样的

include($_GET['file']);

include('/var/www/html/'.$_GET['file']);

这两行代码不同点就在于,第二行会自己拼接一段文件路径,在尝试过程中如果没有文件该有的内容或是报错,就要考虑是不是第二行的代码,此时要用../去跳目录读取。 这种本地文件包含漏洞一般都会与文件上传漏洞相结合来考察,也会和其他方法结合,具体遇到题目再进行学习积累。

远程文件包含

远程文件包含的条件就有些刁钻了,他需要配置文件中allow_url_include开关是打开的状态,现在一般也不会有人会把这个开关打开,所以也只能在一些特定环境中利用了。常用的就像http、ftp协议等去包含远程服务器的文件,例如?file=http://url/xx/file。

常用的伪协议

上面呢当然只是基础,伪协议才是CTF中经常会用到的。

file:// 用来读取本地文件,后面跟文件的绝对路径和文件名php://filter 是一种元封装器,用于数据流打开的筛选过滤应用。基本语法:php://filter/read(write)=过滤器名称/resource=文件路径 常用的过滤器呢就有convert.Base64-encode,题目给提示的话,就可以利用这个过滤器将文件内容进行base64加密后显示在页面上,然后通过解密就能得到文件内容很好用,但是有些题目会检测base64字样,那就可以更换其他过滤器如:convert.iconv.utf-8.utf-7(实现从utf-8到utf-7的转换)、convert.quoted-printable-encode等phar:// 可以用来访问压缩包内的文件,经常与文件上传漏洞结合使用,只要文件为压缩包结构,不管文件后缀是什么,就能访问。zip://、bzip2://、zlib:// 效果和phar://协议一样,但这里的伪协议需要知道文件的绝对路径,访问压缩包内文件的分隔符为#,所以很难使用data:// 这个协议也需要allow_url_include与allow_url_fopen开关打开,这个协议通常用来传递数据 用法:data://text/plain,、data://text/plain,base64,hdhdhd。将我们想要传入的数据进行包含php://input 我们可以利用这个伪协议,将我们想传入的内容放在POST中data部分,这样就能被包含。

例题 [BJDCTF2020]ZJCTF,不过如此

下面我们就看一下这道题 打开题目,页面上就一份代码,顺便查看以下页面源代码,什么都没有,那就分析以下代码吧

error_reporting(0);

$text = $_GET["text"];

$file = $_GET["file"];

if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){ //读取$text变量传入的文件名,内容要是I have a dream

echo "

".file_get_contents($text,'r')."


"; //输出文件内容

if(preg_match("/flag/",$file)){ //匹配flag字段

die("Not now!");

}

include($file); //next.php 包含$file文件,同时也给了一个提示

}

else{

highlight_file(__FILE__);

}

?>

我们上面刚看过data伪协议可以传入内容,那么I have a dream那里就很容易通过了,后面就没思路了。既然提示了next.php,那么我们就尝试看一下吧。

?text=data://text/plain,I have a dream&file=php://filter/read=convert.base64-encode/resource=next.php

base64解密之后就得到下面的代码

$id = $_GET['id'];

$_SESSION['id'] = $id;

function complex($re, $str) { //定义一个函数,里面是一个正则

return preg_replace(

'/(' . $re . ')/ei',

'strtolower("\\1")',

$str

);

}

foreach($_GET as $re => $str) { //变量覆盖中提到过的foreach函数

echo complex($re, $str). "\n";

}

function getFlag(){ //我们想调用的函数

@eval($_GET['cmd']);

}

这里面先定义了一个函数,然后在foreach函数中被调用,正则使用的是preg_replace,经过了解知道这个函数的/e模式有命令执行漏洞,而且也是PHP独有的模式;另外一个搞不懂的就是\\1这个东西,查看其他大佬讲解明白了,这是一个反向引用,在它两边添加括号后,会将匹配到的存放在一个临时缓冲区中,并且编号从1开始,缓冲区里的内容可以通过'\n'来访问,n表示缓冲区编号。

详细相关可以看这篇文章php preg_replace /e 模式 漏洞分析

后面对于现在的我来说有点太复杂了,就只能先到这里了,以后再来解决这道题。

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: