《白帽子讲Web安全》14-PHP安全

第14章 PHP安全

PHP的语法过于灵活,这也给安全工作带来了一些困扰。同时PHP也存在很多历史遗留的安全问题。

PHP语言的安全问题有其自身语言的一些特点。

14.1 文件包含漏洞

  1. 文件包含漏洞是“代码注入”的一种。
  2. 文件包含可能会出现在JSP、PHP、ASP等语言中。
  3. 常见的导致文件包含的函数如下:
    • PHP: include(), include_once(), require(), require_once(), fopne(), readfile(), …
    • JSP/Servlet: ava.io.File(), java.io.FileReader(), …
    • ASP: include file, include virtual, …
  4. 文件包含是PHP的一种常见用法,主要由4个函数完成:
    • include()
    • require()
    • include_once()
    • require_once()
  5. 当使用这4个函数包含一个新的文件时,该文件将作为PHP代码执行,PHP内核并不会在意该被包含的文件是什么类型。
    • 这一特性,在实施攻击时将非常有用。
  6. 要想成功利用文件包含漏洞,需要满足下面两个条件:
    • include()等函数通过动态变量的方式引入需要包含的文件
    • 用户能够控制该动态变量

14.1.1 本地文件包含

  1. 能够打开幷包含本地文件的漏洞,被称为本地文件包含漏洞(Local File Inclusion,简称LFI)
  2. 字符串截断的技巧,也是文件包含中最常见的技巧。
    • 在连接字符串时,0字节(\x00)将作为字符串结束符。
      • PHP内核是由C语言实现的,因此使用了C语言中的一些字符串处理函数。
      • 在一般的Web应用中,0字节用户其实时不需要使用的,因此完全可以禁用0字节。
    • 利用操作系统对目录最大长度的限制,可以不需要0字节而达到截断的目的。
  3. 除了include()等4个函数外,PHP中能够对文件进行操作的额函数都有可能出现漏洞。能够读取敏感文件带来的后果也是比较严重的。
    • fopen()
    • fread()
  4. 文件包含漏洞能够读取敏感文件或者服务器端脚本的源代码,从而为攻击者实施进一步攻击奠定基础。
  5. 目录遍历(Path Traversal)漏洞
    • 跨越目录读取文件
    • 当PHP配置了open_basedir时,将很好地保护服务器,使得这种攻击无效。
    • open_basedir的作用是限制在某个特定目录下PHP能打开的文件,其作用与safe_mode是否开启无关。
  6. 要解决文件包含漏洞,应该尽量避免动态的变量,尤其是用户可以控制的变量。
    • 一种变通方式:使用枚举。

14.1.2 远程文件包含

  1. 如果PHP的配置选项allow_url_include为ON的话,则include/require函数是可以加载远程文件的。这种漏洞被称为远程文件包含漏洞(Remote File Inclusion,简称RFI)。
  2. 远程文件包含漏洞可以直接用来执行任意命令。

14.1.3 本地文件包含的利用技巧

  1. 本地文件包含漏洞,其实也是有机会执行PHP代码的,这取决于一些条件。
  2. 远程文件包含漏洞之所以能够执行命令,就是因为攻击者能够自定义被包含的文件内容。因此本地文件包含漏洞想要执行命令,也需要找到一个攻击者能够控制内容的本地文件。
  3. 一些常用的技巧,用于本地文件包含后执行PHP代码:
    • 包含用户上传的文件
    • 包含data://或php://input等伪协议
    • 包含Session文件
    • 包含日志文件,比如Web Server的access log
    • 包含/proc/self/environ文件
    • 包含上传的临时文件(RFC1867)
    • 包含其他应用创建的文件,比如数据库文件、缓存文件、应用日志等,需要具体文件具体分析。
  4. 上述技巧的具体讨论

14.2 变量覆盖漏洞

  • 安全建议:
    • 确保register_globals=OFF。若不能自定义php.ini,则应该在代码中控制。
    • 熟悉可能造成变量覆盖的函数和方法,检查用户能否控制变量的来源。
    • 养成初始化变量的好习惯。

14.2.1 全局变量覆盖

14.2.2 extract()变量覆盖

14.2.3 遍历初始化变量

14.2.4 import_request_variable变量覆盖

14.2.5 parse_str()变量覆盖

14.3 代码执行漏洞

  • PHP终端代码执行情况非常灵活,但是依然离不开两个关键条件:
    • 用户能够控制的函数输入
    • 存在可以执行代码的危险函数

14.3.1 “危险函数”执行代码

  1. PHP中,能够执行代码的方式远不止文件包含漏洞一种:

    • 比如危险函数popen()、system()、passthru()、exec()等都可以执行系统命令。
    • eval()函数可以执行PHP代码
    • 允许用户上传PHP代码
    • 应用写入到服务器的文件内容和文件类型可以由用户控制
  2. 几个真实案例

14.3.2 “文件写入”执行代码

14.3.3 其他执行代码方式

  1. 直接执行代码的函数
    • eval()
    • assert()
    • system()
    • exec()
    • shell_exec()
    • passthru()
    • escapeshellcmd()
    • pcntl_exec()
  2. 文件包含
    • include()
    • include_once()
    • require()
    • require_once()
  3. 本地文件写入
  4. preg_replace()代码执行
  5. 动态函数执行
  6. Curly Syntax
  7. 回调函数执行代码
  8. unserialize()导致代码执行

14.4 定制安全的PHP环境

  1. 熟悉各种PHP漏洞
  2. 配置php.ini来加固PHP的运行环境
    • 推荐php.ini中一些安全相关参数的配置
      • register_globals
      • open_basedir
      • allow_url_include
      • display_errors
      • log_errors
      • magic_quotes_gpc
      • cgi.fix_pathinfo
      • session.cookie_httponly
      • session.cookie_secure
      • safe_mode
      • disable_functions
    • 推荐禁用的类
      • XMLWriter
      • DOMDocument
      • DOMNotation
      • DOMXPath
      • SQLiteDatabase
      • SQLiteResult
      • SQLiteUnbuffered
      • SQLiteException

14.5 小结

本章先后介绍了PHP中一些特别的安全问题,比如文件包含漏洞、代码执行漏洞,最后对如何定制一个安全的PHP环境给出了建议。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章