当前位置:编程学习 > asp >>

Asp.Net HttpModule初探与简单应用

  • 0x01:起因

    偶然间读到一篇讲解.net执行流程的文章(http://www.zzzyk.com/kf/201112/115301.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()即可。

    第三点是一些零零散散的地方,例如检查..防止任意文件下载,检查~防

    补充:综合编程 , 安全编程 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,