通过上一篇文章,我们知道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库,直接去打开文件,然后再保存一次。 这样,里面不合法的代码会去掉的。但是,我们想想,这样该会花费多大的性能呢?
综上所述,其实,去判断文件内容格式,不是明智的方法。 会非常复杂,而且也容易出现问题。想准确判断,还会消耗大量的服务器资源。除非万不得已,我们不要去尝试做这种操作。 接下来,对于安全上存方法,我会说说思路,欢迎交流!
作者:程默的博客 QQ:8292669
原文网址:http://blog.chacuo.net/141.html
订阅保持关注:http://blog.chacuo.net/feed
本文版权归作者所有,欢迎转载,请务必添加原文链接。