Added AMSITools

This commit is contained in:
Mariusz B. / mgeeky 2022-09-22 19:08:29 +02:00
parent 677491192b
commit f35358ab59
5 changed files with 530 additions and 0 deletions

View File

@ -0,0 +1,343 @@
filter Send-AmsiContent {
<#
.SYNOPSIS
Supplies the AmsiScanBuffer function with a buffer to be scanned by an AMSI provider.
Author: Matt Graeber
Company: Red Canary
.DESCRIPTION
Send-AmsiContent is a wrapper for AMSI functions that passes off buffers to be scanned by an AMSI provider via the AmsiScanBuffer function. This function was designed to support AMSI debugging, testing, and validation scenarios without the need to execute malicious code.
In order to get the full functionality out of Send-AmsiContent, it is recommended to create an AV exception for this script as it is likely to flag AV engine signatures based on the presence of "AMSI" strings.
One way to validate AMSI events is by capturing an ETW trace while using Send-AmsiContent. To start an ETW trace, run the following from an elevated prompt:
logman start AMSITrace -p Microsoft-Antimalware-Scan-Interface Event1 -o AMSITrace.etl -ets
Then, supply the buffers you want to test to Send-AmsiContent followed by stopping your tace with the following command:
logman stop AMSITrace -ets
Upon completing the AMSI trace, the ETL file can be interpreted in Event Viewer or with the Get-AmsiEvent function in this module.
.PARAMETER StandardAppName
Specifies the application name to emulate that will supply the buffer to AmsiScanBuffer. The following application names are supported:
* PowerShell - Refers to PowerShell script code. This application name is supplied in System.Management.Automation.dll. PowerShell generates a dynamic application name string in the form of PowerShell_POWERSHELLPATH_POWERSHELLVERSION.
* VBScript - Refers to VBScript script code. This application name is supplied in vbscript.dll
* JScript - Refers to JScript script code. This application name is supplied in jscript.dll, jscript9.dll, and jscriptlegacy.dll
* WMI - Refers to WMI operations. This application name is supplied in fastprox.dll
* DotNet - Refers to in-memory .NET assembly loads in .NET 4.8+. This application name is supplied in clr.dll
* coreclr - Refers to in-memory .NET assembly loads in .NET 4.8+. This application name is supplied in coreclr.dll
* VSS - Refers to Volume Shadow Copy service operations. This application name is supplied in VSSVC.exe and swprv.dll
* Excel - Refers to Excel4 macro contents. This application name is supplied in EXCEL.EXE.
* Excel.exe - Refers to Excel4 macro contents. This application name is supplied in excelcnv.exe.
* OFFICE_VBA - Refers to VBA macro contents. This application name is supplied in VBE7.DLL.
* Exchange Server 2016 - Refers to Exchange Server AMSI integration (https://techcommunity.microsoft.com/t5/exchange-team-blog/more-about-amsi-integration-with-exchange-server/ba-p/2572371). This application name is supplied in Microsoft.Exchange.HttpRequestFiltering.dll.
.PARAMETER CustomAppName
Specifies a custom application name. Use this parameter when testing non-standard applications.
.PARAMETER ContentBytes
Specifies a byte array to be scanned by registered AMSI providers.
.PARAMETER ContentString
Specifies a string to be scanned by registered AMSI providers. A warning is presented if either the DotNet or VSS application names are specified as those are expected to be supplied as byte arrays.
.PARAMETER ContentName
Specifies an emulated path to the content being scanned.
.INPUTS
PSObject
Accepts the output of Get-AmsiEvent when the -AsByteArray switch is supplied.
.EXAMPLE
Send-AmsiContent -StandardAppName PowerShell -ContentString 'Write-Host foo' -ContentName 'D:\test.ps1'
.EXAMPLE
Send-AmsiContent -StandardAppName PowerShell -ContentString 'Invoke-Expression "Do-Stuff"'
.EXAMPLE
Send-AmsiContent -StandardAppName DotNet -ContentBytes ([IO.File]::ReadAllBytes('C:\Windows\System32\stordiag.exe'))
.EXAMPLE
Send-AmsiContent -StandardAppName VBScript -ContentString 'WScript.Echo "Hello, World"'
.EXAMPLE
Send-AmsiContent -StandardAppName JScript -ContentString 'WScript.Echo("Hello, Mimikatz?");'
.EXAMPLE
Send-AmsiContent -StandardAppName WMI -ContentString 'ActiveScriptEventConsumer.GetObject();\nActiveScriptEventConsumer.GetObject();\nSetPropValue.Name(\"WriteDateTime\");\nSetPropValue.ScriptText(\"Set FSO=CreateObject(\"Scripting.FileSystemObject\"):Set File = FSO.CreateTextFile(\"C:\\Windows\\Temp\\text.txt\"):File.WriteLine FormatDateTime(now):File.Close\");\n'
#>
[CmdletBinding(DefaultParameterSetName = 'CustomAppNameByteContent')]
param (
[Parameter(Mandatory, Position = 0, ParameterSetName = 'StandardAppNameStringContent')]
[Parameter(Mandatory, Position = 0, ParameterSetName = 'StandardAppNameByteContent')]
[String]
[ValidateSet('PowerShell', 'VBScript', 'JScript', 'WMI', 'DotNet', 'coreclr', 'VSS', 'Excel', 'Excel.exe', 'OFFICE_VBA', 'Exchange Server 2016')]
$StandardAppName,
[Parameter(Mandatory, Position = 0, ParameterSetName = 'CustomAppNameStringContent')]
[Parameter(Mandatory, Position = 0, ParameterSetName = 'CustomAppNameByteContent', ValueFromPipelineByPropertyName)]
[String]
[ValidateNotNullOrEmpty()]
[Alias('AppName')]
$CustomAppName,
[Parameter(Mandatory, Position = 1, ParameterSetName = 'StandardAppNameByteContent')]
[Parameter(Mandatory, Position = 1, ParameterSetName = 'CustomAppNameByteContent', ValueFromPipelineByPropertyName)]
[Byte[]]
[Alias('Content')]
$ContentBytes,
[Parameter(Mandatory, Position = 1, ParameterSetName = 'StandardAppNameStringContent')]
[Parameter(Mandatory, Position = 1, ParameterSetName = 'CustomAppNameStringContent')]
[String]
[ValidateNotNullOrEmpty()]
$ContentString,
[Parameter(Position = 2, ValueFromPipelineByPropertyName)]
[String]
$ContentName
)
if (-not ('AmsiNativeMethods' -as [Type])) {
Add-Type -TypeDefinition @'
using System.Runtime.InteropServices;
public static class AmsiNativeMethods {
public enum AMSI_RESULT {
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_BLOCKED_BY_ADMIN_BEGIN = 0x4000,
AMSI_RESULT_BLOCKED_BY_ADMIN_END = 0x4fff,
AMSI_RESULT_DETECTED = 32768,
}
[DllImportAttribute("amsi.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiInitialize(
[InAttribute()][MarshalAsAttribute(UnmanagedType.LPWStr)] string appName,
ref System.IntPtr amsiContext
);
[DllImportAttribute("amsi.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void AmsiUninitialize(
System.IntPtr amsiContext
);
[DllImportAttribute("amsi.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiOpenSession(
System.IntPtr amsiContext,
ref System.IntPtr amsiSession
);
[DllImportAttribute("amsi.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void AmsiCloseSession(System.IntPtr amsiContext, System.IntPtr amsiSession);
[DllImportAttribute("amsi.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int AmsiScanBuffer(
System.IntPtr amsiContext,
byte[] buffer,
uint length,
[InAttribute()][MarshalAsAttribute(UnmanagedType.LPWStr)] string contentName,
System.IntPtr amsiSession,
ref AMSI_RESULT result
);
}
'@
}
if ($CustomAppName) {
$FullAppName = $CustomAppName
} else {
switch ($StandardAppName) {
'PowerShell' {
$PowerShellProcess = Get-Process -Id $PID
# Emulate the dynamically build appname used by PowerShell: https://github.com/PowerShell/PowerShell/blob/03b07a0062648b6b6f9f58227dbd25fb0e0759e7/src/System.Management.Automation/security/SecuritySupport.cs#L1348
$FullAppName = "PowerShell_$($PowerShellProcess.Path)_$($PSVersionTable.BuildVersion.ToString())"
}
'DotNet' {
if (@('StandardAppNameStringContent', 'CustomAppNameStringContent') -contains $PSCmdlet.ParameterSetName) {
Write-Warning 'DotNet content is expected to be supplied as a byte array but string content was supplied.'
}
$FullAppName = $StandardAppName
}
'coreclr' {
if (@('StandardAppNameStringContent', 'CustomAppNameStringContent') -contains $PSCmdlet.ParameterSetName) {
Write-Warning 'coreclr content is expected to be supplied as a byte array but string content was supplied.'
}
$FullAppName = $StandardAppName
}
'VSS' {
if (@('StandardAppNameStringContent', 'CustomAppNameStringContent') -contains $PSCmdlet.ParameterSetName) {
Write-Warning 'VSS content is expected to be supplied as a byte array but string content was supplied.'
}
$FullAppName = $StandardAppName
}
default {
$FullAppName = $StandardAppName
}
}
}
if ($ContentName) {
$ContentNameString = $ContentName
} else {
$ContentNameString = [String]::Empty
}
if ($ContentBytes) {
[Byte[]] $Content = $ContentBytes
} else {
# -ContentString was supplied
[Byte[]] $Content = [Text.Encoding]::Unicode.GetBytes($ContentString)
}
$AmsiContext = [IntPtr]::Zero
$AmsiSession = [IntPtr]::Zero
$AmsiResult = New-Object -TypeName AmsiNativeMethods+AMSI_RESULT
$Result = [AmsiNativeMethods]::AmsiInitialize($FullAppName, [Ref] $AmsiContext)
if ($Result -ne 0) {
$Failure = [ComponentModel.Win32Exception] $Result
Write-Error -Message "AmsiInitialize failed. Message: $($Failure.Message). Error code: $($Failure.NativeErrorCode)"
}
$Result = [AmsiNativeMethods]::AmsiOpenSession($AmsiContext, [Ref] $AmsiSession)
if ($Result -ne 0) {
[AmsiNativeMethods]::AmsiUninitialize($AmsiContext)
$Failure = [ComponentModel.Win32Exception] $Result
Write-Error -Message "AmsiOpenSession failed. Message: $($Failure.Message). Error code: $($Failure.NativeErrorCode)"
}
$Result = [AmsiNativeMethods]::AmsiScanBuffer(
$AmsiContext,
$Content,
$Content.Length,
$ContentNameString,
$AmsiSession,
[Ref] $AmsiResult
)
$ERROR_NOT_READY = 0x80070015
if (($Result -ne 0) -and ($Result -ne $ERROR_NOT_READY)) {
$Failure = [ComponentModel.Win32Exception] $Result
Write-Error -Message "AmsiScanBuffer failed. Message: $($Failure.Message). Error code: $($Failure.NativeErrorCode)"
}
[AmsiNativeMethods]::AmsiCloseSession($AmsiContext, $AmsiSession)
[AmsiNativeMethods]::AmsiUninitialize($AmsiContext)
}
function Get-AMSIEvent {
<#
.SYNOPSIS
Parses the contents of an AMSI ETW trace file.
Author: Matt Graeber
Company: Red Canary
.PARAMETER Path
Specifies the path to an ETL file consisting of an AMSI ETW trace.
.PARAMETER AsByteArray
Returns AMSI event data as a byte array in the Content property. By default, buffers are returned as a unicode string. This option facilitates passing raw AMSI content through to Send-AmsiContent.
.EXAMPLE
Get-AmsiEvent -Path C:\Test\AMSITrace.etl
#>
param (
[Parameter(Mandatory)]
[String]
[ValidatePattern('\.etl$')] # File path must end with .etl
$Path,
[Switch]
$AsByteArray
)
# AMSI events correspond to event ID 1101
Get-WinEvent -Path $Path -Oldest -FilterXPath 'Event[System[Provider[@Name="Microsoft-Antimalware-Scan-Interface"]] and System[EventID=1101]]' | ForEach-Object {
$ScanResultValue = $_.Properties[2].Value
if ($ScanResultValue -eq 0) {
$ScanResult = 'AMSI_RESULT_CLEAN'
} elseif ($ScanResultValue -eq 1) {
$ScanResult = 'AMSI_RESULT_NOT_DETECTED'
} elseif ($ScanResultValue -eq 32768) {
$ScanResult = 'AMSI_RESULT_DETECTED'
} elseif (($ScanResultValue -ge 0x4000) -and ($ScanResultValue -le 0x4FFF)) {
$ScanResult = 'AMSI_RESULT_BLOCKED_BY_ADMIN'
} else {
$ScanResult = $ScanResultValue
}
$AppName = $_.Properties[3].Value
if ($AsByteArray) {
$AMSIContent = $_.Properties[7].Value
} else {
if ($AppName -eq 'DotNet') {
# In this case, the AMSI buffer is a raw byte array of the full .NET assembly PE
$AMSIContent = [BitConverter]::ToString($_.Properties[7].Value).Replace('-','')
} else {
# In this case, the AMSI buffer is raw byte array of unicode-encoded script code
$AMSIContent = [Text.Encoding]::Unicode.GetString($_.Properties[7].Value)
}
}
[PSCustomObject] @{
ProcessId = $_.ProcessId
ThreadId = $_.ThreadId
TimeCreated = $_.TimeCreated
Session = $_.Properties[0].Value
ScanStatus = $_.Properties[1].Value
ScanResult = $ScanResult
AppName = $AppName
ContentName = $_.Properties[4].Value
ContentSize = $_.Properties[5].Value
OriginalSize = $_.Properties[6].Value
Content = $AMSIContent
Hash = (($_.Properties[8].Value | ForEach-Object { '{0:X2}' -f $_ }) -join '')
ContentFiltered = $_.Properties[9].Value
}
}
}

View File

@ -0,0 +1,106 @@
#Requires -RunAsAdministrator
function Get-AMSIScanResult {
<#
.SYNOPSIS
Starts AMSI ETW Trace and then either waits for user to trigger detection or scans input file.
Then collects AMSI events and prints them on output.
Based on Matt Graeber's AMSITools.ps1, sourced:
https://gist.github.com/mgraeber-rc/1eb42d3ec9c2f677e70bb14c3b7b5c9c
.PARAMETER File
Input file to scan if Interactive is not used.
.PARAMETER Interactive
Will wait for user to trigger AMSI detections and await for Enter keypress.
When Enter is pressed, will pull collected AMSI events.
.PARAMETER StandardAppName
Specifies the application name to emulate that will supply the buffer to AmsiScanBuffer. The following application names are supported:
* PowerShell - Refers to PowerShell script code. This application name is supplied in System.Management.Automation.dll. PowerShell generates a dynamic application name string in the form of PowerShell_POWERSHELLPATH_POWERSHELLVERSION.
* VBScript - Refers to VBScript script code. This application name is supplied in vbscript.dll
* JScript - Refers to JScript script code. This application name is supplied in jscript.dll, jscript9.dll, and jscriptlegacy.dll
* WMI - Refers to WMI operations. This application name is supplied in fastprox.dll
* DotNet - Refers to in-memory .NET assembly loads in .NET 4.8+. This application name is supplied in clr.dll
* coreclr - Refers to in-memory .NET assembly loads in .NET 4.8+. This application name is supplied in coreclr.dll
* VSS - Refers to Volume Shadow Copy service operations. This application name is supplied in VSSVC.exe and swprv.dll
* Excel - Refers to Excel4 macro contents. This application name is supplied in EXCEL.EXE.
* Excel.exe - Refers to Excel4 macro contents. This application name is supplied in excelcnv.exe.
* OFFICE_VBA - Refers to VBA macro contents. This application name is supplied in VBE7.DLL.
* Exchange Server 2016 - Refers to Exchange Server AMSI integration (https://techcommunity.microsoft.com/t5/exchange-team-blog/more-about-amsi-integration-with-exchange-server/ba-p/2572371). This application name is supplied in Microsoft.Exchange.HttpRequestFiltering.dll.
.PARAMETER TraceFile
Path where to save ETL file with event logs.
#>
param(
[string]
$File = "",
[string]
$StandardAppName = "OFFICE_VBA",
[switch]
$Interactive,
[string]
$TraceFile = "AMSITrace.etl"
)
if (-not $Interactive -and $File -eq "") {
Write-Error "You must specify -File or -Interactive."
}
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
#
# Step 1: Disable AMSI for this powershell runspace.
#
[Runtime.InteropServices.Marshal]::WriteByte((([Ref].Assembly.GetTypes()|?{$_-clike'*Am*ls'}).GetFields(40)|?{$_-clike'*xt'}).GetValue($null),0x5)
#
# Step 2: Load Matt Graeber's AMSITools.ps1
#
. "$PSScriptRoot\AMSITools.ps1"
#
# Step 3: Start an ETW Trace
#
Remove-Item $TraceFile -EA SilentlyContinue | Out-Null
logman start AMSITrace -p Microsoft-Antimalware-Scan-Interface Event1 -o $TraceFile -ets | Out-Null
if ($Interactive) {
Write-Host "Trigger AMSI detections now and then press any key to pull AMSI events..."
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}
else {
#
# Step 4: Read input file
#
$bytes = Get-Content $File -Encoding Byte
#
# Step 5: Feed AMSI trace
#
Send-AmsiContent -StandardAppName $StandardAppName -ContentBytes $bytes
}
#
# Step 6: Stop ETW Trace
#
logman stop AMSITrace -ets | Out-Null
#
# Step 7: Pull collected events
#
Get-AMSIEvent -Path $traceFile
Write-Host "If you wish to pull AMSI events again, simply run in this terminal:`n`tGet-AMSIEvent -Path $traceFile`n"
}

View File

@ -0,0 +1,80 @@
# Countering AMSI Detection
This page explains how to troubleshoot AMSI detections on Office documents.
This is the typical error message indicating AMSI killed our maldoc:
![amsi.png](amsi.png)
The script provided in this directory, [again](https://github.com/mgeeky/Penetration-Testing-Tools/tree/master/red-teaming/Self-Signed%20Threat), uses splendid work of [Matt Graeber, @mattifestation](https://twitter.com/mattifestation), namely his [AMSITools.ps1]](https://gist.github.com/mgraeber-rc/1eb42d3ec9c2f677e70bb14c3b7b5c9c) script, that pulls AMSI events from Windows' event-log.
## Pulling AMSI Events
We can pull AMSI events to review more closely what happened thanks to Matt's [AMSITools.ps1]](https://gist.github.com/mgraeber-rc/1eb42d3ec9c2f677e70bb14c3b7b5c9c).
Follow these steps:
1. Disable your Anti-Virus. In Defender, that includes turning off Real-Time Detection option.
2. Open up Powershell as Administrator and browse to this script's directory.
3. Load up `Get-AMSIScanResult.ps1` script:
```
PS D:\AMSITools> . .\Get-AMSIScanResult.ps1
```
4. And then - to inspect Office document - simply launch the following:
```
PS D:\AMSITools> Get-AMSIScanResult -Interactive
```
5. You will be prompted with following message:
```
Trigger AMSI detections now and then press any key to pull AMSI events...
```
6. Now re-enable your Anti-Virus, to make sure AMSI provider will be active and Maldoc will get remediated.
7. Open up your faulty Maldoc document to ensure AMSI triggers and event gets generated
8. After seeing AMSI error dialog, close up Office application and get back to Powershell console.
9. Now hit **Enter** in the console and review output or follow instructions.
## Example Event
Example event look like following:
```
ProcessId : 30828
ThreadId : 14248
TimeCreated : 02/09/2022 16:54:54
Session : 0
ScanStatus : 1
ScanResult : AMSI_RESULT_DETECTED
AppName : OFFICE_VBA
ContentName : D:\rmf\output-files\evil2.xlsm
ContentSize : 680
OriginalSize : 680
Content : IXMLDOMDocument2.createelement("obf_someInternalName");
IXMLDOMElement.nodetypedvalue();
IXMLDOMDocument2.createelement("obf_someInternalName");
IXMLDOMElement.nodetypedvalue();
IXMLDOMDocument2.createelement("obf_someInternalName");
IXMLDOMElement.nodetypedvalue();
IWshShell3.run("false", "0", "%WINDIR%\System32\conhost.exe "calc" """);
Hash : 6C58AE0705D2CE87ED36E78E6C366118AA407776D898864F92FF5ADC50294268
ContentFiltered : False
```
The very last line of `Content` entry tells us, which was the last VBA line of code that generated AMSI event.
## Credits
**All credits go to Matt** - this directory contains HIS script, mirrored for preserverance purposes.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,6 +1,7 @@
## Red Teaming and Social-Engineering related scripts, tools and CheatSheets
- **`AMSITools`** - Script using [Matt Graeber's](https://twitter.com/mattifestation) [AMSITools.ps1]](https://gist.github.com/mgraeber-rc/1eb42d3ec9c2f677e70bb14c3b7b5c9c) to pull triggered AMSI events for closer inspection.
- **`backdoor-drop.js`** - Internet Explorer - JavaScript trojan/backdoor dropper template, to be used during Penetration Testing assessments. ([gist](https://gist.github.com/mgeeky/b0aed7c1e510560db50f96604b150dac))