What gets scrutinized in the given entry is whether or not the use of encoders and generating fuzzy NOPs can help avoid interception by AV.Alright, what about inlining it? Like a said, typically we have been shoving stuff into a variable, then doing some dereferencing tricks in C, and then executing it as a function. Executing instructions from data is inherently suspicious, it’s not a normal thing to do, it’s not a normal thing that executables do. What if we instead replace the actual instructions of the executable so that our payload is the instruction set, it is the text section of that executable? This is sort of my first stab at this idea of blending in instead of hiding.
So the analogy that I think most aptly describes this concept is, imagine you’ve got a guy who wants to rob a jewellery store. There are two different scenarios. In one, the guy is waiting for everybody to clear out and he hides in an alleyway somewhere, a cop walks by and sees this guy standing around in an alleyway not doing anything. He is not doing anything that is immediately recognizable as bad. But do you think that cop is going to come check him out? Yeah, he is.
Now imagine if instead our thief, in the second scenario, dresses up as a meter maid or somebody fixing the street lights, somebody that cop expects to see, something that is completely normal. The cop is going to walk right by because he has already preconditioned to see that guy and say: “No, it’s cool.” That’s the same problem with antivirus evasion: everybody is trying to hide in the alleyway when what they need to be doing is looking like something the antivirus already expects to be there.Basically, what I did is I took Metasm, took the payload and just wrote it in as raw assembly instructions and recompiled in the Exe. This (see left-hand image) is what our first attempt looked like. The second attempt (see right-hand image) is to basically do the same thing but we tried encoding it a couple of different ways. Because we control the generation and the executable, it’s really easy to set everything as read-writable executable so our polymorphic shellcode can write over itself, and encoded shellcode works really well. So we tried this with Shikata Ga nai, which is the most common one that everybody uses and knows and loves, also Stephen Fewer’s new Bloxor Encoder. Results weren’t really good (see left-hand image). Doing inlining actually increased our detection rate by about double where we were right before this. Shikata dropped it but only dropped it back to the same level that we had a problem with in the first place. And Bloxor was almost as bad as not encoding it. That was somewhat disheartening but gets back to – encoders do not evade antivirus. I am going to keep driving this home because I keep seeing it. That got me thinking as I was looking at those results, every time we encoded the shellcode there were a certain set of detections that were always there when we used an encoder, that’s a little weird. Encoders have always been incidental in their AV evasion usage; they are actually there to remove bad characters for an exploit. Because it makes the code look different, we have gotten past signature detection but, as we said, signatures really aren’t our problem. So my next thought was: “I wonder if the encoder itself is generating additional detections beyond the payload itself.” What I did was I took a series of meaningless assembly instructions, and it was just: push eax, push ecx, pop eax, pop ecx; basically, swapping two registers around, four or five bytes of shellcode, run that through our two encoders and push that up to VirusTotal – still get a whole bunch of detections.
This should be the final nail in the coffin. If any of you do not believe me that encoders do not evade antivirus, encoders cause antivirus detections, they are suspicious. They look like packers, people have been using packers for, I don’t know, twenty years now, they do not work, do not use them. They are great for exploits if you are doing a memory corruption exploit because you need to get away from bad characters, but if you are doing PsExec and you tell me: “I don’t understand why my payload got caught, I ran it through Shikata Ga nai five times,” – I will kill you!Conclusion about encoders: they do drop the number of detections but they come with their own whole set of detections that they bring all on their own, so it’s a complete fail. What can we do if we are not using encoders? Well, we still want to break up the way that code looks, right? So I came up with this idea of generating fuzzy NOPs (see left-hand image). These are NOPs that are not your standard NOPs, they are not your 0x90. It’s actually a series of instructions that at the end have a zero sum. So the registers in the stack all must be in the exact same state at the end of the instruction set as they were at the beginning. And you can just nest these as deep of a level as you want as long as you always back everything out at the end.
Immediate negation doesn’t work because that’s really obvious, and heuristics can easily just, basically, ignore it. So if you inc eax and then dec eax, AV is going to be smart enough to realize that: “Hey, that is a no operation really.” So we nest about four levels deep: inc eax, push ecx, do something else, pop ecx, dec eax.It looks like legitimate assembly instructions. It’s a series of operations but in the end we have done absolutely nothing. Then you take these and you insert them between all the recognizable sets of instructions in our payload, and hopefully that’s going to break up detection. Nope, it didn’t do a darn thing, we ended up with the exact same results that we got without doing this (see right-hand image). So, unfortunately that’s a big fail.
Read previous: AV Evasion 3: EXE Templates and Run-Time Dynamic Linking