注:屏蔽本漏洞的紧急通知: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.gif type = "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都拿下了,其它也就都没什么可说的了,
今天就先到这吧。。。还得写文档,明天演示项目,注定又是一个无眠夜。。。