Support for CheckPrereqs and Cleanup Commands (#531)

* Support for CheckPrereqs and Cleanup Commands

* for powershell executor, report prereqs are met if no prereq_commands are given

* remove invoke call from end of file, commited accidentally
This commit is contained in:
Carrie Roberts
2019-08-30 09:42:44 -06:00
committed by Michael Haag
parent 75c332ac52
commit 019b63fdb5
5 changed files with 107 additions and 10 deletions
+16 -1
View File
@@ -45,5 +45,20 @@ end.join(', ') %>
<%= test['executor']['command'].to_s.strip %>
```
<%- end -%>
<%- if test['executor']['prereq_command'] != nil -%>
#### Commands to Check Prerequisites:
```
<%= test['executor']['prereq_command'].to_s.strip %>
```
<%- end -%>
<%- if test['executor']['cleanup_command'] != nil -%>
#### Cleanup Commands:
```
<%= test['executor']['cleanup_command'].to_s.strip %>
```
<%- end -%>
<br/>
<%- end -%>
<%- end -%>
@@ -23,5 +23,10 @@ atomic_tests:
executor:
name: command_prompt
elevation_required: true # indicates whether command must be run with admin privileges. If the elevation_required attribute is not defined, the value is assumed to be false
prereq_command: | # for the "command_prompt" executor, if any command returns a non-zero exit code, the pre-requisites are not met. For the "powershell" executor, all commands are run as a script block and the script block must return 0 for success. You can remove the prereq_command section if there are no pre-req's
TODO
command: | # these are the actaul attack commands, at least one command must be provided
TODO
cleanup_command: | # you can remove the cleanup_command section if there are no cleanup commands
command: |
TODO
+10
View File
@@ -109,8 +109,14 @@ atomic_tests:
executor:
name: command_prompt
elevation_required: true
prereq_command: |
fltmc.exe filters | findstr #{sysmon_driver}
command: |
fltmc.exe unload #{sysmon_driver}
cleanup_command: |
sc stop sysmon
fltmc.exe load #{sysmon_driver}
sc start sysmon
- name: Disable Windows IIS HTTP Logging
description: |
@@ -138,5 +144,9 @@ atomic_tests:
executor:
name: command_prompt
elevation_required: true
prereq_command: |
sc query sysmon
command: |
sysmon -u
cleanup_command: |
sysmon -i -accepteula
@@ -3,9 +3,13 @@
Invokes specified Atomic test(s)
.DESCRIPTION
Invokes specified Atomic tests(s). Optionally, you can specify if you want to generate Atomic test(s) only.
.EXAMPLE Check if Prerequisites for Atomic Test are met
PS/> Invoke-AtomicTest T1117 -CheckPrereqs
.EXAMPLE Invokes Atomic Test
PS/> Invoke-AtomicTest T1117
.EXAMPLE Generate Atomic Test
.EXAMPLE Run the Cleanup Commmand for the given Atomic Test
PS/> Invoke-AtomicTest T1117 -Cleanup
.EXAMPLE Generate Atomic Test (Output Test Definition Details)
PS/> Invoke-AtomicTest T1117 -GenerateOnly
.NOTES
Create Atomic Tests from yaml files described in Atomic Red Team. https://github.com/redcanaryco/atomic-red-team
@@ -47,7 +51,19 @@ function Invoke-AtomicTest {
[Parameter(Mandatory = $false,
ParameterSetName = 'technique')]
[String]
$PathToAtomicsFolder = "..\..\atomics"
$PathToAtomicsFolder = "..\..\atomics",
[Parameter(Mandatory = $false,
ValueFromPipelineByPropertyName = $true,
ParameterSetName = 'technique')]
[switch]
$CheckPrereqs = $false,
[Parameter(Mandatory = $false,
ValueFromPipelineByPropertyName = $true,
ParameterSetName = 'technique')]
[switch]
$Cleanup = $false
)
BEGIN { } # Intentionally left blank and can be removed
PROCESS {
@@ -109,7 +125,9 @@ function Invoke-AtomicTest {
Write-Debug -Message 'Gathering final Atomic test command'
$finalCommand = $test.executor.command
$prereqCommand = $test.executor.prereq_command
$command = $test.executor.command
$cleanupCommand = $test.executor.cleanup_command
if ($test.input_arguments.Count -gt 0) {
Write-Verbose -Message 'Replacing inputArgs with default values'
@@ -118,10 +136,22 @@ function Invoke-AtomicTest {
for ($i = 0; $i -lt $inputArgs.Length; $i++) {
$findValue = '#{' + $inputArgs[$i] + '}'
$finalCommand = $finalCommand.Replace($findValue, $inputDefaults[$i])
if( $nul -ne $prereqCommand ) { $prereqCommand = $prereqCommand.Replace($findValue, $inputDefaults[$i]) } else { $prereqCommand = "" }
$Command = $command.Replace($findValue, $inputDefaults[$i])
if( $nul -ne $cleanupCommand ) { $cleanupCommand = $cleanupCommand.Replace($findValue, $inputDefaults[$i]) } else { $cleanupCommand = "" }
}
}
if ($CheckPrereqs) {
$finalCommand = $prereqCommand
}
elseif ($Cleanup) {
$finalCommand = $cleanupCommand
}
else {
$finalCommand = $command
}
Write-Debug -Message 'Getting executor and build command script'
if ($GenerateOnly) {
@@ -129,18 +159,41 @@ function Invoke-AtomicTest {
}
else {
Write-Verbose -Message 'Invoking Atomic Tests using defined executor'
if ($pscmdlet.ShouldProcess(($test.name.ToString()), 'Execute Atomic Test')) {
$testName = $test.name.ToString()
if ($pscmdlet.ShouldProcess($testName, 'Execute Atomic Test')) {
switch ($test.executor.name) {
"command_prompt" {
Write-Information -MessageData "Command Prompt:`n $finalCommand" -Tags 'AtomicTest'
$execCommand = $finalCommand.Split("`n")
$execCommand | ForEach-Object { Invoke-Expression "cmd.exe /c `"$_`" " }
$finalCommandEscaped = $finalCommand -replace "`"", "```""
$execCommand = $finalCommandEscaped.Split("`n") | Where-Object { $_ -ne "" }
$exitCodes = New-Object System.Collections.ArrayList
$execCommand | ForEach-Object {
Invoke-Expression "cmd.exe /c `"$_`" "
$exitCodes.Add($LASTEXITCODE) | Out-Null
}
$nonZeroExitCodes = $exitCodes | Where-Object { $_ -ne 0 }
if ($CheckPrereqs ) {
if ($nonZeroExitCodes.Count -ne 0) {
Write-Host -ForegroundColor Red "Prerequisites not met: $testName"
}
else {
Write-Host -ForegroundColor Green "Prerequisites met: $testName"
}
}
continue
}
"powershell" {
Write-Information -MessageData "PowerShell`n $finalCommand" -Tags 'AtomicTest'
$execCommand = "Invoke-Command -ScriptBlock {$finalCommand}"
Invoke-Expression $execCommand
$res = Invoke-Expression $execCommand
if ($CheckPrereqs ) {
if ([string]::IsNullOrEmpty($finalCommand) -or $res -ne 0) {
Write-Host -ForegroundColor Red "Prerequisites not met: $testName"
}
else {
Write-Host -ForegroundColor Green "Prerequisites met: $testName"
}
}
continue
}
default {
@@ -45,7 +45,7 @@ Verbose
### Generate Tests
This process generates all Atomic tests and allows for easy copy and paste execution.
This process generates all Atomic tests (prints test details to screen) and allows for easy copy and paste execution.
Note: you may need to change the path.
Invoke-AllAtomicTests -GenerateOnly
@@ -68,6 +68,15 @@ Specify a path to atomics folder, example C:\AtomicRedTeam\atomics
Invoke-AtomicTest T1117
```
#### Check that Prerequistes for a Given TTP are met
For the "command_prompt" executor, if any of the prereq_command's return a non-zero exit code, the pre-requisites are not met. Example: **fltmc.exe filters | findstr #{sysmon_driver}**
For the "powershell" executor, the prereq_command's are run as a script block and the script must return 0 for success. Example: **if(Test-Path C:\Windows\System32\cmd.exe) { 0 } else { -1 }**
```powershell
Invoke-AtomicTest T1117 -CheckPrereqs
```
#### Execute Specific Attacks (by Attack Number) for a Given TTP
```powershell
@@ -79,6 +88,11 @@ Invoke-AtomicTest T1117 -TestNumbers 1, 2
```powershell
Invoke-AtomicTest T1117 -TestNames "Regsvr32 remote COM scriptlet execution","Regsvr32 local DLL execution"
```
#### Run the Cleanup Commands For the Specified Test
```powershell
Invoke-AtomicTest T1089 -TestNames "Uninstall Sysmon" -Cleanup
```
## Additional Examples