PHP任意文件上传CVE-2015-2348 漏洞分析
03 Apr 2015 - Tr3jer_CongRong
当时发现这个Vulnerability Summary for CVE-2015-2348漏洞公告的时候,果然是字符截断导致的,存在于PHP高版本中,多数安全研究者都在说漏洞怎么怎么鸡肋的,经过测试表明,还是要看利用的场景而异说明是不是真的很鸡肋
.
漏洞分析:
move_uploaded_file()
函数,这个函数是将上传的文件移动到新位置.
move_uploaded_file ( string $filename , string $destination )
源代码:ext/standard/basic_functions.c
这个函数拿php-5.3.x & php5.6.x作比较,发现高版本此函数的长度比较判断被干掉了……
if (strlen(path) != path_len) {
RETURN_FALSE;
}
if (strlen(new_path) != new_path_len) {
RETURN_FALSE;
}
strlen(new_path)
为move_uploade_file()-$destination
参数的长度(\0截断的话只计算截断前面的字符长度),在PHP中,所有的变量都是用一个结构_zval
来保存的,而new_path_len
对应着结构体中的int len
,由于是二进制保存的,所以计算长度的时候空字符以及后面的字符都会包含在内.
那么当空字符截断的时候,由于长度不等,
strlen(new_path) != new_path_len
即为FALSE,低版本的截断上传则无效.
漏洞证明:
Windows7 & PHP5.4.x
upload.php
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>upload</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit">
</form>
</body>
<?php
echo "<pre>";
var_dump($_FILES);
echo "</pre>";
move_uploaded_file($_FILES['file']['tmp_name'], "tmp/eval.php\x00.jpg");
?>
</html>
可以看出上传一个.jpg格式的木马在经过move_uploaded_file()转存的时候,截断生效了,截断上传一直都是个简单粗暴的漏洞,但是
无脑黑们
对这个漏洞不怎么感冒,认为谁会将转存的地址通过$_POST之类的接收呢?
鸡肋吗?
个人觉得这个漏洞并不是一文不值的,换个角度,以程序员的角度思考下,什么情况下$destination
参数需要外部接收呢?
demo.php
<html>
<meta content="text/html" charset="utf-8">
<body>
<form action="" method="post" enctype="multipart/form-data">
<label>选择图片:<label>
<input type="file" name="file" />
<input type="hidden" name="address" value="<?php echo time(); ?>">
<br />
<input type="submit" value="Submit" />
<br />
</form>
</body>
<?php
error_reporting(0);
$upload_name=$_FILES['file']['name'];
$type=substr($upload_name,strrpos($upload_name,'.')+1);
if($type == "jpg" || $type == "png" || $type == "gif"){
$address=$_POST['address'].".".$type;
if (move_uploaded_file($_FILES['file']['tmp_name'],"tmp/".$address)) {
echo "图片地址:tmp/".$address;
}
}else{
echo "上传类型错误!";
}
?>
</html>
抓包截断,将time()生成的数字后面加上.php
和一个空字符
:
截断上传成功后从文件名上也会发现漏洞存在于此函数:
只是个简单的测试demo,因场景而异漏洞还是会存在的,毕竟\0是C的特性,当演变成了漏洞后,就要看开发者是否认真对待.
$destination
不要使用$_GET或者$_POST来接收- $_FILES[‘file’][‘name’]不受影响,推荐作为
$destination
参数 - 漏洞涉及的版本存在于PHP5.4.38-5.6.6