The sample from this one comes from Packet Wire @packet_Wire. Twitter thread here
After getting the location of the Word document and downloading it. The file name was “Auditor-of-State-Notification-of-EFT-Deposit” with hash values of.
Let’s dive into the macro.
Using LibreOffice we can see in the code under Document objects –> vUwdwkwHZAwSRz –> Private Sub Document_open() . It will eventually launch VBA[.]Shell with a reassembled string.
Looking at the bottom we see it contains 3 scripts.
So we can now extract these 3 scripts and open them up in Notepad++ or your favorite text editor.
Before we leave the document we also want to check if there are any property’s we may need for decoding or any forms that may have any pre-filled values that we may also need later. In this case there are none.
The screenshot above goes over the various parts that makes up this “Style” of encoding. I have decoders/string builders for 5 other versions and I am sure I have missed a few more in-between.
If we search for the two values in the beginning of the “VBA.Shell” line and to the left of the “CVar(“C”)” there are no other hits on the names so those are just junk inserted and will get handled when not found with the “On Error Resume Next” routine.
If we take a look at the script we saved as “BlUkafEw” then we can see that this entire script contains junk code that does not get used except as a distraction/time waster.
One of the next things we may notice is the heavy use of “CStr”.
Here we see the “CStr” wraps the “Chr” function to convert a numeric char code to string. Searching the other value names inside currently return no other hits so in this case they can safely be ignored.
That leave us with the value of CStr(Chr(99)) which is “c”.
Next let us put both of the remaining scripts into 1 document to make searching for strings easier between the 2 scripts.
As we look and search for the string to get rebuilt we can get a count of how many times the string is found. If it is only found once then it most likely junk. That does not mean that earlier in the code it does not decode to the string you are looking for.
In this case no. We still have junk as the second value after “CStr”.
The next value though has 3 hits.
So lets take a closer look at this first function that will reassemble part of the final string.
Doing a few string searches we can see that this first function contains a lot of junk code so lets clean it up to get a better idea of how the function works.
Now we can have a better understanding of how this works. The original line of code will call each function name and then each function will reassemble a string and return that to be tacked onto the original call.
So one of the first things we will want to do is go thru all of the “CStr” function and replace those with the char for that char code.
So another new tool. We input the combined 2 scripts and the string we are looking for “CStr” and it will find and replace all of them with the char.
Now that the char codes are replaced with the Char we can go onto the next tool that will reassemble the final string.
Now that the easy part of rebuilding this long encoded string is complete we now move on to the harder part, interpreting what this is doing.
After viewing this Twitter thread from Shiao Qu @ShiaoQu17 here it got me looking at this in a different lite. We need to break up the string in sections.
The first section that is highlighted will build the cmommand for cmd.exe to launch the decoded part.
The next section is the Encoded string.
The final section is the directions how to decode the center part.
Here is part 1 cleaned up a bit. Although I still don’t fully understand “exactly” everything it does. I do have a real good idea how it works.
In the second part, everything after the first equals sign to the closing parentheses “)” is the encoded text we will be working with.
In part 3 we will get an idea of how this string in section2 gets decoded.
That is still hard to read so lets clean that up some.
I may have gotten carried away cleaning this string but the important part for me is the 2 values highlighted “2153, –6”.
What this does is takes the encoded string and set an index value of “2153” which is the string length and takes the last character in the string then advances backwards 6 chars to the next value. So our first char will be “p” and then count backwards every 6 chars to get our decoded string.
In my tool I just reverse the string and count forwards.
I seen the video here by Karsten Hahn @struppigel for a different type and he does a better job of explaining the way that the call works at the end for that type and returns the decoded value.
The trick here is that when it will automatically remove the extra characters as it runs under cmd.exe. If the string is not cleaned correctly when decoding by hand the the index will be off and return the wrong output value for the decoded script. One other thing I found was in Powershell we generally get rid of the tick mark “`” as an escape char but here it appeared that it was paired with “^” looking like it would be removed also. After more testing I only ended up removing the Cmd escape char of “^”. Or in the case of my current tool I do a string replace of “^`” with “*” which is one character that was not used in order to keep the proper length. The replacement really was not needed in this case.
Here is the decoded script and tool.
And the final decoded script formatted for better reading.
Although this looked very complicated from the start. Especially if you already read the scripts of the builder here by Daniel Bohannon @danielhbohannon or read the white paper located here it did not turn out to be as difficult as it first appeared to beat the encoding .
If you don’t care to really understand how it works you can always drop the document on ANY.RUN @anyrun_app Like this sample was here .
Just scroll down the right till you find the poweshell.exe process , select on that. Then view more information to get this screen.
I still have a lot more to learn about how some of the obfuscation works. I was still able to extract the final payload which was the whole point anyway.
That’s it for this one I hope everyone learned as much as I did.