Anda di halaman 1dari 7

Modifying Empire to Evade Windows

Defender
Antivirus evasion as a topic has always fascinated me. When I began my graduate computer science studies many
years back, I originally proposed a topic to my advisors about improving antivirus engines to detect polymorphic
viruses by mapping execution flows in binaries. As graduate studies go, this topic was ultimately shot down and I
eventually settled on another research topic.
Bypassing antivirus is a necessary evil if you work in penetration testing or red teaming. It's also one of the more
frustrating areas -- Frustrating, because "signature-based" antivirus software is both pretty ineffective at blocking
threats, but at the same time is sometimes a pain to evade.
The popular wisdom to evade antivirus is "write your own custom tools." That's great advice if all you need to do is
write a simple reverse shell, or if you have a large budget and lots of time to develop a well polished C2 infrastructure
from scratch. The rest of us rely on the huge wealth of open source (and commercial) tools developed by folks in the
security community. Yes, I want to be able to run something like mimikatz on an engagement and not jump through
massive hoops to do so.
In comes Empire. If you aren't familiar with the tool, Empire is a post-exploitation C2 server that includes a wide
variety of offensive tools. It's a powerful tool to use as part of an offensive operation, if it doesn't get flagged by
antivirus in the process and become an unusable frustration. For a while, Empire was pretty good at evading things
like Windows Defender. This is no longer true. If you create a generic http listener agent payload and execute in-
memory, without even touching the disk, you will likely see something like the following.

Windows Defender busted us! I guess it's time to pack it in for the assessment, right? No way!
By tearing into Empire a bit (yea for free open source software!), we can easily modify some key areas and bypass
that pesky client-side antivirus.

Before we start with any testing, we need to turn off "Cloud-delivered Protection" and especially "Automatic sample
submission" in Windows Defender. We don't want any of our tests creeping out onto the internet and into Windows
Defender's distributed signatures. Of course, keep "Real-time protection" on so we can test execution as it happens.
Whatever you do, DO NOT UPLOAD TO VIRUS TOTAL! This will completely thwart everything you are trying to
accomplish and will not even be effective in this case. As you will learn below, Windows Defender can detect Empire
even if the initial payload passes antivirus inspection. By uploading to Virus Total you will not be able to understand if
the tool would run undetected on the target and you will definitely burn the modifications you have been working on so
hard.
Now that our test lab is ready, it's time to get to work on Empire.

My first several (unsuccessful) attempts to bypass Windows Defender amounted to lazily setting misc options within
the Empire launcher payload. Does it work!? No. Does it work now!? No. And so on.
Empire http listener default options
Empire multi/launcher default options

Next I thought it was time to get sneaky. I would run the payload through the gauntlet of powershell obfuscation tools
out there. Run it through Unicorn... Does it work?! No. Run it through Veil Framework... Does it work?! No. Run it
through Empire's own native Invoke-Obfuscation... Does it work?! No.
I should note that by using the obfuscation tools, I was able to get a payload that could be written to disk,
essentially bypassing the antivirus signature, but upon execution it was either detected or simply failed.
As usual, bashing at things with hammers rarely gets successful results. Time to look under the hood and learn what
Empire is doing.
Dissecting Empire
The initial payload Empire generates is a so-called "stager", specifically a stage0 payload. A stager is a bit of code
that is designed to remotely download and execute either another stager or an actual payload. In our example we will
be working with the multi/launcher powershell stager for an http listener.
Testing the stage0 payload is actually quite simple. Generate the payload, write it to a file, and transfer it to the
Windows machine. If it triggers an antivirus warning when it hits the disk, it needs more work. If it transfers and then
executes fine, you likely have a usable stager.
One big note. When testing payloads over and over -- and triggering Windows Defender over and over -- Windows
Defender can (for lack of a better term) "freak out". During my testing I ran into an issue where Windows Defender
flagged ALL powershell files as viruses upon execution, even empty files! If this happens, give your VM or machine a
reboot. My theory is that Windows Defender likely learned that the host I was transferring files from was malicious and
banned powershell execution no matter the file. Rebooting flushes this. (Aren't we smart for having turned off the
automatic malware submission and cloud-delivered protection!?)
To generate a multi/launcher stager that bypasses Windows Defender, all that's required is to play with the options
presented within Empire. (Shocking, I know!) I won't show you the exact options I'm using, because someone will
immediately use them and ignore my warning about uploading to Virus Total. I will, however, show you the options I
recommend modifying.

Recommended Empire http listener options to edit


Option Description Default
/admin/get.php,/news.php,/login/process.php|Mozilla/5.0
Three URL's that Empire will call during various
DefaultProfile (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like
times as well as a User-Agent string.
Gecko
ServerVersionThe web server version identifier Microsoft-IIS/7.5
Host Your host (or IP) and port number.
Port Should be the same as the specified Host port
Mozilla/5.0 (Windows NT 10.0; Win64; x64)
The User-Agent that Empire sends to mimic
UserAgent AppleWebKit/537.36 (KHTML, like Gecko)
real web browser traffic.
Chrome/71.0.3578.98 Safari/537.36
The URI the stager is served from. This must
StagerURI include /download to work without additional
modification.
The default self-signed certs when setting up
Empire are located at ./Empire/data.
Depending on how sophisticated the
CertPath
environment, self-signed certs may not work.
Windows Defender doesn't mind self-signed
certs.
A random delay when sending beacon calls to
DefaultJitter 0.0
the Empire server.
Launcher The command used to execute the stager. powershell -noP -sta -w 1 -enc

Recommended Empire multi/launcher options to edit


Option Description Default
This must be set and will likely be 'http' if you are following
Listener
along.
UserAgent User-agent string to use for staging.
SafeChecks Attempts to detect if the launcher is running in a sandbox. True
Obfuscate Obfuscate the auto-generated launcher code. False
ObfuscateCommandObfuscation command to use. Token\All\1,Launcher\STDIN++\12467
I will give you one tip. Set SafeChecks to false. SafeChecks attempts to determine if the stager is running inside an
antivirus sandbox. Eliminating SafeChecks cuts down a lot of the generated code, which is clearly not working as
intended since we were getting detected by antivirus.
With our fancy stager payload we will for sure be able to run Empire, right?! Wrong. The payload will execute, and you
will see an initial connection. Sending stage 1! Great! Then nothing. Something is wrong.

While experimenting I decided to turn off antivirus protection, start Empire on the Windows host, and turn antivirus
back on. To my excitement, my Empire beacon did not die! As long as we can get Empire to start we'll be OK. But,
why isn't it starting?

Digging deeper into the Empire codebase yields the stage1 code. This code sets up the cryptographically secure
environment Empire enjoys to avoid detection, but itself is not encoded in any way. Time for modification. After some
trial and error, editing portions of the file I determined that the Invoke-Empire function name was to blame. As is
suggested in this Black Hills Information Security article, changing the name of the function to Invoke-
RandomStringHere is all we need to thwart detection. Even though all we need to do is edit the Invoke-Empire
function name, bonus points for modifying the stage1 code further.
Edit: ./Empire/data/agent/stagers/http.ps1:

Invoke-Empire -Servers @(($s -split "/")[0..2] -join "/") -StagingKey $SK -SessionKey $key -SessionID

Edit: ./Empire/data/agent/agent.ps1

function Invoke-Empire {

Let's try running our Empire stager again.


Excellent! Pop champagne glasses! We've slain Windows Defender! (Keep reading... We didn't.)

Since were running the tests on a fully patched Win10 host, there aren't many methods of privilege escalation. So,
let's try the trusty powershell/privesc/ask module, that literally pops up a dialog box ask asks the user if they want to
run powershell as Administrator. The exploit fires, a good sign. The dialog pops up! I click yes!! ...and nothing.
This I admit had me a bit puzzled. If my stagers worked for the initial exploitation, why not again for privilege
escalation? After some debugging I was able to capture the stager that was being sent with the privesc/ask module.
While it contained some of the modifications I set in the multi/launcher configuration, there was one glaring difference.
It also contained the SafeChecks code that we previously set to False!

I'm not sure if the SafeChecks inclusion here is due to a bug in Empire or not. But, the SafeChecks code is currently
problematic, which appears to be confirmed by this Empire bug. Simply setting the option to always be False solves
our issue.
Edit: ./Empire/lib/listeners/http.py:

def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", userAgent='defau


"""
Generate a basic launcher for the specified listener.
"""

# Add this line to override SafeChecks


safeChecks='False'

Run `python -m compileall` and restart Empire. Then fire up powershell/privesc/ask.


Finally. We are in business. At least for today...