標籤:
今天群裡有人聊圖片上傳,簡單說下自己的經驗
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看看~
上傳測試
成功上傳了
有人說把圖片另存新檔其他格式就能消除一句話木馬。。。。。呃,好吧,你可以這樣理解~看圖:
滲透的時候一般遇到這種圖片上傳後再二次渲染的,一般直接放棄,因為內部的一句話已經不存在了
至於二次渲染是什麼鬼,可以先自行研究會,先睡了~~~
上傳偽技術~很多人都以為判斷了尾碼,判斷了ContentType,判斷了標頭檔就真的安全了。是嗎?