一、文件包含漏洞产生的原因
1.什么是文件包含?
为了更好的使用代码的重用性,引入了文件包含函数,可以通过文件包含函数将文件包含进来, 直接使用包含文件的代码。
2.什么是文件包含漏洞?
在包含文件时候,为了灵活包含文件,将被包含文件设置为变量,通过动态变量来引入需要包含的文件时,用户可以对变量的值可控而服务器端未对变量值进行合理地校验或者校验被绕过,这样就导致了文件包含漏洞。通常文件包含漏洞出现在PHP语言中。
<?php
$file = $_GET['file']; //从GET方法里获取参数file的值,将它赋值给定义的变量file
include($file): //调用include函数去查看变量file对应的文件的内容
3.函数
这里的函数说的是PHP中的函数。
1.文件包含函数:
include() 、include_once()、require()、require_once():包含并运行指定文件。
include和require的区别:
两者在包含文件的结构上完全一样,唯一的区别是对于错误的处理。
当在遇到包含文件不存在,或是出错的时候,include会继续向下执行,而require会立即停止执行,并报错。
once的作用:
在脚本执行期间同一个文件有可能被包含超过一次的情况下,使用once就的话就只会包含一次,以避免函数重定义、变量重新赋值等问题。
2.文件读取函数:
highlight_file、show_source:读取文件并进行语法高亮显示。
readfile:读入一个文件并写入到输出缓冲。
file_get_contents:将文件的内容读入到一个字符串中,可以读取远程文件。
fopen() :打开文件或者 URL。
file() :把整个文件读入一个数组中。
4.文件包含漏洞分类
1.本地文件包含
2.远程文件包含(允许将URL (如http: //或ftp: //)作为文件处理)
在php.ini配置文件中有两个设置与文件包含漏洞有关,需要了解一下:
- allow_url_fopen:
为ON时,能读取远程文件,例如file_get_contents()就能读远程文件 - allow_url_include:
为ON时,就可使用include和require等方式包含远程文件,为OFF时只能包含本地文件
注意:
从PHP5.2开始allow_url_include就默认为OFF了,而allow_url_fopen直是ON的。
文件包含漏洞利用方式
1.伪协议
在PHP中经常使用伪协议进行文件包含。
1.file://:读取本地文件,后面可以跟绝对路径和相对路径。
2.php://filter:是一种元封装器, 设计用于数据流打开时的筛选过滤应用。
- 这里的用法举例里面是将源文件index.php转换成base64后读取出来。
2.php://input:可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。
3.zip://:想要访问压缩包里的文件,文件名前必须用“#”而不是“/”。
- “#”的URL编码是%23。
4.compress.bzip2://、compress.zlib://:都是读取压缩包的,它们有两种语法,一种是相对路径、一种是绝对路径。
5.data:// 同样类似与php://input,可以让用户来控制输入流。
6.phar://:解压缩包的一个函数,不管后缀是什么,都会当做压缩包来解压。
- 例如:phar://xxx.png/shell.php
2.绕过方式
1.00截断:
Windows在读文件名时,当遇到ASCII码0时会判断为读取结束,会自动停止对后面内容的读取。
在URL中的形式是%00,在十六进制中是0x00。
2.长度截断:
也是利用操作系统对文件名读取的特性进行绕过。
Windows最大读取长度:256;
Linux最大读取长度:4096。
3.包含日志文件:
我们使用浏览器对URL请求时都会存储在日志里,如果我们在请求地址里写上一句话木马,那么当我们请求的时候就会把这个一句话木马写入日志文件。
如果我们知道日志文件的路径,那我们就可以包含这个日志文件,从而获得webshell。
4.包含session:
用法和包含日志差不多,往session里写入一句话木马,然后知道session路径以后就可以做文件包含。
文件漏洞的防御
1.PHP 中使用 open_basedir 配置限制访问在指定的区域
2.过滤.(点)/(反斜杠)\(反斜杠)
3.禁止服务器远程文件包含
4.尽量不要使用动态包含,可以在需要包含的页面固定写好