目录
文件包含及文件包含漏洞
PHP中常见包含文件函数
include()
include_once()
require()
require_once()
文件包含漏洞原理
常见漏洞代码
文件包含漏洞危害
文件包含漏洞的分类
文件包含利用
1.上传图片马,包含图片马GetShell
2.读取网站源码及配置文件
php://filter
php://input
data:text/plain
zip://伪协议
file://伪协议
Phar协议
更多伪协议
3.包含日志文件GetShell
4.包含session文件GetShell
%00截断
漏洞挖掘
修复办法
1.PHP 中使用open_basedir 配置限制访问在指定的区域。
2.过滤 . / \ ../../../
3.过滤伪协议
4.禁止服务器远程文件包含。
5.包含的参数值,不要用户可控。
6.设置白名单
程序开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这种文件调用的过程一般被称为文件包含。
开发人员为了使代码更灵活,会将被包含的文件设置为变量,用来进行动态调用,从而导致客户端可以恶意调用一个恶意文件,造成文件包含漏洞。
即在文件包含的路径是攻击者可控的情况下,攻击者可以通过控制参数变量从而能包含本不在开发者意愿之内的文件。
当使用改函数包含文件时,只有代码执行到include()函数时才将文件包含进来,发生错误时只给出一个警告,继续向下执行。
功能与include()相同,区别在于当重复调用同一文件时,程序只调用一次。
require()与include()的区别在于require()执行如果发生错误,函数会输出错误信息,并终止脚本的运行。
功能与require()函数相同。区别在于当重复调用同一文件时,程序只调用一次。
重点:include()与require()函数的区别
当处理一个不存在或者无法包含的文件时,对于include()会抛出错误,然后继续执行下面的PHP代码。require()会直接抛出致命错误,后面的代码无法继续执行。
如果出现语法错误,两个不会继续执行,如果是找不到文件,include()会继续执行,require()会终止执行。
文件包含漏洞产生的原因是在通过引入文件时,包含的文件名,用户可控,由于传入的文件名没有经过合理的校验,或者校验被绕过。
1. 配合文件上传漏洞 GetShell
2.可以执行任意脚本代码(php://input)(即时没有文件上传也能执行脚本代码)
3.网站源码文件及配置文件泄露(PHP://filter/read=convert.base64-encode/resource=Test.php)(即时没有文件上传也能读取)
4.远程包含GetShell
5.控制整个网站甚至是服务器
1)本地文件包含:包含服务器端的文件
当被包含的文件在服务器本地时,就形成了本地文件包含漏洞。
本地文件包含就是通过浏览器包含 Web 服务器上的文件,这种漏洞时因为浏览器包含文件时没有进行严格的过滤允许遍历目录的字符注入浏览器并执行。
2)远程文件包含:包含远程 url 的文件(allow_url_fopen allow_url_include)
远程文件包含就是允许攻击者包含一个远程的文件,一般是在远程服务器上预先设置好的脚本,此漏洞是因为浏览器对用户的输入没有进行检查,导致不同程度的信息泄露,拒绝服务攻击甚至在目标服务器上执行代码。
本地文件包含和远程文件包含造成漏洞的原因是一样的。当 php.ini 中的配置选项 allow_url_fopen (是否运行通过一个url进行包含)和 allow_url_include 为ON的话,则包含的文件可以是第三方服务器中的软件,这样就形成了远程文件包含漏洞。
php://filter
利用条件:只是读取,所以只需要开启 allow_url_fopen , 对于 allow_url_include 不做要求。
实现效果:将文件种的数据进行 base64 加密之后输出
index.php?file=php://filter/read=convert.base64-encode/resource=Test.php
不支持多 /
';
echo 'Input again';
}
?>
php://input
需要开启 allow_url_include=on,对于 allow_url_fopen 不做要求。
接受post请求
php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下 $HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data 潜在需要更少的内存。 enctype="multipart/form-data" 的时候 php://input 是无效的。
data:text/plain
条件:allow_url_fopen 参数与 allow_url_include 都需要开启。
i
用法:i
1) ?file=data:text/plain,
2) ?file=data:text/plain;base64,编码后的 php 代码
注意:base64加密之后的代码,不能有+号,否则会和 url 中的+编码冲突。
注:测试发现plain改为plan也可输出正确结果。i
zip://伪协议
使用条件:使用 zip 协议,需要将 # 编码为%23 ,所以需要PHP的版本 >= 5.3.0,要是因为版本的问题无法将 # 编码为 %23 ,可以手动更改。
用法: ?file=zip://[压缩文件路径 + 压缩文件名]#[压缩文件内的子文件名]
注:既可以用相对路径,也可以用绝对路径。
file=zip://./1.zip%231.txt
file=zip://c:\PHPstudy\WWW\Test\1.zip%231.txt
file://伪协议
file://可以用来访问本地文件系统,且不受 allow_url_fopen 与 allow_url_include 的影响。
用法:?file=file://文件绝对路径
支持多 / 如?file=file:///文件绝对路径
不支持文件相对路径
Phar协议
用法:?file=phar://压缩包/内部文件 phar://xxx.png/shell.php
注意:PHP >= 5.3.0 压缩包需要是zip协议压缩,rar不行 ,将木马文件压缩后,改为其任意格式的文件都可以正常使用。
步骤:写一个一句话木马文件 sehll.php ,然后用zip协议压缩为 shell.zip ,然后将后缀改为 png 等其他格式。
PHP官方的伪协议解释
1.首先 找到日志文件存放位置
2.让日志文件插入 PHP 代码
3.包含日志文件
httpd.conf 文件注释 ' CustomLog "logs/access.log" common ' 后出现 access.log 文件。
小结:只有日志中记录内容为正确的可执行文件格式时才能执行。
例如:
可执行
不可执行
不可执行
不可执行
Session包含
利用条件:session的存储位置可以获取。
通过 phpinfo() 的信息可以获取到 session 的存储位置。
通过 phpinfo() 的信息,获取到 session.save_path
使用前提:1)要知道 session 的存储位置
2)有一个可控的 session 参数位置
3)要有一个文件包含点
%00截断
1) /etc/passwd%00
2)需要 magic_quotes_gpc=off
3)PHP < 5.3.4 有效
";
}
$file_name = $_GET['file'].".jpg" ;
echo $file_name."
";
include $file_name ;
?>
1.没有同用的挖掘办法(Google 搜索 include...file=...)
2.特定的CMS,特定的版可能存在漏洞(include , require)
3.Web 漏洞扫描器扫描,常见的 Web 漏洞扫描器都支持可以检测。
4.手工挖掘,看参数,filename=xxx,是否可以包含其他文件。
1) 利用 str_replace() 函数。
2)利用 preg_replace() 函数。