You are here

Behind Enemy Lines: A Pen Tester’s Take on Evading AMSI

Written by: Jake Spinney, GWAPT

Intro

During penetration tests, it’s common to run into antivirus as part of the exploitation phase. The tools used in a penetration test are well known by antivirus vendors, which means we have to get creative in understanding how a client’s antivirus is searching for malicious payloads and manually modify our own to avoid detection.

At DEF CON 2019, the conference offered a hands-on workshop on evading the Windows Antimalware Scanning Interface (AMSI) run by BC-Security.

What is AMSI?

The Windows Antimalware Scanning Interface (AMSI) is a way for applications and antivirus products to interface with each other more effectively to detect malicious payloads. This is accomplished when an application invokes AMSI to scan a given file, script, or command. Depending on what was scanned, AMSI gives the target being scanned a risk score. If the risk score is over a certain value, AMSI hands the payload off to an AMSI-compatible antivirus solution for additional scanning and sterilization of the threat, as appropriate.

To demonstrate some of the techniques taught at this workshop, we will use a Windows 10 (build 1903) virtual machine as our testing system, with Windows Defender (which is AMSI-compatible) for our antivirus. At the time of writing, the antivirus signatures are up-to-date and real-time protection is enabled. In order to invoke AMSI, we will be using various PowerShell scripts and payloads.

AMSI at Work

Before we dive into weaponized Windows PowerShell scripts that may be used in the field, let’s discuss how AMSI and PowerShell work together. The phrase “amsicontext” is a pattern that triggers a high-risk AMSI score when used in PowerShell, thus invoking Windows Defender. The PowerShell Script example below is simply attempting to write “amsicontext” to the screen. The error in red text, which is Windows Defender intervening, is made possible because PowerShell invoked AMSI before executing our command. If we pretend this code was malicious for a moment, what are some ways that a penetration tester could hide or obfuscate this malware from AMSI?

Figure 1 - Triggering AMSI

Evasion 1: Concatenation

The first example is called concatenation. This is when we take our phrase “amsicontext”, split it into two separate phrases “amsi” and “context”, and put them back together. To demonstrate this, we:

  1. Attempt to store the evil phrase “amsicontext” to the variable “evil_0”. AMSI, detecting the phrase and invoking Windows Defender, blocks us from doing this.
  2. Attempt to store the concatenated version of our evil phrase, “amsi”+”context”, into the variable “evil_1”. As you can see, AMSI did not invoke Windows Defender, as it did in Step 1.
  3. To demonstrate concatenation, we successfully write the contents of “evil_1” to the screen. “amsicontext” is printed to the screen, demonstrating our first successful evasion technique.

Figure 2 - Concatenation at work

Evasion 2: Type-Casting

Our next example will cover a programming concept called type-casting. All characters, from letters and numbers to formatting and emojis, can be represented as numbers in code. For example, the phrase “Wolf” can be broken up into letters and represented as digits 87 (uppercase ‘W’), 111 (lowercase ‘o’), 108 (lowercase ‘l’), and 102 (lowercase ‘f’), respectively, in ASCII code. If we break up “amsicontext” into ASCII codes and tell PowerShell to interpret these numbers as characters (referred to as type-casting), we can write “amsicontext” to the screen without triggering AMSI.

Figure 3 - Type-casting example, where "amsicontext" is replaced with its ASCII code representations.

Evasion 3: Variable Insertion

What other ways can we obfuscate “amsicontext” without losing its value? In PowerShell, we can store part of the phrase in a variable and reference the contents of that variable elsewhere. In the example below, we:

  1. Create a variable called “var” and store the phrase “context” to it.
  2. Attempt to write “amsi” and a reference to the variable to the screen. This takes the contents of “var” and replaces $var with “context”.

Figure 4 - Using variable insertion to directly replace the contents of $var with "context", evading AMSI.

Evasion 4: Format String

We can accomplish a similar phrase insertion pattern using what are called format strings, which are special characters used to represent other values to be inserted later. In the example below, we use “{0}” and “{1}” as placeholders for the phrases “con” and “text” respectively.

Figure 5 - Using format strings to replace content with in-line placeholders

Evasion 5: String Replacement

Lastly, PowerShell string replacement lets us replace phrases with other phrases. In the example below, we use the phrase “WOLF” as a placeholder for “context” which lets us construct the phrase “amsicontext” without getting blocked by AMSI or Defender.

Figure 6 - Replacing phrases with other phrases through the '-replace' option

Putting It All Together

Now that we’ve demonstrated examples using a harmless string, let’s demonstrate how we would use these techniques using malicious payloads. To do this, we’ll use a couple of open-source tools known as Invoke-Obfuscation and PowerShell Empire. Invoke-Obfuscation allows us to use the aforementioned techniques, and many more, to obfuscate a PowerShell payload of our choosing. Our payload will be generated using PowerShell Empire, which is a command and control framework for remotely controlling infected target machines. What makes Empire unique is that it gives us control of a target machine without having to download and execute an EXE file, like other types of malware.

By tasking PowerShell Empire to obfuscate our payload, we can create a lengthy PowerShell command, which can be used in place of other binary payloads when exploiting vulnerable services.

Figure 7 - Powershell Empire stager creation, with AMSI evasions turned on.

Upon delivering this payload to our target, we are able to successfully infect the target with a PowerShell Empire agent without being blocked by antivirus.

Figure 8 - Successful execution of the PowerShell Empire agent.

Conclusion

While we were able to ultimately bypass antivirus, there are many other defenses to prevent this scenario from happening in your network:

  • Restricting which users can execute PowerShell
  • Auditing command line and PowerShell usage across endpoints and servers
  • Monitoring network traffic

These are great steps for detecting and preventing adversaries and penetration testers alike from gaining access to your infrastructure. Above all, don’t let antivirus be the only shield defending your network – a defense in depth approach to securing your infrastructure will always be preferable.

For more information on assessing the security posture of your organization, reach out to Jake Spinney at jspinney@wolfandco.com or Sean Goodwin at sdgoodwin@wolfandco.com