23 comments

[ 0.22 ms ] story [ 29.3 ms ] thread
It seems that it's not just Defender (despite the title), even more sophisticated "endpoint protection" suites seems to not bother checking stacks.

That bothers me a lot.

Agreed. The additional VirusTotal bypass was unexpected, and more interesting to me.
(comment deleted)
Interesting. Presumably this breaks the emulated environment in which Defender is running the executable, and when this fails Defender assumes the executable is safe rather than suspicious?
Sometimes I get prompts from Windows Defender that it would like to upload some files to Microsoft for further analysis. The weird thing is that they are well known binaries from official sources, for example node.exe (Node JS). Just to be sure a couple times I checked the digital signatures and all that.

Doesn't Microsoft download important applications to analyze or whitelist itself?

Maybe Microsoft is trying to hunt down a piece of malware that has an authentic digital signature? Stuxnet had it.
I get the same thing with notepad++ updates. Only time I use windows is work and the apps that usually update are vscode (which I assume they preanalyze) and notepad++. Other than that I live in WSL for …work
Can anyone explain certainly why this works?
What section is used eventually by the payload? Somehow the stack size feels like a red herring. These tools scan the executables without executing them, don't they? The payload is surely not on the stack yet.
The payload for both approaches should be in the data segment I think. Which makes this strange.

Edit : a map file should show the difference if any

Here a test in godbolt https://godbolt.org/z/rKao1ssb9 .

All 3 compilers GCC, Clang and MVSC instead of placing the whole stack initialization value in rodata and then copying from there using memcpy, chose to initialize parts of array using `mov [stack_pointer] Literal_value` . Results might be slightly different with different sizes of constant and various other factors like optimization level. This breaks up the big constant array int smaller chunks which is probably why the AV didn't detect when just scanning file, and the whole constant is only assembled during execution on stack. Even if compiler didn't break up the constant, it shouldn't be difficult to achieve similar result by having an encrpyted version of payload in read only section, and then decrypting it to stack. Manual analysis would trivially defeat such encryption with key stored next to it, but for automated analysis the solution is to execute the binary in sandboxed environment and allowing it decrypt itself, but the problem here is that Windows defender doesn't properly notice the payload if it gets stored in unusually big stack and that's why the blogpost about it.

As for why the compiler by default breaks up the constant. I assume it's because compiler heuristics are written with assumption that you wouldn't have 2MB constant initializing stack variable. And for more reasonable initial stack variable values, storing them as instruction literals can be more performant as that way it avoids additional memory loads. When array and constant is sufficiently big GCC and clang fully switches to rodata+memcpy strategy. But with optimizations disabled MSVC naively copies the values with "move [ptr], 1_byte_literal" one byte at a time even for very big arrays.

yes, I just tested with VC and was going to post that I found exactly what you said. Thanks for explaining in detail.
I guess that every byte being stored as `mov [stack_ptr], 0x12` is why executable with 2MB array takes 16MB of disk space.
> These tools scan the executables without executing them, don't they?

No, modern AV software executes unknown binaries in an emulated system environment. Defender has an x86-to-safe-x86 JIT compiler built in to make this more performant.

What I could never get over... Windows Defender (and all other client-side AV) is effectively pointless if you are operating as administrator on the machine. A carefully-crafted powershell command (running in an elevated context) can completely erase all traces of Defender in seconds.

Once you get your hands on a TrustedInstaller session, you are pretty much in god mode.

You don't even need that. AV does not know what "malware" is. It only knows heuristics from known bad ware. If I make a program in visual studio that does some bad stuff, and give it to you, defender won't do a thing about it because it's doing the same stuff good ware could also be doing.

This is why AV's are low on the list of security. Prevention is far better than detection.

Does that also apply to things like Symantec Endpoint Protection, which has many additional modules like SONAR - is that mostly marketing and loud yelling?
Most endpoint protection systems typically use a combination of looking at known hashes or bad things and active process monitoring to identify new bad things. They're not perfect, and have varying levels of success. It is better than nothing.

I can't speak to Symantec, but I've worked for companies that provide endpoint protection and watched a live demo of novel "malware" getting caught escalating privileges.

That's why cloud delivered detection is good as well edrs including defender atp and others.

I "attack simulated" as many ways as I could, disabling defender. If anything on our environment so much as changes a registry key, service or adds an exclusion we get alerts for it, no need for cloud delivered protection/atp to take its time analyzing behavior.

OPs writeup is great but it has nothing to do with behavioral analysis.

It doesn't even matter what bypass you found. I spent so much time defeating defender at one point, as soon as my payload breaks opsec on a cloud delivered box (e.g.:run "whoami") in about a day defender starts catching it.

I can almost guarantee this bypass can only last as long as attackers use it stealthily. Enough automatic detections will get human eyes on it.

If you are administrator, you can create and launch new scheduled tasks ... as NT\SYSTEM from that you can ... anything. Get TCB privilege, get Trusted Installer account, install kernel level drivers ... god mode.
(comment deleted)
Wait until the author finds out the 1995 technique of encrypting your payload as resource and decrypting it at runtime and then just jump to it in memory data (execute data technique) - the reason why AV's implemented heuristic analysis beside the classic signature one.
(comment deleted)