作者:白远方 June 18, 2007
关键字:rootkit,反主动防御,网络监控,ring0,mcafee8.5i,KIS6,ZoneAlarm Pro,实用级产品测试
目录:
反主动防御rootkit的产生背景及其必要性
反网络访问主动防御
反API钩子进程行为主动防御
反系统Notify进程行为主动防御
绕过监控进入ring0安装驱动
实用级反主动防御rootkit的通用性问题
反主动防御rootkit的产生背景及其必要性
当前随着新型木马,病毒,间谍软件对网络安全的威胁日益加重,传统的特征查杀型的安全产品和简单的封包过滤型防火墙已不能有效保护用户,因此各大安全公司纷纷推出自己的主动防御型安全产品,例如卡巴斯基kis6,mcafee8.5i,ZoneAlarm Pro等,这些产品应对未知的病毒木马都有很好的效果,若非针对性的作过设计的木马和rootkit,根本无法穿越其高级别防御。因此,反主动防御技术,作为矛和盾的另一方,自然被渗透者们提上日程;由于主动防御安全产品的迅速普及,为了不使后门木马被弹框报警,具有反主动防御能力的rootkit成为了一种必然选择。
反网络访问主动防御
几乎现在每个防火墙都具有应用程序访问网络限制功能。一个未知的程序反弹连接到外网,或者是在本地监听端口,基本上都会引起报警。而且对系统进程的行为也有了比较严格的审查,原先的注射代码到winlogon等系统进程,在向外反弹连接的方法,很多主动防御软件都会阻止了。
很多防火墙的应用程序访问网络限制,都可以通过摘除tcpip.sys上面的过滤驱动,并还原tcpip.sys的Dispatch Routines来绕过。据称这是因为在ndis层次取得进程id不方便而导致的。但是如果在一个实用级的rootkit里应用此方法则是不智之举,因为存在部分防火墙,如ZoneAlarm,其ndis过滤层必须和tdi过滤层协同工作,才会放行网络连接。至于ndis层次的中间层驱动的摘除,和NDIS_OPEN_BLOCK的还原,则是一项不太可能完成的任务,因为无法从原始文件中读取的方法,获得NDIS_OPEN_BLOCK的原始值;即使能够成功恢复ndis钩子,也不能保证系统可以正常运行,很可能会出现各种不明症状。
到现在为止,绕过应用程序访问网络限制最好的选择,还是那两个:简单的一个,注射代码到一个ie进程,用它反弹连接出来,访问外网;复杂的选择则是应用内核驱动,如ndis hook/添加新的ndis protocol,来实现端口复用,或者使用tdi client driver反弹连接。已经有很多木马和rootkit使用前者,因其简单易行,在实际开发中工程量小,出现问题的可能性也少得多,产品成熟的时间代价也小。但是目前很多的主动防御已经注意到这一点,并且在程序行为监控中严密防范了其他程序对ie的感染行为。
如图,想要使用僵尸IE访问网络的木马被拦截
反API钩子进程行为主动防御
接下来是主动防御系统的很重要的一部分:进程行为监控。该部分主动防御软件一般通过两种解决方案来执行,一是API钩子,二是windows支持的notify routine。
大量的主动防御安全软件,如KIS6,ZoneAlarm Pro,使用API钩子来监控进程的危险行为。如注射远程线程,启动傀儡IE,加载驱动,注册服务,修改敏感系统注册表键值等。但是作为一个rootkit,完全绕过这些操作,基本上是不可能的;于是摆放在面前的任务,就是如何击败这种主动防御。
对于特定种类的监控,总是有特定的方法可以绕过。比如注射远程线程,如果常用的CreateRemoteThread被监控了,可以尝试采用Debug API, SetThreadContext的方法绕过,也可以尝试采用hook其ntdll!ZwYieldExecution等频繁调用的函数来装载自己的DLL模块。注册表监控,我的朋友xyzreg曾经写过系列文章,提出了很多种方法,包括RegSaveKey, Hive编辑等方法绕过卡巴斯基的注册表监控,其Hive编辑的方法目前仍未能有任何主动防御系统拦截。
但是从一个通用型,为实战设计的实用型rootkit来说,采用这些特定的技术并不是一个非常好的选择;因为这些技术可以保证对付一个主动防御软件,却不能保证通用,甚至通用性很差。而且针对每一个可能被主动防御拦截的行为,都采用一套特定的绕过技术,从工程代价上来讲,太过巨大,开发耗时,等其成熟更是不知道要多少时间来测试和更改。因此我们需要的一个相对涵盖范围广,能够解决绝大多数主动防御技术的解决方案。
针对API钩子实现的进程行为监控,一个较好的通用解决方案就是卸载所有安全软件所安装的API钩子。为兼容性和稳定起见,几乎所有的安全软件在安装API钩子时都会选择hook SSDT表,例如KIS6,ZoneAlarm Pro。我们如果能够进入ring0,就可以使用一个驱动程序,读取系统文件ntoskrnl.exe/ntkrnlpa.exe/ntkrpamp.exe,从中提出我们所希望的SSDT表的原始函数地址,替换被安全软件hook的地址,用此方法可以通用性很好的解决绝大多数的API钩子实现的进程行为监控。不过此方法有一个前提,就是事先必须绕过监控进入ring0。关于如何实现此前提,请阅读第五部分,“绕过监控进入ring0安装驱动”。
如图,ZoneAlarm Pro更改了大量的SSDT函数地址来监控程序行为。
反系统Notify进程行为主动防御
部分主动防御安全软件不仅仅是用API钩子,同时使用了微软提供的Notify Routine,来监视进程的行为。使用该技术的安全软件不是太多,但是也不至于少到一个实用级别rootkit可以忽略的程度。
以下几个微软DDK函数,PsSetCreateProcessNotifyRoutine,PsSetCreateThreadNotifyRoutine,PsSetLoadImageNotifyRoutine,被用作支持主动防御软件监控新进程的建立,新线程的建立,和一个新的模块被加载。处理该种类型的防御不能简单的清空NotifyRoutine就完事,因为系统本身,还有一些第三方正常模块和驱动,可能添加和使用该链表。
解决方案,一是可以先将使用了该技术的主动防御系统的驱动程序模块做一个列表出来,然后遍历这三条链表,找出地址指向这些驱动模块的项,再将这些项删除脱链。但是这需要对大量主动防御系统的研究和测试,并且通用型也不好。第二种方法,由于Notify Routine的监控力度要远弱于API钩子,因此在纯ring3将程序做一些小的改动,就可以越过这种类型的监控。
另外还有几个SDK函数,可以提供对文件和注册表的更改的notify。不能排除也有部分主动防御软件使用了它们。例如国产的超级巡警(AST.exe),使用了RegNotifyChangeKeyValue,做了对注册表敏感键值修改的事后警告提示。如果仅仅使用了API钩子清除技术,那么在此时就会被AST报警。和以上介绍的三个内核notify类似的也是,有不少正常的notify在被使用,不分青红皂白的全部卸载,会导致系统异常。
因此可见,Notify类监控虽然使用的不多,但是其对付的难度和需要的工程量,比API监控还要大。
如图,已经处理了API钩子监控的rootkit仍然被notify方式的AST报警。
绕过监控进入ring0安装驱动
这部分是重中之重。由于几乎每个主动防御系统都会监控未知驱动的加载和试图进入ring0的举动, 而我们在第一,第二和第三部分绕过主动防御要做的处理,都必须需要ring0权限。因此监控进入ring0,是一个独立的话题,也是我们实现前三个部分需要的条件。
直接添加注册表项,ZwLoadDriver安装驱动,是几乎要被任何主动防御系统报警。必须要采用一些隐蔽的或者是为人不知的方法。总结目前已经公布出来的进入ring0的办法,
有以下几种:
感染文件,例如win2k.sys,添加自己的代码到里面,启动的时候就会被执行。这种方法的优点是简单易行,稳定度和兼容性很好。但是最大的缺点就是必须重新启动以后,才能进入ring0,这是一个产品级别的后门所不能容忍的。而且微软自己的系统文件保护容易绕过,mcafee和卡巴斯基的文件监控可就不是那么容易了。
利用物理内存对象,来写入自己的代码到内核,并添加调用门来执行。这个是最早被人提出的不用驱动进入ring0的办法。因为出来的时间太长了,所以有以下一些问题:更新的操作系统内核不支持,如2003SP1;很多的主动防御系统会拦截,例如KIS6。所以这个办法也不理想。
利用ZwSystemDebugControl。这个代码在国外有人放出来过,利用它写内存,挂钩NtVdmControl,进入ring0。此法缺陷在于老的windows2000不被支持,最新的windows2003sp1上也取消了这个函数的此能力。不过好处在于,这个方法用的人少,基本上没有主动防御会注意到它,并进行拦截。
利用ZwSetSystemInformation的SystemLoadAndCallImage功能号加载一个模块进入ring0。这个方法提出来比较久了,但是因为用的人少,仍未被主动防御软件所重视。用得少的原因是,它不好用。它只能加载一个普通的模块到内核并且调用,却不是加载一个驱动,因此没有一个DriverObject。这导致了非常多的麻烦。因为要想使用这个办法,必须先用这个办法安装一个简单的内核模块,再用这个模块添加调用门等方式,执行代码清除主动防御的监视驱动安装的钩子,安装一个正常的驱动,才能最终完成任务。而且这个方法似乎对windows2003sp1以上的系统也无效。
因此,要想有一个相对完美的进入ring0解决方案,最好是寻找别人不知道或者使用很少的方法,或者将上面的有缺陷的方法做一个综合,用多种方法通过判断情况来选择使用。我在这里有一个新的思路提供给大家,微软新公布了一部分文档,关于HotPatch的使用。HotPatch可以在执行中修改系统中存在的用户态公用dll的内容,甚至是修改内核模块的内容。具体代码和细节,在这里我不能多说。
要想开发一个好的反主动防御rootkit,绕过监控进入ring0是必不可少的,然而这部分也是使用不成熟技术最多的,最容易出现严重问题的部分。作为一个负责任的实用级产品,一定要对这个部分作做详细的测试,来保证自己的产品不会在某些特殊的环境,比如64位CPU运行32位系统,多核处理器,HyperThread处理器上面,出现故障或者蓝屏。
实用级反主动防御rootkit的通用性问题
前文已述,本文的宗旨在于讨论一种实用级别rootkit开发的可行性。因此,工程量的大小,需要投入的人力,时间和金钱,也是我们需要考虑的内容。必须要考虑更好的兼容性通用性,和工程上的开发代价和稳定成熟周期不能无限大。因此,对于部分新技术,例如BiosRootkit,VirtualMachine-Rootkit,本文不做讨论,因为那些都属于如果要想做稳定通用,工程代价非常大,以至于他们只拥有技术上面的讨论价值,而不具备作为一个产品开发的可选解决方案的可能性。至少是目前来看是如此。
每个主动防御软件的原理和构造都是不相同的,因此不可能指望有某一种方法,从工程上可以解决一个主动防御系统,就可以无需测试的,保证无误的解决其他系统。因为这个原因,开发一个成熟稳定的反主动防御rootkit,必然要在兼容各种主动防御的系统的通用性上面下大功夫。按照不同的主动防御系统,在程序里switch case,应该是非常必要的,尽管绝大多数反主动防御代码原理上可以通用。基本上,在测试程序通用型的时候,常用的主动防御软件,是每种都要安装一个并且仔细测试的。
以下举例说明,几个常用主动防御系统各自需要注意的特点,这都是笔者在实际开发中遇到的比较典型的例子。
Mcafee8.5,该主动防御软件在最大化功能时会禁止在系统目录下创建可执行文件,光这一点就会让几乎全部rootkit安装失败,若非针对它做了设计。在这个系统下面,也不可能使用感染文件的方法来进入ring0。
KIS6,该系统会自动列举运行的隐藏进程,并且弹框警告。因此在这系统下,不太可能把自己的进程隐藏。而且它列举隐藏进程的手段很底层,很难绕过。
ZoneAlarm Pro,该系统下,如果一个其它的进程启动IE并且访问网络,安全报警仍然会以该进程本身访问网络为准执行,另外还会弹框警告,除非将自己的僵尸IE进程的父进程更改,或者不用IE来反弹连接。
国产的瑞星,总体来说这个系统的主动防御弱于国外产品,但是它特殊在于,会对IE作出非常严格的限制,默认不允许IE装载任何非系统的dll。因此在这个系统下基本不可能利用IE反弹。
其他的特殊情况还有很多。作为一个成熟产品开发者,这些都是必须要考虑的。