4.ASP.NET VirtualPath型内存马

2024-11-22 19:16   广东  

1.关于VirtualPathProvider

这其实是ASP.NET提供的一种特殊功能,中文名叫虚拟文件,顾名思义,这不是一个真实的文件,但是却能在WEB上访问到这个文件,一听这个性质其实就挺内存马的,来学习一波。那么要怎么利用它做一个内存马呢?首先要实现VirtualPathProvider这个抽象类

里面有挺多方法的,这里先学两个,分别是FileExists()、GetFile(),前者主要是用来配置虚拟文件对应的URI的命中规则,后者主要是配置这个虚拟文件的内容,其中GetFile()需要返回VirtualFile类型

跟进一下VirtualFile类

有一个Open()方法需要实现,注意到这个方法返回一个Stream,其实就对应我们虚拟文件的内容,因此可以重写Open()返回恶意代码。

从上面这些代码可以先想到两种实现VirtualFile内存马的方式。第一,既然FileExists()在虚拟文件的生命周期中会被自动触发,那么我们可以在其中实现恶意代码,我们还可以研究一下有没有其它类似的方法起到这样的效果。第二,我们可以通过GetFile()返回一个恶意的VirtualFile类,在这个类的Open()方法中返回恶意文件内容,也可以实现内存马。


2.实现恶意VirtualPathProvider类并注册

这里我们先来学习一下第二种,通过GetFile()方法返回虚拟文件内容的思路,参考yzddmr6师傅的代码,关键其实是这几段:

SamplePathProvider类是VirtualPathProvider的实现类,其中实现GetFile()方法。当判断一个路径是虚拟文件路径时,返回SampleVirtualFile类的对象(这是VirtualFile类的实现类)

SampleVirtualFile类里记得实现Open方法,返回文件内容:

这样就写好了一个恶意的虚拟文件类SamplePathProvider(),其构造方法接受虚拟文件路径和内容,触发虚拟路径后会运行到SampleVirtualFile类中的Open方法返回恶意代码,这样就相当于一个内存马了。然后怎么注册它呢?答案是调用

HostingEnvironment.RegisterVirtualPathProvider()  //看名字就知道是用于注册的

这里还有个问题就是VirtualPathProvider继承了MarshalByRefObject,之前在学习.NET Remoting和ObjRef链的时候了解过这个类,里面有一个独特的租约机制,用于控制实例的生存期,需要对我们做好的恶意虚拟文件对象调用一下InitializeLifetimeService()方法,让内存马持久存活。

运行上述代码注入内存马后,访问/test.aspx地址:

用哥斯拉连接一下:

这就说明我们的虚拟文件内存马注入成功了。可以看到这种内存马还是非常方便的,我个人非常喜欢这种内存马,足够简单也足够可靠,可以把你想要的几乎任何aspx文件直接打成内存马,只需要改动base64编码的内容即可。


3.使用FileExists方法创造内存马

实际上也不一定完全要按照上面的那个流程去创造,前面提到过FileExists()用于配置虚拟文件URI的命中规则,等于说在虚拟文件生命周期中会被自动触发,像这样的方法都是可以在里面实现恶意代码令其成为内存马的,并且这些方法里拿到httpcontext对象也比较容易,获取请求和设置响应都比较方便。比如这里实现FileExists,在其中调用恶意代码,参考:

https://exp10it.io/2024/02/asp.net-%E5%86%85%E5%AD%98%E9%A9%AC/#getcachekeyfileexists

注入就还是老样子:

由于这个FileExists()的特性,当你访问一个存在or不存在的路径时都会触发它,所以效果类似于JAVA那边注入了一个uri规则为/*的Filter型内存马,随便访问一个路径,加上cmd参数执行命令即可


4.使用GetCacheKey方法创造内存马

除了FileExists,虚拟文件生命周期中还会触发GetCacheKey方法,也可以在这里实现恶意代码。并且这个方法优先于FileExists触发。不过得访问已存在的文件时才能触发GetCacheKey。

注入完后,访问一个不存在的路径就没法触发GetCacheKey()

但是,目标已有的一些路由规则,或者是目标真实存在的aspx之类的文件,都可以触发,比如我这里用已有的路由规则去触发:

再比如随便找一个可访问的ASP.NET相关文件,我这里创建一个空的aaa.aspx文件

依然可以成功访问到


5.绕过预编译限制

前面我们学习了注册虚拟文件的关键方法是

RegisterVirtualPathProvider()

而它又是靠

RegisterVirtualPathProviderInternal()

方法实现注册的

要走到

RegisterVirtualPathProviderInternal()

可以注意到有一个if()判断,只有

BuildManager.IsPrecompiledApp

值为false,才可以正常注册虚拟文件。

这个BuildManager.IsPrecompiledApp是什么呢?其实这个就是用来判断是否开启预编译的,如果开启了它的值就会变成true,虚拟文件就无法正常注册了。

解决方法也很简单,调用RegisterVirtualPathProvider()之前把它的值强行改成false即可。


6.绕过FriendlyUrls

这个技术可以把ASP.NET的Uri风格改为类似RestFul的风格,比如我有一个test.aspx文件,可以直接用test去访问。这个会影响基于VirtualFile(GetFile)的虚拟文件内存马。

题外话,不知为啥感觉ASP.NET的开发者们特别执于实现这种效果,除了FriendlyUrls,还有一个在web.config里可以开启的配置项ExtensionlessUrlHandler,也可以把URL去掉aspx变成类似RestFul风格(会造成一些鉴权绕过问题)

FriendlyUrls实现的方法其实也是往RouteTable.Routes里插入一个特殊的Routes规则,绕过FriendlyUrls的方法也是靠反射,先从RouteTable.Routes里拿到对应的对象,然后改掉其配置项里的AutoRedirectMode

7.参考

https://yzddmr6.com/posts/asp-net-memory-shell-virtualpath/#%E7%BB%95%E8%BF%87%E9%A2%84%E7%BC%96%E8%AF%91https://exp10it.io/2024/02/asp.net-%E5%86%85%E5%AD%98%E9%A9%AC/#%E7%BB%95%E8%BF%87-friendlyurls


HW专项行动小组
大师!教我打攻防
 最新文章