逆天之路

你以什么眼光看世界,你的世界就是什么。你不相信什么,你的世界就没有什么....

Fork me on GitHub

您现在的位置是:首页>笔记> 当前文章

上传伪技术~很多人都以为判断了后缀,判断了ContentType,判断了头文件就真的安全了。是吗?

作者:dunitian 发布时间:2016-07-16 02:35 点击量:859

分类: > .Net笔记 > 最热技能 > Other

  • 今天群里有人聊图片上传,简单说下自己的经验(大牛勿喷)

    0.如果你的方法里面是有指定路径的,记得一定要过滤../,比如你把 aa文件夹设置了权限,一些类似于exe,asp,php之类的文件不能执行,那么如果我在传路径的时候,前面加了一个../呢,这样这种服务器端的限制就跳过了。(DJ音乐站基本上都有这个问题,以及用某编辑器的同志)

    1.常用方法:这种就是根据后缀判断是否是图片文件,需要注意的是这种格式:文件:1.asp;.jpg  1.asp%01.jpg  目录: 1.jpg/1.asp 1.jpg/1.php 等等,IIS和Nginx部分版本是有解析漏洞的(不要用文件原有名称,eg:1.asp.jpg=》去后缀后的名字就是1.asp)

    /// <summary>
            /// 图片上传
            /// </summary>
            /// <param name="file"></param>
            /// <returns></returns>
            public JsonResult UploadA(HttpPostedFileBase file)
            {
                if (file == null) { return Json(new { status = false, msg = "图片提交失败" }); }
                if (file.ContentLength > 10485760) { return Json(new { status = false, msg = "文件10M以内" }); }
                string filterStr = ".gif,.jpg,.jpeg,.bmp,.png";
                string fileExt = Path.GetExtension(file.FileName).ToLower();
                if (!filterStr.Contains(fileExt)) { return Json(new { status = false, msg = "图片格式不对" }); }
     
                //todo: md5判断一下文件是否已经上传过,如果已经上传直接返回 return Json(new { status = true, msg = sqlPath });
     
                string path = string.Format("{0}/{1}", "/lotFiles", DateTime.Now.ToString("yyyy-MM-dd"));
                string fileName = string.Format("{0}{1}", Guid.NewGuid().ToString("N"), fileExt);
                string sqlPath = string.Format("{0}/{1}", path, fileName);
                string dirPath = Request.MapPath(path);
     
                if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); }
                try
                {
                    //todo:缩略图
                    file.SaveAs(Path.Combine(dirPath, fileName));
                    //todo: 未来写存数据库的Code
                }
                catch { return Json(new { status = false, msg = "图片保存失败" }); }
                return Json(new { status = true, msg = sqlPath });
            }
    2.Context-Type的方法(很多人说这个安全性比上一个高。。。。。呃,也许吧,上面至少还有个文件后缀硬性判断,contentType这玩意抓个包,本地代理一开,直接就可以串改,传的是1.asp,你收的contextType依旧是图片格式,最后保存就玩完了)


    /// <summary>
            /// 图片上传
            /// </summary>
            /// <param name="file"></param>
            /// <returns></returns>
            public JsonResult UploadB(HttpPostedFileBase file)
            {
                if (file == null) { return Json(new { status = false, msg = "图片提交失败" }); }
                if (file.ContentLength > 10485760) { return Json(new { status = false, msg = "文件10M以内" }); }
     
                //判断文件格式(MimeMapping)
                var contentType = file.ContentType;
                if (contentType == null) { return Json(new { status = false, msg = "图片提交失败" }); }
                contentType = contentType.ToLower();
                var extList = new Dictionary<string, string>() { { "image/gif", ".gif" }, { "image/jpeg", ".jpg" }, { "image/bmp", ".bmp" }, { "image/png", ".png" } };
                if (!extList.ContainsKey(contentType)) { return Json(new { status = false, msg = "图片格式不对" }); }
     
                //todo: md5判断一下文件是否已经上传过,如果已经上传直接返回 return Json(new { status = true, msg = sqlPath });
     
                string path = string.Format("{0}/{1}", "/lotFiles", DateTime.Now.ToString("yyyy-MM-dd"));
                string fileName = string.Format("{0}{1}", Guid.NewGuid().ToString("N"), extList[contentType]);
                string sqlPath = string.Format("{0}/{1}", path, fileName);
                string dirPath = Request.MapPath(path);
     
                if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); }
                try
                {
                    //todo:缩略图
                    file.SaveAs(Path.Combine(dirPath, fileName));
                    //todo: 未来写存数据库的Code
                }
                catch { return Json(new { status = false, msg = "图片保存失败" }); }
                return Json(new { status = true, msg = sqlPath });
            }

    如果非要用这个,建议和第一个一起用

    3.头文件判断,很多人都以为这是最终方案。。。。。。呃,也许吧。。。

    先贴代码:

        /*头文件参考:(我自己测是如有偏差请联系我)

            7790:exe,dll

     

            5666:psd

            6677:bmp

            7173:gif

            13780:png

            255216:jpg,jpeg

            

            239187:js

            6787:swf

            7368:mp3

            4838:wma

     

            6063:xml

     

            8297:rar

            55122:7z

            8075:docx,xlsx,pptx,vsdx,mmap,xmind,“zip”

            208207:doc,xls,ppt,mpp,vsd

       */

    /// <summary>
    /// 判断扩展名是否是指定类型---默认是判断图片格式,符合返回true(没有释放stream,请手动:file.InputStream.Dispose();)
    /// eg:图片 压缩 文档:"7173", "255216", "6677", "13780", "8297", "55122", "8075", "208207"
    /// eg:img,"7173", "255216", "6677", "13780" //gif  //jpg  //bmp //png
    /// eg:file,"8297", "55122", "8075", "208207" //rar //7z //zip   文档系列
    /// </summary>
    /// <param name="stream">文件流</param>
    /// <param name="fileTypes">文件扩展名</param>
    /// <returns></returns>
    public static bool CheckingExt(this Stream stream, params string[] fileTypes)
    {
        if (fileTypes == null || fileTypes.Length == 0) { fileTypes = new string[] { "7173", "255216", "6677", "13780" }; }
        bool result = false;
        string fileclass = "";
     
        #region 读取头两个字节
        var reader = new BinaryReader(stream);
        byte[] buff = new byte[2];
        try
        {
            reader.Read(buff, 0, 2);//读取每个文件的头两个字节
            fileclass = buff[0].ToString()   buff[1].ToString();
        }
        catch (System.Exception ex) { stream.Dispose(); reader.Dispose(); return false; }
        #endregion
     
        #region 校验
        for (int i = 0; i < fileTypes.Length; i  )
        {
            if (fileclass == fileTypes[i])
            {
                result = true;
                break;
            }
        }
        #endregion
        return result;
    }
    /// <summary>
    /// 图片上传(理论上需要二次渲染下图片,微软Save的时候有应该有一定的验证[我把含有一句话木马的图片上传,最后会返回一张空图片])
    /// </summary>
    /// <returns></returns>
    public JsonResult UploadC(HttpPostedFileBase file)
    {
        if (file == null) { return Json(new { status = false, msg = "图片提交失败" }); }
        if (file.ContentLength > 10485760) { return Json(new { status = false, msg = "文件10M以内" }); }
        string filterStr = ".gif,.jpg,.jpeg,.bmp,.png";
        string fileExt = Path.GetExtension(file.FileName).ToLower();
        if (!filterStr.Contains(fileExt)) { return Json(new { status = false, msg = "图片格式不对" }); }
        //防止黑客恶意绕过,头文件判断文件后缀
        if (!file.InputStream.CheckingExt())
        {
            //todo:一次危险记录
            return Json(new { status = false, msg = "图片格式不对" });
        }
        //todo: md5判断一下文件是否已经上传过,如果已经上传直接返回 return Json(new { status = true, msg = sqlPath });
     
        string path = string.Format("{0}/{1}", "/lotFiles", DateTime.Now.ToString("yyyy-MM-dd"));
        string fileName = string.Format("{0}{1}", Guid.NewGuid().ToString("N"), fileExt);
        string sqlPath = string.Format("{0}/{1}", path, fileName);
        string dirPath = Request.MapPath(path);
     
        if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); }
        try
        {
            //todo:缩略图    水印
            file.SaveAs(Path.Combine(dirPath, fileName));
            //todo: 未来写存数据库的Code
        }
        catch { return Json(new { status = false, msg = "图片保存失败" }); }
        return Json(new { status = true, msg = sqlPath });
    }

    其实这个很好欺骗的,好几种方法,简单说2种:

    第1个,用Copy命令

    生成了一句话图片木马

    第2个,用edjpgcom 打开一张图片就可以直接插入一句话木马了

    图片跟之前看起来没什么不同的

    WinHex看看~

    上传测试

    成功上传了

     

    有人说把图片另存为其他格式就能消除一句话木马。。。。。呃,好吧,你可以这样理解~看图:

     

    渗透的时候一般遇到这种图片上传后再二次渲染的,一般直接放弃,因为内部的一句话已经不存在了

    至于二次渲染是什么鬼,可以先自行研究会,先睡了~~~



关键字词  毒逆天  原创

 

毒逆天