The other day I was given a sample vbscript file by Paul Melson @pmelson so I could take a look at the odd shell code in it.
Here is the original script.
This starts out as a normal script running PowerShell to do a base64 decode. The next level was Gzip base64 encoded then we get to the 3rd layer.
This looks like a standard shell code loader. But when I tried to run it thru my tools we discover that is Shikata Ga Nai Encoded.
In a previous blog post Here I go in a little deeper on how this Shikata Ga Nai encoding works. I had to modify my decoder for this sample to extract the final shell code.
While trying to decode this the normal way of using CyberChef to find the start key and inputting all of the shell code bytes into my tool and removing 1 byte /2 chars at a time by hand until I get the decoded shell code I was not finding the expected output of the decoded shell code.
The highlighted bytes are the key in byte order. My tool will reverse them to be used.
My next step is to fire up a VM and run the extracted shell code thru SCDbg and see if it returns anything. SCDbg only works with 32 bit shell code.
Here is what I seen.
If all I wanted to do is extract and IP then I could stop here.
This tells me it does decode but not how it decodes.
I next tried to run it thru psxray located Here but it didn’t fully decode the shell code.
The next thing I tried was blobrunner located Here in conjunction with x32 dbg
I then began to suspect that this may have been encoded multiple times or by more than 1 encoder.
After a Google search I found This blog post that tells me there is an option in Msfvenom to encode the shell code with multiple rounds.
This verified my theory of multiple layers . But how does it work ? how do you peel off the layers ?
Let’s start by comparing the encoded to the decoded file in the hex editor.
Here we can see that the decoded and encoded file are the same to offset 0x25.
That tells me that the encoded bytes start there.
The other question is how do I know if I have it properly decoded or not ? This type of encoding will not be easy to tell by just looking at the decoded value. So I added a search into the return value of the decoder. If the result contains the bytes for “FNSTENV” 0xD97424F4 then I hopefully found the decoded layer.
Testing this by only inputting the bytes 0x25 onward and the start key from CyberChef we see this.
Once we click ok it will write to the output to keep from over running the decode.
Here we can see that for every for 4 decoded bytes a new key is generated for the next 4 bytes.
So we take a large enough sample from the decoded section to compare to the known decoded shell code from SCDbg and we see that it matches up with the starting offset at 0x25.
So the next theory is to take the ouput from the decoder drop it into CyberChef to get the next key and then move the output of the decoder to the input.
At this point I’m not doing any pointer math to try and figure out where the next part starts. We could also copy the bytes at offset 0x25 to a new file then compare the output to it and see where the difference it but I’ll do it the easier way of just adding a shift button to the tool.
It will shift / remove 1 byte (2 chars) from the left giving it a new point to start decoding at.
While testing this theory of inputting the output from the previous run I decided to keep a log of each layer.
The enc len was a guess based on the the first 2 outputs that I never went back to verify based on the number from CyberChef results.
Each layer needed to be shifted 20+ times before it found the decoded output when you just input the output.
One odd thing I found around level 5-6 was it pops up the found message at 12 shifts but the CyberChef looks a little strange compared to the others and the first decoded bytes were not in the known decoded file like before.
After some trial and error I decided to try and continue shifting and see if the messaged popped up again. It did at around 28 shifts.
In the short shifts we don’t have a “MOV” to get the key but we do in the 28 shift one.
Continuing on, this process was repeated for 10 rounds. Dropping each output decoded bytes into CyberChef to retrieve the next key and then shifting until we get the message that there is another round or the the decoded shell code was found.
We can verify that it decoded correctly by dropping it in the other tools.
So if we look up the term “Shikata Ga Nai” we see it means “it cannot be helped” or “nothing can be done about it”.
Now something can be done about it now that we have a better understanding of how it works.
After writing this post I decided to move the code that did the checking and pop up a message box after the code that writes the output to the output text box. That way it will already be present when the message box pops up so a screenshot can be taken then.
I also considered adding a counter to keep track of the shifts but decided not to for now.
That’s it for this one, thanks for following along. I hope you found it as interesting to read as I did to research it.
Hash for Script
Sha1 : 94659C6520CFBDCA3CFECDA7781CED15659B0687
Sha 256 : 8B5366D58D00CBA37DB8D1E1CCDD1C767F730EA197476A736EB8FEED43B8FCBC
MD5 : 2B0324C016BD023EC1405007A7DCD6A1
Hash for Shell code
Sha1 : 8E1B4CFC4B1146C332AE6D4C5F9C86C242574370
Sha 256 : F8BDB9D9CE545075F483F4F1F919560EEE0108E313121DD2B891BFDF31A65DCE
MD5 : 9F88A4BBAFF1B8F530EE29F7226B3338
Links:
Link to VT for Shell Code
Link to Previous blog post on this type of encoding.
Link to SCDbg
Link to PSXray
Link to BlobRunner
Link to blog post on Msfvenom
Link to my Github with tools