文件包含简介
服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当PHP来执行,这会为开发者节省大量的时间
文件包含函数require()
require_once()
include()
include_once()
include和require区别主要是,include在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行;而require函数出现错误的时候,会直接报错并退出程序的执行,而include_once(),require_once()这两个函数,与前两个的不同之处在于这两个函数只包含一次,适用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,你想确保它只被包括一次以避免函数重定义,变量重新赋值等问题
漏洞产生原因
文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码
示例代码<?php
$filename = $_GET['filename'];
include($filename);
?>
文件包含漏洞
无限制本地文件包含漏洞
测试代码:<?php
$filename = $_GET['filename'];
include($filename);
?>
常见敏感文件目录:
Windows系统c:\boot.ini // 查看系统版本
c:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件
c:\windows\repair\sam // 存储Windows系统初次安装的密码
c:\ProgramFiles\mysql\my.ini // MySQL配置
c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密码
c:\windows\php.ini // php 配置信息
Linux/Unix系统/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 配置文件
测试结果:
包含session文件
利用条件:
知道session文件路径,在phpinfo()里面可以看到
默认情况下,session.use_strict_mode值是0。此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=ghtwf01
示例代码:<?php
session_start();
$ctfs=$_GET['ctfs'];
$_SESSION["username"]=$ctfs;
?>
查看一下生成的session文件,phpinfo成功写入
然后利用文件包含包含一下,当然也可以写入一句话getshell
以phpMyAdmin CVE-2018-12613为例包含session文件
首先进入执行SQL语言地方,执行如下操作select '<?php phpinfo();?>'
打开F12查看到session名,完整的session文件就是sess_session名
phpstudy里面默认session存储位置是phpstudy下tmp/tmp,于是包含该session文件
包含图片马
一般用于文件上传,上传图片马后如果存在文件包含漏洞,那么就可以执行图片马里面的php代码
包含日志文件
(1)包含apache日志
进入一个网页,比如phpmyadmin,burpsuite抓包,在URL栏添加一句话木马,这样它就会报错,并把报错语句(一句话木马)写入apache日志
日志里面已经写入了phpinfo,然后包含日志
但是我这个环境的日志不允许包含,所以没法执行代码,但是实战中就有可能权限允许包含
(2)包含ftp日志
ftp连接时,用户名输入一句话木马
日志位置在/var/log/vsftpd.log
(3)包含ssh日志ssh -p 22 "<?php phpinfo(); ?>"@目标ip地址
日志位置在/var/log/auth.log
(4)包含临时文件
无限制远程文件包含
远程文件包含需要打开远程文件包含许可,即allow_url_include = On
有限制文件包含绕过
(1)%00截断
条件:magic_quotes_gpc=off`php版本<5.3.4`
测试代码<?php
$filename = $_GET['filename'];
include($filename.".php");
?>
如果要包含1.txt,它在后面自动加上.php,所以包含的文件就是1.txt.php,没有这个文件,所以采用%00截断
(2)路径长度截断
Windows下目录最大长度为256字节,超出的部分会被丢弃
Linux下目录最大长度为4096字节,超出的部分会被丢弃
测试代码<?php
$filename = $_GET['filename'];
include($filename.".php");
?>
exp:.................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
所以效果如下
(3)问号截断
测试代码<?php
$filename = $_GET['filename'];
include($filename.".php");
?>
问号截断漏洞是针对远程文件包含的情况,在PHP的配置文件中,打开远程文件包含许可,即allow_url_include = On
(4)#号绕过
测试代码<?php
$filename = $_GET['filename'];
include($filename.".php");
?>
一样是需要打开远程文件包含
(5)空格绕过
测试代码<?php
$filename = $_GET['filename'];
include($filename.".php");
?>
一样是需要打开远程文件包含
php伪协议
(1)php://filter
因为直接打开php文件不会显示里面的代码,所以我们可以以base64编码的方式读取指定文件的源码
php://filter/convert.base64-encode/resource=php文件名
base64解码即为源代码
(2)data://
利用data:// 伪协议可以直接达到执行php代码的效果
如果此处对特殊字符进行了过滤,我们还可以通过base64编码后再输入(才发现php代码里面加了分号的base64无法执行)
(3)zip:// bzip2:// zlib://
zip://
执行压缩文件,如果网站允许我们上传压缩文件,我们也可以将php文件压缩后进行上传,再通过zip://协议执行,以dvwa平台为例
然后包含payload:http://127.0.0.1/zx/test.php?filename=zip://D:/Program%20Files/PHPTutorial/WWW/DVWA/hackable/uploads/phpinfo.zip%23phpinfo.php
bzip2://
压缩文件至xxx.bz2并上传,访问的使用使用compress.bzip2://
zlib://
压缩文件至xxx.gz并上传,访问的时候使用compress.zlib://
(4)php://input
我们可以利用这种方法直接写入文件,比较特殊的一点,enctype=multipart/form-data 的时候php://input是无效的
发现shell.php已经写入到本地
(5)phar://
这个伪协议和zip://一样可以读取压缩包里面的内容,以刚才在dvwa上传的zip文件为例
(6)file://
这个伪协议是用来读文件内容的,需要加文件的绝对路径
上述伪协议适用条件
php://allow_url_fopen:off/on
仅php://input需要on(还有一些也需要on为了方便记忆就没写上去了)
data://allow_url_fopen:on
allow_url_include :on
file://allow_url_fopen:off/on
allow_url_include :off/on
zip:// bzip2:// zlib://allow_url_fopen:off/on
allow_url_include :off/on
phar://allow_url_fopen:off/on
allow_url_include :off/on
参考链接