什么是文件包含?
程序开发人员通常会把一些可重复使用的函数写入某个文件中,这样在使用这些函数时,就可以直接调用此文件,,而无须重复编写函数代码,这种调用文件的过程就被称为文件包含。
为了实现代码复用,减少重复的工作量,文件包含在程序开发中被大量使用。如果网站开发人员对允许包含的文件没有严格的控制,就很有可能造成漏洞。
文件包含是 PHP 的一种文件加载机制。
常见:
include(); 如果被包含的文件不存在,会产生错误,,并停止运行脚本。
require(); 如果被包含的文件不存在,只会产生警告,脚本将继续运行。
include_once(); 与include类似,区别是,如果文件中的代码已经被包含。则不会再次包含
require_once(); 与require类似,区别是,如果文件中的代码已经被包含,则不会被再次包含
例如
include('header.php');
意思就是:把 header.php 加载到当前 PHP 程序中。
include() 到底做了什么?
例如:include('test.php');
假设 test.php:<?php echo "Hello";
那么:
include()
↓
找到 test.php
↓
读取文件
↓
PHP解析其中的PHP代码
↓
执行
所以 include() 和普通读取文件不一样。
例如:file_get_contents('test.php');
主要是:读取文件内容
而:include('test.php');是:加载文件,交给PHP处理
什么是文件包含漏洞?
正常情况下:include('header.php');
程序员自己决定:加载 header.php
但是如果写成:
file = _GET'file';
include($file);
就出现了一个关键问题:
用户输入
↓
$_GET['file']
↓
$file
↓
include($file)
也就是说:**用户可以影响 include() 要加载哪个文件。**这就是文件包含漏洞的核心。
文件上传和文件包含到底有什么区别?
文件上传
解决的是:"文件怎么进入服务器?"
用户
↓
上传文件
↓
服务器
↓
保存文件
关键:
$_FILES
move_uploaded_file()
文件包含
解决的是:"程序加载哪个文件?"
用户输入
↓
文件路径
↓
include()
↓
加载文件
关键:
include()
require()
文件上传、文件包含为什么可以联系起来?
因为文件上传可以让服务器上出现一个新的文件。
而文件包含可以让 PHP 程序加载一个文件。
因此两者可以形成:
文件上传
↓
服务器产生文件
↓
文件包含
↓
PHP加载这个文件
文件包含配合文件上传



虽然这是一个普通的文本文件,但是文件内容确实符号php语法规范,那么这些代码通过文件包含就可以正常被执行。
将txt的后缀名改成jpg,也可以正确显示phpinfo()信息。所以只有文件内容符号php语法规范,那么任何扩展名都可以通过文件包含被php解析。

在渗透测试中,通常会利用文件包含这个特点来配合文件上传,因为通常网站只会允许上传图片,如果网站还同时存在文件包含漏洞,就可以借助文件包含执行图片中的代码。
upload-13

在这里并没有通过扩展名来判断文件类型,而是直接读取了文件中的内容来进行判断。
对于系统中的大多数文件,每种文件类型文件的头部都会有一些固定的信息,用于标识文件的类型。
jpeg:FFD8FFE0
png:89504E47
gif:47494638
第2、、3、4行代码是以二进制的方式打开文件,然后读取文件的前两个字节,并保存到$bin变量中。
第五行代码unpack()函数将bin变量中的数据提取出来并保存到strInfo数组里。Cchars表示以十进制的形式表示数据,并且数组中每个元素的键名都是以chars开头,键名依次为chars1、chars2。。。。。
第6行将$strInfo中的两个数据拼接在一起,并用intval()函数转换成数值型数据。其中扩展名为gif的图片,就会得到7173。
7~21行,在case语句中判断,如果这个数据等于255216,那么就是扩展名为jpg的图片,如果为13780,就是png,7173就是gif

对于扩展名为jpg的图片,文件头部两字节为FFD8,也就是十进制255216。
所以这里只需在webshell的头部添加上图片文件中的头部信息即可。
copy /b test.jpg + shell.php shell.jpg
准备1张png图片,2.txt的内容为<?php phpinfo();

/b Binary 二进制模式。制作图片马专用

上传成功,这里对图片进行了改名

使用这里的文件包含漏洞

文件包含利用成功

gif格式
由于gif格式的图片头部47494638正好是对应ASCII字符GIF89a
所以可以直接在记事本中这样编辑

上传成功

利用文件包含漏洞成功

文件包含防御
- 输入验证与过滤
- 对用户输入的文件路径进行严格验证,防止用户输入恶意路径。
- 限制可访问的目录(例如:禁止访问 /etc、/bin 等系统目录)。
- 使用固定的文件名
- 通过预定义的文件名来避免动态包含用户提供的文件路径。
- 避免使用用户提供的路径
- 如果必须使用用户输入的数据,确保它们仅用于合法的、预定义的路径或文件。
- 禁用远程文件包含
- 禁止 PHP 中的 allow_url_fopen 和 allow_url_include 功能,防止远程文件包含漏洞。
- 目录遍历限制
- 使用 realpath () 等函数确保路径不包含任何目录遍历字符(如../)。