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

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

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.头文件判断,很多人都以为这是最终方案。。。。。。呃,也许吧,不过如果你是4.5以及以后也许就可以这样理解了~~

先贴代码:

/*头文件参考:(我自己测是如有偏差请联系我)
7790:exe,dll
5666:psd
6677:bmp
7173:gif
13780:png
255216:jpg,jpeg

8297:rar
55122:7z
8075:docx,xlsx,pptx,vsdx,mmap,xmind,“zip”
208207:doc,xls,ppt,mpp,vsd
 */
/// <summary>
/// 判断扩展名是否是指定类型---默认是判断图片格式,符合返回true
/// eg:file,"7173", "255216", "6677", "13780" //gif  //jpg  //bmp //png
/// </summary>
/// <param name="stream">文件流</param>
/// <param name="fileTypes">文件扩展名</param>
/// <returns></returns>
public static bool CheckingExt(this Stream stream, params string[] fileTypes)
{
    if (fileTypes.Length == 0) { fileTypes = new string[] { "7173", "255216", "6677", "13780" }; }
    bool result = false;
    string fileclass = "";
 
    #region 读取头两个字节
    using (stream)
    {
        using (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) { 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看看~

上传测试

成功上传了

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

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

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

原文发布于微信公众号 - 我为Net狂(dotNetCrazy)

原文发表时间:2016-07-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏游戏杂谈

Unity项目中文字的统一管理

一款游戏在研发初期就需要考虑多语言的问题,否则后期在进行多国语言版本时就面临着巨大的成本。鉴于之前页游的经验,其它同事设计出读取Excel的方式来管理所有的文字...

14910
来自专栏林德熙的博客

win10 uwp 读取保存WriteableBitmap 、BitmapImage 保存 WriteableBitmap 到文件从文件读 WriteableBitmapIma

我们在UWP,经常使用的图片,数据结构就是 BitmapImage 和 WriteableBitmap。关于 BitmapImage 和 WriteableBi...

14710
来自专栏挖掘大数据

常用的Hadoop 文件查看工具

packages.config <?xml version="1.0" encoding="utf-8"?> <packages> <package id...

21990
来自专栏c#开发者

MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具集成Visual Studio 2013

MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具 经过一个多星期的努力总算完成了单表,多...

471130
来自专栏听雨堂

ASP.NET TreeView相关问题

1、用代码在treeview web控件中,添加node的方法 表字段:编号,父编号,名称 数据: 1 0 中华人民共和国 2 1 湖南 3 1 湖北...

22170
来自专栏Golang语言社区

原子读写性能简单测试

代码如下: package main import ( "fmt" "sync/atomic" "time" ) func benc...

46560
来自专栏飞扬的花生

Html5上传插件封装

      前段时间将flash的上传控件替换成使用纯js实现的,在此记录 1.创建标签 <div class="camera-area" style="dis...

43380
来自专栏函数式编程语言及工具

Akka(29): Http:Server-Side-Api,Low-Level-Api

 Akka-http针对Connection的两头都提供了方便编程的Api,分别是Server-Side-Api和Client-Side-Api。通过这两个Ap...

21980
来自专栏更流畅、简洁的软件开发方式

分页解决方案 之 QuickPager的使用方法(在UserControl里面使用分页控件的方法)

      因为我一直没有在UserControl里面使用过QuickPager分页控件,我都是直接在.aspx里面使用,所以这个bug一直没有发现。后来告诉我...

20370
来自专栏GreenLeaves

C#核编之System.Console类

      顾名思义,Console类封装了基于控制台的输入输出和错误流的操作,下面列举一些System.Console类常用的成员的,这些成员能为简单的命令行...

21050

扫码关注云+社区

领取腾讯云代金券