第 14 章 PHP 安全
14.1 文件包含漏洞
严格来说,文件包含漏洞是“代码注入”的一种。在“注入攻击”一章中,曾经提到过“代码注入”这种攻击,其原理就是注入一段用户能够控制的脚本或代码,并让服务器端执行。“代码注入”的典型代表就是文件包含( File Inclusion )。文件包含可能会出现在 JSP、PHP、ASP 等语言中,常见的导致文件包含的函数如下。
- PHP:
include()
,include_one()
,require()
,require_once()
,fopen()
,readfile()
, … - JSP/Servlet:
ava.io.File()
,java.io.FileReader()
, … - ASP:
include file
,include virtual
, …
文件包含是 PHP 的一种常见用法,主要由 4 个函数完成:
- include()
- require()
- include_once()
- require_once()
当使用这 4 个函数包含一个新的文件时,该文件将作为 PHP 代码执行,PHP 内核并不会在意该被包含的文件是什么类型。 所以如果被保护的是 txt 文件、图片文件、远程 URL ,也都将作为 PHP 代码执行。
要想成功利用文件包含漏洞,需要满足下面两个条件:
- include() 等函数通过动态变量的方式引用需要包含的文件;
- 用户能够控制该动态变量。
14.1.1 本地文件包含
能够打开并包含本地文件的漏洞,被称为本地文件包含漏洞(Local File Inclusion ,简称 LFI )。
14.1.2 远程文件包含
如果 PHP 的配置选项 allow_url_include
为 ON 的话,则 include/require 函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞( Remote File Inclusion , 简称 RFI )。
14.1.3 本地文件包含的利用技巧
本地文件包含漏洞,其实也是有机会执行 PHP 代码的,这取决于一些条件。
远程文件包含漏洞之所以能够执行命令,就是因为攻击者能够自定义被包含的文件内容,因此本地文件包含漏洞想要执行命令,也需要找到一个攻击者能够控制内容的本地文件。
经过不懈的研究,安全研究者总结出了一下几种常见的技巧,用于本地文件包含后执行 PHP 代码。
- 包含用户上传的文件。
- 包含 data:// 或 php://input 等伪协议。
- 包含 Session 文件。
- 包含日志文件,比如 Web Server 的 access log 。
- 包含 /proc/self/environ 文件。
- 包含上传的临时文件 ( RFC1867 )。
- 包含其他应用创建的文件,比如数据库文件、缓存文件、应用日志等,需要具体情况具体分析。
包含用户上传的文件很好理解,这也是最简单的一种方法。用户上传的文件内容中如果包含了 PHP 代码,那么这些代码被 include() 加载后将会执行。
但包含用户上传文件能否攻击成功,取决于文件上传功能的设计,比如要求知道用户上传后文件所在的物理路径,有时这个路径很难猜到。
PHP 创建的上传临时文件,往往处于 PHP 允许访问的目录范围内。包含这个临时文件的方法,其理论意义大于实际意义。
PHP 会为上传文件创建临时文件,其目录在 php.ini 的 upload_tmp_dir
中定义。但该值默认为空,此时在 Linux 下会使用/tmp 目录,在 Windows 下会使用 C:\windows\temp 目前。