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:
committed by
Michael Haag
parent
75c332ac52
commit
019b63fdb5
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+61
-8
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user