Deceiving Defender: Meterpreter
Demonstrating manual manipulation of a meterpreter payload in order to bypass Windows Defender
Last updated
Demonstrating manual manipulation of a meterpreter payload in order to bypass Windows Defender
Last updated
In this installment of Deceiving Defender, we'll be manually manipulating a meterpreter payload in order to bypass Windows Defender detection.
If you're familiar with this blog, you'll remember that we applied a similar technique on an msfvenom calc and succeeded. Along the way, we learned a couple of things that will be useful as we approach this challenge.
BinaryNinja can be used to modify the payload
There are likely several signatured portions payload stub are the primary means of detecting the payload
Depending on how we modify these stubs we might have to modify some address offsets
Without further ado lets get started.
We use the following command to generate a standard msfvenom meterpreter payload.
If we scan the binary with ThreatCheck we'll find that our payload is detected at the following bytes.
We open the .bin file in BinaryNinja and quickly find the bad bytes.
If we examine this portion of the code in split view, we can find that we're in ordinal_1 and we can see the assembly that we're going to have to modify.
Generally, the approach I like to take when doing this is as follows:
Modify equivalent function opcodes
xor rax, rax == xor eax, eax
test eax, eax == cmp eax, 0
Modify null space with nops
Has no impact because the program shouldn't be in here anyway
Modify opcodes for near-equivalent functions. Sometimes we can get away with near-equivalent instructions :
45 52 :: rex.RB push r10 ~ 41 52 :: push r10
Modify hardcoded constants, retain runtime equivalence through nop injection and offset recalculation
Some of these changes can break the functionality of our payload, so it's important that as we make these changes we constantly validate that our payload still functions.
Looking at the code snippet we have to change here, lets see if there are any quick changes we can make to break this signature.
Looking at the highlighted instructions, we know we can actually move those single byte constants into low bytes of eax instead of the entire eax register, that will save us a few bytes at each of these instructions and enable us to change the constants, and increment their value properly and break the Windows Defender signature.
The block of assembly we're in right now has approximately a dozen or so instructions we can modify in this way. Lets make some of those changes…
Afterwards our disassembly should look like this:
Luckily for us, our program has some interrupt instructions between the end of the current function, and the beginning of the next function our payload includes some interrupt instructions. This space between functions is sometimes called an intersegment gap, and is usually filled with nop, null-bytes, or in our case interrupts.
We can leverage this space to manipulate our function and generate just enough nops to break the signature without breaking our program, but it's going to take a little bit of work.
Looking at our disassembly output, we can see that we have 7 bytes to play with at the bottom of our function.
And another 7 bytes to play with at the top of our function. That gives us a total of 14 bytes to play with to build up some space and change some constants. Remember, modifying these bytes can potentailly break the stability of our payload, so constantly check that the payload works as intended.
We can shift things around a little bit and start buying ourselves some space.
And after some more careful shuffling around we have a function that ends like this
Now we can use the additional space we have to modify the constants in our function. This bit is pretty tedious so we won't dive into every aspect of it, but needless to say that the methodology applied is the same as above.
After making a few more changes, we're able to bypass Windows Defender detection at this offset...only to get detected at another offset.
If we take a look at the offset we find above, we find a data segment that looks like this:
One of the easiest things we can do here is change some null bytes to non-printable characters. If we're careful, we should be able to break the signature at this new offset and maintain a functional payload.
[Intentionally left blank]
And, it turns out to be an easier win than we thought. By simply changing a single byte, we break the signature, and retain a functioning payload!
In this writeup we demonstrated an effcient workflow for payload manipulation and successfully bypassed detection by Windows Defender on a Windows 10 system.
This methodology focused on the injection of bytes in order to manipulate existing payload instructions and beat the Windows Defender signature. We succeeded in our approach and retained a functioning meterpreter payload on a modern Windows 10 system with Windows Defender enabled.
Our approach was limited to opcode manipulation without considering the encoding or encryption options made availible by MSFVenom.
As this article is for demonstration purposes only, we chose to limit the scope of our efforts to a non-executable format in order to reduce the effort necessary to bypass AV detection.