PHP任意文件上传漏洞(CVE-2015-2348)
安全研究人员今天发布了一个高危漏洞——PHP任意文件上传漏洞(CVE-2015-2348),这个漏洞影响范围很大。
在上传文件的时候只判断文件名是合法的文件名就断定这个文件不是恶意文件,这确实会导致其他安全问题。并且在这种情况下,在你自己的文件中检查漏洞很不现实,因为这个漏洞可以绕过你对文件名后缀、文件类型(Content-Type)、Mime type、文件大小等的检查,所以仅仅依靠这些检查是救不了你的。
漏洞细节
这个漏洞存在于php中一个非常常用的函数中:move_uploaded_files,开发者总是用这个函数来移动上传的文件,这个函数会检查被上传的文件是否是一个合法的文件(是否是通过 HTTP 的 post 机制上传的),如果是合法的文件,则将它一定到指定目录中。
例子:
move_uploaded_file ( string $filename , string $destination )
这里的问题是,可以在文件名中插入空字符(之前多次修复过这个漏洞,比如CVE-2006-7243),利用插入空字符的方式,攻击者可以上传任意文件,引起远程代码执行漏洞等。
我这里用DVWA来演示这个例子,DVWA级别最高的一题中因为种种原因不是很容易通过,意在告诉开发者如何去开发更安全的文件上传组件。让我们来看看这个例子:
代码地址:https://github.com/RandomStorm/DVWA/blob/master/vulnerabilities/upload/source/high.php
代码片段:
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1); $uploaded_size = $_FILES['uploaded']['size'];
if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "JPEG") && ($uploaded_size < 100000)){ if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path)) {
$html .= '';
$html .= 'Your image was not uploaded.';
$html .= ''; }
else {
$html .= $target_path . ' succesfully uploaded!';
.
.
这段代码有好多个漏洞,比如XSCH, XSS等,但是没有RCE这种严重的漏洞,因为从PHP 5.3.1开始,空字符的问题已经被修复了。这里的问题是,DVWA将用户上传的name参数传递给了move_upload_file()函数,那么 php 执行的操作可能就是这样子的:
move_uploaded_file($_FILES['name']['tmp_name'],"/file.php\x00.jpg");
这本应该创建一个名为file.php\x00.jpg的文件,但实际上创建的文件是file.php。
这样,就绕过了代码中对后缀名的校验,并且事实证明GD库中又很多其他函数也存在这个问题(比如getimagesize(), imagecreatefromjpeg()…等),可以看这个例子。
如果你机器的php版本在 5.4.39, 5.5.x – 5.5.23, 或者 5.6.x – 5.6.7,可以通过检查文件名中是否有\x00字符来解决本文中所述的问题。
安全建议
如果你的机器上存在这个漏洞,建议使用随机字符串重命名文件名,而不是使用用户上传上来的name参数的值。