Qbot – .vbs file full deobfuscation

Got a bunch of phish that were slip-streamed in from a compromised account the other day. But for some reason, this one stood out from the rest…

Challenge accepted! Amongst the phish we received, all of the URLs were similar in that you downloaded a zip file from a wordpress site.


Inside the .zip file was a single .vbs file. You can get your own copy here:


Based on the any.run activity, we can see the .vbs file reaches out to corbuchrochet.com along with a base64 encoded string of system information.


Yet, is this all there is to this script? What follows will be a full deobfuscation of the .vbs script in the downloaded .zip file. I’m not doing this just for intellectual pursuits. The danger of relying on a sandbox alone is that you may miss other indicators of compromise. And we’re going to find out that’s the case here. A link to the deobfuscated file can be found at the bottom.


Upon opening the .vbs file, we see that it is filled with a ton of garbage… over 10 megabytes, actually. Most of it is taken up by the green text below. But what about the rest of it? Line 10 contains a string that is over 41,000 characters long. That is likely not garbage. There’s also a bunch of math and other variables scattered throughout the script. Is it useless?

Base64 strings

After getting rid of the green text, we’re left with something a bit more manageable. We can see scattered throughout the script is a function named MRJTm() next to some base64 encoded strings. It’s a safe bet that MRJTm() is the function that decodes those strings. If you go and investigate it, you’ll see that it does. We could do a search/replace of MRJTM to something like decode_base64 in order to make our script easier to read.

Line 264: wscript.shell
Line 268: Looks like whatever gets downloaded ends up in %TEMP% and named PaintHelper.

Cleaning up more garbage in functions

At this point, there’s still a bunch of garbage text that needs to be removed. This is where the long slog through the .vbs script begins. How to tell what is needed and what isn’t?

Let’s use this function near the bottom as an example. We can see the function name of bZfje is also used as the return variable. The parameter fed to the function (JlpGX) is tossed into Cstr(), a .vbs command that turns an expression into a string. Note, that none of the other variables are used in this function at all.


If we rename the function with what seems to be its purpose and get rid of the extraneous variables, we end up with this instead.


I then started from the bottom of the script and kept getting rid of extra variables. Here’s some more that got cleaned up.

What about those URLs?

In order to explain this, I’m going to grab some important lines from the script. This means that what you’ll be seeing next is not the original section of script that you’ve seen above. This is meant to help illustrate what is going on.

First, line 96 contains the base64 encoded string for “GET”. This is the line that reaches out to download something. Variable LidvFFe will be the actual URL and variable Zbqxn gets tacked onto the URL.

LidvFFe comes from line 90. It takes the string fed to the function (param_01) and splits it on seven underscore characters. Line 86 calls function CBvJkMY with a parameter of YToIIxnf.

Variable YoIIxnf (line 86) is ultimately derived from variable HMTkcZ (line 2). Function hYpafX (lines 4-79) is used to decode HMTkcZ several times (lines 82-84). This output gets saved into YoIIxnf which as we’ve seen makes its way to variable LidvFFe (line 96).

Since we’ve determined that line 96 is where the URL is called (variable LidvFFe), I put a wscript.echo command right after it (line 97, above). If we call up our script from the command line with cscript, variables LidvFFe and Zbqxn should be printed to the screen. Note, you’ll have to remove the apostrophe that comments out the line.


Decoded base64:    Windows Defender - 6,21,0|Microsoft Windows 10 Pro

We can then see all four URLs contained in this script. Tacked onto the end is a long string of base64 encoded text. While it is simple enough to decode it and see what it contains, how did it get there?

Getting System Information

Variable Zbqxn comes from line 92. The information in it originally comes from function uTFjNC which grabs system information, which then gets fed into VUjtEX and encoded into base64.

Function uTFjNC is mostly a bunch of hex characters and junk code.

However, if we condense the hex characters, get rid of the junk code, and rename some variables, it begins to make more sense. The script is creating a WMI instance to query information about the machine. Seems like it is looking for AntiVirus products and information on the Operating System.

Persistence: Task Scheduler

Finally, this script establishes persistence. After an executable gets downloaded to the Temp folder and named PaintHelper.exe, the script creates a scheduled task. Look for the variable named margaritasexy to see the beginning of that section. It calls up Schedule.service on line 388.

From there it sets up things like the name of the task, what time it will run, and what will be executed. Here’s what it looks like in Task Scheduler and in the registry.

NOTE the red arrow pointing from Id to the Tasks folder. That ID ({56D3…}) also has an entry in the Tasks folder above. That needs to be deleted as well.

My deobfuscated script

As promised, my cleaned-up script can be found here: https://pastebin.com/F3QiP9rG

And as always, thanks for reading.