现在的位置: 首页 Asp.Net >正文

Asp.Net HttpModule初探与简单应用

还是很久之前的文章,文中强奸蜘蛛的手法早已经没用了,不过改改当成探针也不错,例如根据UA针对性的输出一些js获取信息之类。

后门部分算是对 C#版菜刀一句话,留后门专用  的第一次补充,全局模块后门有时在网站改版后会救人一命。

最后,这个玩意的工程和源码同样忘了打包,想要源码的直接Reflector吧,没用各种高级特性各种语法糖,反编译出来的跟源码是一样的。

需要强签名的自己用sn生成一个。


0x01:起因

偶然间读到一篇讲解.net执行流程的文章(http://www.cnblogs.com/sunfny/archive/2010/08/22/1805796.html ),文章中提到的一句话引起了注意:


Http请求通过一系列Module,这些Module对Http请求具有完全的控制权。这些Module可以做一些执行某个实际工作前的事情。

Http请求经过所有的Module之后,它会被HttpHandler处理。在这一步,执行实际的一些操作,通常也就是.aspx页面所完成的业务逻辑。

HttpHandler处理完以后,Http请求再一次回到Module,此时Module可以做一些某个工作已经完成了之后的事情。


这里提到了HttpModule优先于页面执行,也就是说借助HttpModule我们可以在页面执行前做一些我们想做的事,不由自主地,一些淫荡的想法慢慢滋生出来。


0x02:示例

光想不做是YY,这里给出三个已实现的例子,权当抛砖引玉。希望各种大牛小牛撼地神牛集思广益,想出其他的一些利用方式。


首先想到的就是喜闻乐见的强奸蜘蛛。众所周知现在的.net强奸蜘蛛方式基本都是通过global.asax判断user-agent来确定是否劫持,但这里有一个最明显的缺点:global.asax的劫持方式是基于session的(也就是global.asax文件中的Session_Start方法),如果在一个session周期内连续请求两次,那么只有第一次的请求结果是我们需要的劫持后的页面(由于不做黑产,不能确认搜索引擎是否使用这种方法来判断站点劫持与否,但这个缺点却是实实在在的)。但是如果借助HttpModule就完全不同了,只要特征符合,基于Request(HttpApplication.BeginRequest)的HttpModule就会忠实的输出想要输出的东西。


之后便是后门。事实上在开始接触HttpModule的时候刚好写完那个留后门专用的菜刀一句话(System.WebServices.dll),尝试将其变为一个HttpModule并添加到站点中,结果就是站点下大部分通过aspnet_isapi.dll处理的文件(.aspx/axd/.asmx/.ashx)均变为了一句话,而在后续测试中发现只要拓展名相匹配,即使文件并不存在也是可以成功连接的,对于隐藏shell真的是太便利了。另:连接index.aspx/login.aspx等常用页面是针对于日志记录很好的隐蔽方法。


最后是密码记录,记录一个预编译的.net站点密码真是很麻烦(曾经见到把所有代码都编译到类库中,而每个aspx文件中都只有一句“不应删除的预编译文件”的站),用JS记录可能被发现,而且对于某些自动提交表单的登录工具可能是完全无效的。而使用HttpModule则将一切都变得简单:首先获取HttpContext.Current.Request.Url.AbsolutePath属性的值,判断是否为验证页面;之后获取HttpContext.Current.Request["User"]与HttpContext.Current.Request["Pwd"]的值,如果非空就记录到文件或使用System.Net.WebClient类提供的UploadData(对应HTTP POST)或DownloadData(对应HTTP GET)方法将数据发送至箱子中。


0x03:编写与使用

HttpModule在编写的时候极为简单,在项目中添加System.Web引用,编写一个实现IHttpModule接口的类,并在类的Init方法中添加HttpApplication.BeginRequest事件的处理方法,在处理方法中完成要做的操作,最后编译为类库即可。代码所处命名空间与类库的名称最好起为类似于System.WebSecurity等迷惑性强的名称,同时程序集信息全部仿照正常的.net组件以达到最好的迷惑效果(可以使用Reflector加载系统程序集来查看信息)。


而在使用HttpModule的时候只要将HttpModule放至/bin/目录下,并配置web.config的system.web节点下面的httpModules子节点,添加一个类似于


<add name="WebSecurity" type="System.WebSecurity.PageSecurity"/>

的节点即可,具体请参见上面给出的那篇文章。

PS.一些可自定义的参数如一句话的密码、密码记录器要监控的页面等可以在appSettings节点下添加类似于

<add key="KeyName" value="KeyValue"/>

的子节点,并在模块中使用System.Configuration.ConfigurationManager.AppSettings["KeyName"]语句来获取约定的值。

为了迷惑,可以将KeyName起为类似于SecurityInitalize的名称,并将value进行Base64编码(为了防止被解密可以先进行DES加密,由模块进行解密)。

另外,如果需要按照约定的格式请求一个并不存在的文件也能正常显示(例如一句话),请在方法结束时调用HttpContext.Current.Response.End()方法终止输出,以防文件不存在时出现404错误。


0x04:全局模块的创建

可能看了上面的文章你已经觉得HttpModule的功能相当强大,可惜它还是有着很大的不足。最大的不足就在于需要将文件放在/bin/目录中,这种方法不一定能瞒过聪明的管理猿。当然,在只有Web权限的时候我们只能做到这么多了,毕竟这也是相当隐蔽的做法(最大的优势便是不为人知,各种杀软与网马查找工具全部哑火)。而当成功获取服务器权限的时候,一切就都不一样了。


设想一个模型:通过某种方式成功获取到了服务器权限,脱裤发现密码使用了高强度的SHA(PWD+MD5(PWD))加密,由于进一步渗透的需要只能使用密码记录。而服务器上面存在多个分站,分站由于不同属所以密码不是通用的,为了记录密码不得不依次在站点添加记录模块,如果站点一多的话……天啊,让春哥菊爆了我吧。

设想第二个模型:同样的通过某种方式成功获取到了服务器权限,装上远控之后为了保险希望同时在多个站点留下后门。当你手忙脚乱的慢慢依次安装时是否有一种大吼的冲动:“难道没有一种简单的方式复用同一模块吗?”


答案是有的,GAC(Global Assembly Cache,全局程序集缓存)完美的解决了这一点。你可能注意到类似于System.Web等Frame Work自带的程序集从来都不需要放在/bin/目录中也可以正常调用,这便是GAC的作用了。

如果想把编写完成的模块加入至GAC,需要将其进行强命名,创建强命名程序集的方式见:http://wenku.baidu.com/view/d47064dcd15abe23482f4df1.html ,这里不做赘述。

之后将编译好的强命名程序集拖放至%systemroot%\assembly中即可,或使用gacutil.exe /i AssemblyFileName命令加载。要注意,单纯的复制进%systemroot%\assembly目录是完全无用的。

最后便是配置web.config了,当然,这里不用繁琐的依次配置站点目录中的web.config(虽然写个程序批量修改也不是什么困难的事情),只需要配置%systemroot%\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config即可(不得不说.net的这个特性实在太好用了)。


由于我们的程序集是强命名的,所以添加模块时节点中type属性的值也要做相应的修改,下面是一个合法的示例,注册了名为WebConfiguration的模块(这个名称没有多大意义),模块对应的类为System.WebConfiguration.InitPageConfiguration,程序集为System.WebConfiguration,程序集版本为2.0.0.0,区域为neutral,公钥标记为38a562ed75a84829。公钥标记获取方式可以参考上面创建强命名程序集的那篇文章,而其余的四个属性都是在编写时自己定义的。


<add name="WebConfiguration" type="System.WebConfiguration.InitPageConfiguration,System.WebConfiguration,Version=2.0.0.0, Culture=neutral, PublicKeyToken=38a562ed75a84829"/>

另外,由于web.config默认没有appSettings这一节点,所以要手动添加。appSettings节点是与System.Web同级别的节点,修改时需注意。


来看看最终的效果吧:如果添加的是一句话模块,那么服务器上所有asp.net的站点下任意一个.net支持的页面都可以作为一句话连接(例如http://www.fuck.com/神兽草泥马.aspx可以直接连接,而不论 神兽草泥马.aspx是否存在。);如果添加的是蜘蛛劫持模块,那么整个服务器上面所有的asp.net的站点都会被劫持;如果添加的是密码记录模块,那么所有向符合条件的链接提交的数据都会被记录并发送/记录。这看起来似乎与添加IIS ISAPI拓展来留后门有些相似,但二者的隐蔽程度是完全不能同日而语的(我完全不能相信管理员有没事查看assembly目录的习惯,更多时候他们或许根本不知道后门可以隐藏在这里,更何况程序集名称也具有很大的隐蔽性)。


0x05:关于防护模块的设想


说了这么多不妨换个思维来思考安全的编写,毕竟学习信息安全最终的目的不是入侵而是防护,入侵不过是相对来说较快的学习方式罢了。限于时间原因没有编写出示例,所以在这里单提出来作为一个设想,有兴趣的可以自行尝试。


第一点便是全局防注入。由于HttpModule可以在HttpHandler(可以理解为具体的页面)执行前拦截一切的操作,这为功能的编写提供了极大的便利。众所周知的asp防注入基本都是在具体的某个页面include一个防注入页面,而HttpModule优先于页面执行的特性恰恰做到了这一点,余下的判断、过滤等代码自不用多说,参考asp的代码即可。至于日志功能则可以借助System.Data命名空间下的一系列类与方法来写入到数据库中。

另外,可以创建一个专有的配置文件,里面规定某些参数必须是指定的类型(例如规定ArtileID为int),在模块中读取配置文件的属性,并使用Convert类进行类型转换,抛出异常则终止运行并显示禁止信息即可。


第二点则是变相禁止目录执行。借助HttpModule的特性,可以先使用HttpContext.Current.Request.Url.AbsolutePath获取当前的虚拟路径,判断(在配置文件中规定一个允许的列表)是否允许执行,如果不在允许执行的目录中,直接调用HttpContext.Current.Response.End()即可。


第三点是一些零零散散的地方,例如检查..防止任意文件下载,检查~防止爆路径(这个只是听说,没有遇到过),日志查询的接口,修改配置文件的接口等等。


当然,和狗神盾之类专业防护软件当然是不能相提并论的,但轻量级、可以与站点同时发布的模块在某些时候未必不是一个好的选择。


0x06:附件

压缩包中System.WebSecurity是蜘蛛劫持模块,System.WebConfiguration是菜刀一句话,在对应的web.config中有详细的说明。这两个模块可以直接使用(前缀为Signed-的类库已经过强签名,使用时需去掉Signed-前缀。)

pwdlogger.cs是密码记录的DEMO,由于测试时直接放在App_Code目录中调试导致未编译,若有需要请自行编译与签名。


下载:      HttpModules.zip

百度网盘:http://pan.baidu.com/s/1c0CJUtq

解压密码见注释。