沉于思考,默默学习!

你不能预知明天,但你可以利用今天。你不能样样顺利,但你可以事事尽力!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  63 随笔 :: 0 文章 :: 711 评论 :: 0 引用

公告

通过上一篇文章,我们知道wed上存漏洞,最常见一种是文件名检测漏洞,接下来,我们看看另外一种漏洞,上存文件类型漏洞,这也是一种较为容易出现问题。

我当时就想,既然我知道我需要允许上存什么样的文件,那么,我就只允许你上存该文件。只要我文件类型判断准确了,你想上存能够执行的代码。我都给阻止掉,不就行了吗? 这确实,是个好的方法,但是我们再做的时候,往往会出现下面一些问题。

这里我们看下常见实现的php代码。 这里,常见两个问题是:

 

1.读取文件type,直接做文件类型判断

2.通过工具分析文件格式,以此来确认文件类型

 

  • 问题一:读取文件type,判断文件类型

 
if(isset($_FILES['img']))
{
    $file = save_file($_FILES['img']);
	if($file===false) exit('上存失败!');
	
	echo "上存成功!",$file;
}



function check_file($img)
{
	///读取文件
	if($img['error']>0) return false;
	
	$type = $img['type'];
	$filename = $img['name'];
	
	
	///读取文件扩展名
	$len=strrpos($filename,".");
	if($len===false) return false;
	
	//得到扩展名
	$ext = strtolower(substr($filename,$len+1));
	
	///判断文件类型
	if($type && preg_match('%^image/.+$%',$type)) return $ext;
	
	return false;
}

function save_file($img)
{
	$ext = check_file($img);
	if(!ext) return false;
	
	//格式检测ok,准备移动数据
	$filename = time().$ext;
	$newfile = "upload/" .$filename;
	if(!move_uploaded_file($img["tmp_name"],$newfile)) return false;
	
	return $newfile;

}

 

以上加蓝色代码,是关键,这个里面我们直接读取type类型,也就是文件内容。通过第一篇知识:web上存漏洞及原理分析、防范方法 我们知道,type来自浏览器端浏览器自动传入变量。 如果是浏览器,这个值一般没有问题。但是,如果是来自用户自己组织的包,他可以给type 设置个:image/jpeg值, 然后,给name 一个 index.php 值。

估计大家已经看到问题,这样一来,我们生成的文件$filename变成为:time().’php’了。 就创建一个php文件。

  • 通过工具分析文件格式,以此来确认文件类型

 

我们已经清楚知道了,type值是可以随便构造的,这类检查用户类型方法。是没有任何作用,恶意用户,可以随便给一个php文件发送上来,传一个image类型。 那么,肯定有朋友会说,我直接用php程序,去分析用户传入的tmp_name 文件格式,这个总靠谱吧! 我们看看下面代码。

function check_file($img)
{
	///读取文件
	if($img['error']>0) return false;
	
	$typelist = array(array("FFD8FFE1","jpg"),
	array("89504E47","png"),
	array("47494638","gif"),
	array("49492A00","tif"),
	array("424D","bmp"));
	
	$file = $img['tmp_name'];
	$filename = $img['name'];
	
	
	///读取文件扩展名
	$len=strrpos($filename,".");
	if($len===false) return false;
	
	//得到扩展名
	$ext = strtolower(substr($filename,$len+1));
	
	///判断文件类型
	//读取文件开头15字节,一般通过这些字节值,可以确定它的格式
	$file = @fopen($file,"rb");
	$bin = fread($file, 15);
	
	foreach ($typelist as $v)
	{
		$blen=strlen(pack("H*",$v[0])); //得到文件头标记字节数
		$tbin=substr($bin,0,intval($blen)); ///需要比较文件头长度
		 
		if(strtolower($v[0])==strtolower(array_shift(unpack("H*",$tbin)))) 
		{
			return $ext;
		}
	}
	
	return false;
}

该方法,直接分析用户传入文件格式,然后决定该文件类型,是否允许保存!这套,我们看来非常可靠方法,应该很准确,应该没有问题,不读取type,自己来分析格式。 其实:如果用户传入一个文件,前面4字节是:89504E47, 然后,后面加入一段<?php代码 。上存的文件名称是image.php 。这样一来,我们发现,这段代码保存为php文件了。 只是这个文件,前面一部分可能是图片格式,后面一部分,只纯粹的php 程序。 通过浏览器,去访问下这个,还真的可以运行呢。 很久以前,就有人做过image图片木马。可以去百度搜索:”将php木马隐藏在图片里” ,这样做出的文件,你用画图软件看是个图片,你如果用php运行这段代码,里面php能够执行了。

 

好了,我们总结下,看来通过type判断类型,以及通过文件格式检测类型。 都不能很好解决,准确判断用户上存文件格式了。 其实,我们反过来想想,文件格式,不是通过一个简单字节标识码就能够准确判断的。 如果真的要去检测文件类型,我们该用什么方法呢?如果真的要检测格式,例如是图片,可以用php gd库,直接去打开文件,然后再保存一次。 这样,里面不合法的代码会去掉的。但是,我们想想,这样该会花费多大的性能呢?

综上所述,其实,去判断文件内容格式,不是明智的方法。 会非常复杂,而且也容易出现问题。想准确判断,还会消耗大量的服务器资源。除非万不得已,我们不要去尝试做这种操作。 接下来,对于安全上存方法,我会说说思路,欢迎交流!

作者:chengmo  QQ:8292669 
原文网址:http://blog.chacuo.net/141.html 
订阅保持关注:http://blog.chacuo.net/feed 
本文版权归作者所有,欢迎转载,请务必添加原文链接。

posted on 2013-06-04 14:38 程默 阅读(...) 评论(...) 编辑 收藏