文件包含漏洞学习笔记(更新中)

文件包含漏洞学习笔记

前言:

一直感觉之前对漏洞的理解过于肤浅,所以最近打算对这些常见的漏洞类型都好好研究一番

成因:

由于开发没有较好的判断和过滤来源文件路径,从而导致能把目标文件中的内容引入到字符串或者本文件中

所以造成这些漏洞的函数共性都是能读取目标文件中的内容并且引入到字符串或者本文件中

符合以上要求的函数如下两大类:

这一类是将来源文件内容引入到本文件中的函数:

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/

https://www.smi1e.top/%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E%E4%B8%8Ephp%E4%BC%AA%E5%8D%8F%E8%AE%AE/#file

在ctf中伪协议是非常常见的,利用伪协议读取源码等等

常用的伪协议hackbar中就带了

image-20200522224222642

php://

php:// 可以访问各个输入/输出流(I/O streams)所以我们可以利用php伪协议这一点来进行命令执行和源码读取等

  1. php://filter 不需要 allow_url 开启即可读取、包含也可以进行使用,php://filter是php语言特有的协议流,我这里将这个协议理解为桥梁。将目标文件和我们之间建立起来的桥梁。一般都是用来读取源码这里有一个地方需要注意就是我们在读取源码的时候一定要用base64进行编码否则对应的php文件会被解析导致无法读取源码

    image-20200523094743011

http://192.168.1.14/test/inc.php?file=php://filter/convert.base64-encode/resource=inc.php

最后的inc.php 可以换成别的文件对应的就可以读取别的文件的源码了

相对的如果要读取上一级的文件自然就需要利用 ../

image-20200523094949742

image-20200523095011717

  1. php://input 这个的使用条件比之前要苛刻一些,一定要allow_url_include为on才可以 php://input是个可以访问请求的原始数据的只读流,可以读取到post没有解析的原始数据, 将post请求中的数据作为PHP代码执行。

    image-20200523104832780

    可以看到我们的命令正确的执行了

    同样的我们可以利用这个协议来进行命令的执行

    image-20200523104936349

zip://

zip://, bzip2://, zlib://协议在allow_url双off的情况下都可以正常使用

这个一般在什么情况下用到呢,比如我们在网站的一个地方可以上传我们的压缩包,同时又发现了一处文件包含,这时候就可以利用这个协议来进行命令执行

Zip://[压缩文件绝对路径]#[压缩文件内的子文件名]。(这里的#要进行url编码)

环境:macOS + php 5.4.45

将phpinfo代码写入 include.txt 然后将文件进行压缩

image-20200523215754924

然后利用zip://的特性,从而导致解析

image-20200523215938167

不过好像php版本5.3以下需要绝对路径,待核实

data://

data:资源类型;编码,内容

前提两者都要为on

同时php版本大于5.2

http://192.168.1.14/test/inc.php?file=data://text/plain,<?php phpinfo()?>

image-20200523115728039

绕过小姿势

在什么情况下会需要这种截断呢?很多时候在实战的情况中并不是完全可控的

所以这种时候我们可以利用截断来进行绕过

<?php
  $name = $_GET['name'];
    include .$name.'.jpg';
  1. %00截断 存在于php<=5.3.0 且magic_quotes_gpc 为off (magic_quotes_gpc为on的话所有特殊符号都会进行转义 )
  2. 路径长度截断 存在于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

image-20200519170715796

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

image-20200519170939888

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这样的话就算引入也无法解析

image-20200519171335311

抓包之后对参数进行修改,这里遇到一个坑就是发现payload中包含空格的情况下返回错误400,错误400就不会写入error.log而是写入了access.log

<?php+phpinfo();?> 利用加号来替换空格

image-20200519171617320

此时我们的日志已经被记录在error.log里面了

image-20200519171755492

然后利用phpstudy可以知道路径

image-20200519171933044

最后利用文件包含漏洞getshell

http://192.168.1.14/test/inc.php?file=../../Extensions/Apache2.4.39/logs/error.log

image-20200519172013037

ps: sqlmap下/data/txt中有fuzz的字典

image-20200519172317491

image-20200519172350597

同时可以可以利用一些信息泄漏小漏洞来找到我们的路径

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(); ?>

然后在我们的本地环境中远程调用我们的文件

image-20200522215149874

可以看到我们的php被解析了

任意文件读取和任意文件包含的区别

这两个我之前概念总是不是很清晰今天专门研究一下

在我个人看来:任意文件包含>任意文件读取

任意文件读取 利用 get_file_contents 等类似将文件读取并且以字符串等形式输出的,所以能做到的只有读取信息,比较重要的一点就是 在读取 php 代码的时候一定要用 php://filter + base64 来进行一个读取,不然php源码是读取不到的 只有一片空白

由于没有include require 等引入文件的函数所以任意文件读取是不能解析php的,也就是说 只能读取文件

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像