打印

[php] 上传 文件头检查

各位达人,
有没有上传时,对文件头检查,以判断是不是真实的文件类型的例子?

谢谢。
我搜了老久,还没有找到。
这是ASP的最简短的!

if fileExt<>".gif" and fileExt<>".jpg" then
        response.write "<font size=2>图片格式只能为jpg/gif[ <a href=# onclick=history.go(-1)>重新上传</a> ]</font>"
        response.end
    end if
www.ziyou05.cn 自由工作室 QQ群:5501476
楼上,我不会菜到连扩展名都不会判断吧!

TOP

认证您的手机,获得手机认证图标, 更多手机认证的好处
刚要去吃饭,忍不住还是想回个帖

这问题我以前也想过,到是可以通过 $_FILES['file']['type'] 获取上传文件的MIME类型,可是浏览器判断MIME类型好像也是看扩展名,并不分析文件头。

可如果用PHP分析上传的文件要涉及到二进制操作,那可就头大了……
看到一段JAVA的:不过,看不出来什么门道。

                bool xx=false;  //default sFileName is not Exe or Dll File
                System.IO.FileStream  fs=new System.IO.FileStream(sFileName,System.IO.FileMode.Open,System.IO.FileAccess.Read);
                System.IO.BinaryReader r=new System.IO.BinaryReader(fs);
                string bx="";
                byte buffer;
                try
                {
                    buffer=r.ReadByte();
                    bx=buffer.ToString();
                    buffer=r.ReadByte();
                    bx+=buffer.ToString();

                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc.Message);
                }
                r.Close();
                fs.Close();
                if (bx=="7790"||bx=="8297"||bx=="8075")//7790:exe,8297:rar,8075k
                {
                    xx=true;
                }
                Console.WriteLine(bx);
                return xx;                 dll:MZ
                exe:MZ
                rar:Rar
                zip:PK

TOP

二进制读取文件,得到前两个字节并将其转换成字符串,就能得到 7790, 8297什么的?
如果是这样那我倒有点思路了……
ok,我试试去。

TOP

好了,核心部分搞定,多谢xling提供的那段Java代码:
复制内容到剪贴板
代码:
<?php
$filename = "D:\\296.mid";
$file     = fopen($filename, "rb");
$bin      = fread($file, 2); //只读2字节
fclose($file);
$strInfo  = @unpack("c2chars", $bin);
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
$fileType = '';
switch ($typeCode)
{
    case 7790:
        $fileType = 'exe';
        break;
    case 7784:
        $fileType = 'midi';
        break;
    case 8297:
        $fileType = 'rar';
        break;
    case 255216:
        $fileType = 'jpg';
        break;
    case 7173:
        $fileType = 'gif';
        break;
    case 6677:
        $fileType = 'bmp';
        break;
    case 13780:
        $fileType = 'png';
        break;
    default:
        echo 'unknown';
}
echo 'this is a(an) '.$fileType.' file:'.$typeCode;
?>
本帖最近评分记录
  • kuhanzhu 威望 +1 谢谢分享 2007-11-30 13:29

TOP

关键是 unpack 这个函数,把读到的二进制内容转成 字符串!

好帖,收藏了

TOP

打击你一下,
你百度一下:gif89a文件头欺骗

TOP

回复 #9 xling 的帖子

我汗…… 那怎么办?你再处理一下这个吧,解决了别忘了发上来

TOP

不知道DZ是怎么处理的。
汗。。。没有做处理!
我记得以前上传一个改过后缀名的文件,会提示“看起来不是真实的***文件”云云
现在居然没有处理!

[ 本帖最后由 xling 于 2007-11-30 13:49 编辑 ]
附件: 您所在的用户组无法下载或查看附件,您需要注册/登录后才能查看!

TOP

检测图片类型和是否为图片都是无效的。
可以检测后缀再加文件头检测。这样就相对应了,让加了文件头的asp文件等后缀是jpg等图片后缀。
再加备份还原数据库路径检测等。(不要犯动网7.0的还原问题就行了)
我的淘宝店:http://shop58394963.taobao.com/,中奖也不信
对管理有异议,请前往事务区进行投诉。请勿PM。

TOP

回复 #12 kuhanzhu 的帖子

没听明白。
能否细说?

TOP

回复 #11 xling 的帖子

你的那个已经上传成功了。
而且DZ确实是检测了后缀jpg上传的。能显示,那是因为浏览器是不看后缀的,就跟一个会动的gif文件改为jpg后缀仍然能动一样。

gif89a文件头检测是指程序为了他人将asp等文件后缀改为gif后上传,读取gif文件头,检测是否有gif87a或gif89a标记,是就允许上传,不是就说明不是gif文件。

而欺骗刚好是利用检测这两个标记,只要在木马代码前加gif87a就能骗过去。

有些程序因为有了检测功能,就更省事,直接检测文件头,上传(所有文件都检测文件头)。因此比如一个后缀为asp的木马,前面加了gif文件头标记,就直接上传了。这样,一个木马很容易就利用了。

而对于还要检测后缀的程序来说。木马只能把后缀改为gif来欺骗程序以gif形式上传,传上去之后再利用备份还原的方式进行asp后缀改回,再进行利用。
我的淘宝店:http://shop58394963.taobao.com/,中奖也不信
对管理有异议,请前往事务区进行投诉。请勿PM。

TOP

第一个典型例子是动网7.0头像上传漏洞。
系统检测后缀,不允许的文件为asa、asp、cdx、cer等一些常见的ASP环境下的后缀,却没想到全能空间需要过滤如php\aspx等后缀。
而程序又同时这样处理了:split(FileMIME,"/")(0)<>"image"(我已经找到硬盘上很久前的录像了
也就是说非gif和jpg文件不嫁了
因此把文件头写到一个php或aspx木马前就利用了

而后一个例子是动网7.0后台备份还原问题,只要进入后台且上传了张后缀为jpg的木马图片,利用备份还原就能把jpg木马图片恢复为asp文件进行利用。
因此只要扣好上面几点途径就好了。
我的淘宝店:http://shop58394963.taobao.com/,中奖也不信
对管理有异议,请前往事务区进行投诉。请勿PM。

TOP

谢谢版主。

Fanbin
你的代码很好,让我认识了unpack这个函数。

但是dll的头两个字节解压回来也是:7790,和exe的一样。

TOP

dll就是动态链接库文件,在某些方面上它就是和exe差不多的,甚至有些程序只把exe做为一个外壳,而核心在dll里
至于头两个字节一样,我也没办法,它就是那样的

是你的Java代码给了我提示哈!

TOP

jpg和gif 验证错误没有很大关系,一些关键的文件类型不要检测错误了才是最要的
ThinkPHP->博客

TOP

如果检测GIF/JPG/PNG/BMP格式图片,可以使用getimagesize函数。
如果是其它的文件,可以检测文件头与扩展名。

附一个检测函数
复制内容到剪贴板
代码:
/**
* 检查文件类型
*
* @access      public
* @param       string      filename            文件名
* @param       string      realname            真实文件名
* @param       string      limit_ext_types     允许的文件类型
* @return      string
*/
function check_file_type($filename, $realname = '', $limit_ext_types = '')
{
    if ($realname)
    {
        $extname = strtolower(substr($realname, strrpos($realname, '.') + 1));
    }
    else
    {
        $extname = strtolower(substr($filename, strrpos($filename, '.') + 1));
    }
    $str = $format = '';
    $file = @fopen($filename, 'rb');
    if ($file)
    {
        $str = @fread($file, 0x400); // 读取前 1024 个字节
        @fclose($file);
    }
    else
    {
        if (stristr($filename, ROOT_PATH) === false)
        {
            if ($extname == 'jpg' || $extname == 'jpeg' || $extname == 'gif' || $extname == 'png' || $extname == 'doc' ||
                $extname == 'xls' || $extname == 'txt'  || $extname == 'zip' || $extname == 'rar' || $extname == 'ppt' ||
                $extname == 'pdf' || $extname == 'rm'   || $extname == 'mid' || $extname == 'wav' || $extname == 'bmp' ||
                $extname == 'swf' || $extname == 'chm'  || $extname == 'sql' || $extname == 'cert')
            {
                $format = $extname;
            }
        }
        else
        {
            return '';
        }
    }
    if ($format == '' && strlen($str) >= 2 )
    {
        if (substr($str, 0, 4) == 'MThd' && $extname != 'txt')
        {
            $format = 'mid';
        }
        elseif (substr($str, 0, 4) == 'RIFF' && $extname == 'wav')
        {
            $format = 'wav';
        }
        elseif (substr($str ,0, 3) == "\xFF\xD8\xFF")
        {
            $format = 'jpg';
        }
        elseif (substr($str ,0, 4) == 'GIF8' && $extname != 'txt')
        {
            $format = 'gif';
        }
        elseif (substr($str ,0, 8) == "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
        {
            $format = 'png';
        }
        elseif (substr($str ,0, 2) == 'BM' && $extname != 'txt')
        {
            $format = 'bmp';
        }
        elseif ((substr($str ,0, 3) == 'CWS' || substr($str ,0, 3) == 'FWS') && $extname != 'txt')
        {
            $format = 'swf';
        }
        elseif (substr($str ,0, 4) == "\xD0\xCF\x11\xE0")
        {   // D0CF11E == DOCFILE == Microsoft Office Document
            if (substr($str,0x200,4) == "\xEC\xA5\xC1\x00" || $extname == 'doc')
            {
                $format = 'doc';
            }
            elseif (substr($str,0x200,2) == "\x09\x08" || $extname == 'xls')
            {
                $format = 'xls';
            } elseif (substr($str,0x200,4) == "\xFD\xFF\xFF\xFF" || $extname == 'ppt')
            {
                $format = 'ppt';
            }
        } elseif (substr($str ,0, 4) == "PK\x03\x04")
        {
            $format = 'zip';
        } elseif (substr($str ,0, 4) == 'Rar!' && $extname != 'txt')
        {
            $format = 'rar';
        } elseif (substr($str ,0, 4) == "\x25PDF")
        {
            $format = 'pdf';
        } elseif (substr($str ,0, 3) == "\x30\x82\x0a")
        {
            $format = 'cert';
        } elseif (substr($str ,0, 4) == 'ITSF' && $extname != 'txt')
        {
            $format = 'chm';
        } elseif (substr($str ,0, 4) == "\x2ERMF")
        {
            $format = 'rm';
        } elseif ($extname == 'sql')
        {
            $format = 'sql';
        } elseif ($extname == 'txt')
        {
            $format = 'txt';
        }
    }
    if ($limit_ext_types && stristr($limit_ext_types, '|' . $format . '|') === false)
    {
        $format = '';
    }
    if ($extname != $format)
    {
        $format = '';
    }
    return $format;
}
[ 本帖最后由 wenming 于 2007-12-3 23:03 编辑 ]
珍视拥有的、遗忘失去的。

TOP

那段代码明显不是Java是.net的。
修行的魔法师

TOP