Modified Invoke-AtomicRedTeam functions and README
This commit is contained in:
@@ -13,14 +13,11 @@ Version: 1.0
|
||||
.DESCRIPTION
|
||||
Create Atomic Tests from yaml files described in Atomic Red Team. https://github.com/redcanaryco/atomic-red-team
|
||||
|
||||
.EXAMPLE
|
||||
Convert Single Yaml File to Technique Object
|
||||
.EXAMPLE Convert Single Yaml File to Technique Object
|
||||
$T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
.EXAMPLE
|
||||
Generate the Atomic Tests For A Given Technique, don't execute.
|
||||
.EXAMPLE Generate the Atomic Tests For A Given Technique, don't execute.
|
||||
Invoke-AtomicTest $T1117 -GenerateOnly
|
||||
.EXAMPLE
|
||||
Execute the Atomic Tests For A Given Technique
|
||||
.EXAMPLE Execute the Atomic Tests For A Given Technique
|
||||
$T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
Invoke-AtomicTest $T1117
|
||||
.NOTES
|
||||
@@ -33,75 +30,127 @@ Github repo: https://github.com/redcanaryco/atomic-red-team
|
||||
#>
|
||||
|
||||
function Confirm-Dependencies {
|
||||
[CmdletBinding(DefaultParameterSetName = 'dependencies',
|
||||
SupportsShouldProcess = $true,
|
||||
ConfirmImpact = 'Medium')]
|
||||
Param ( )
|
||||
|
||||
Write-Verbose -Message 'Checking whether powershell-yaml is installed'
|
||||
|
||||
if (Get-Module -ListAvailable -Name 'powershell-yaml') {
|
||||
Write-Host "PowerShell-Yaml Module Exists. Good To Go." -Foreground Green
|
||||
}
|
||||
else {
|
||||
$Title = "PowerShell-Yaml Is Not Installed"
|
||||
$Message = "Do you want to Install?"
|
||||
$Yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Y-Yes", "Yes"
|
||||
$No = New-Object System.Management.Automation.Host.ChoiceDescription "&N-No", "No"
|
||||
$Options = [System.Management.Automation.Host.ChoiceDescription[]]($Yes, $No)
|
||||
$Result = $Host.ui.PromptForChoice($Title, $Message, $Options, 0)
|
||||
|
||||
switch ($Result) {
|
||||
0 { Install-Module -Name powershell-yaml }
|
||||
1 { Write-Host "Atomic Red Team Requires PowerShell-Yaml Exiting"; exit}
|
||||
try {
|
||||
if (-not(Get-Module -Name 'powershell-yaml' -ListAvailable)) {
|
||||
if ($pscmdlet.ShouldProcess("PowerShell-Yaml Module", "Install required module")) {
|
||||
Install-Module -Name powershell-yaml -Force
|
||||
Write-Verbose -Message 'Successfully installed powershell-yaml module'
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error -ErrorRecord $Error[0] -RecommendedAction 'Please install powershell-yaml before continuing'
|
||||
throw 'Unable to install powershell-yaml'
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Verbose -Message 'Importing powershell-yaml module'
|
||||
Import-Module -Name powershell-yaml -Force
|
||||
}
|
||||
catch {
|
||||
Write-Error -ErrorRecord $Error[0] -RecommendedAction 'Please import the powershell-yaml module before continuing'
|
||||
throw 'Unable to import the powershell-yaml module'
|
||||
}
|
||||
}
|
||||
|
||||
function Get-AtomicTechnique {
|
||||
[CmdletBinding()]
|
||||
[CmdletBinding(DefaultParameterSetName = 'technique',
|
||||
SupportsShouldProcess = $true,
|
||||
PositionalBinding = $false,
|
||||
ConfirmImpact = 'Medium')]
|
||||
Param(
|
||||
[Parameter(Mandatory = $true,
|
||||
Position = 0,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
# Returns A HashTable For Each File Passed In
|
||||
BEGIN { }
|
||||
PROCESS {
|
||||
|
||||
Write-Debug -Message "Getting atomic technique from $Path"
|
||||
|
||||
Process
|
||||
{
|
||||
Write-Verbose -Message 'Attempting to convert files from yaml'
|
||||
foreach ($File in $Path) {
|
||||
$parsedYaml = (ConvertFrom-Yaml (Get-Content $File -Raw ))
|
||||
Write-Output $parsedYaml
|
||||
if ($pscmdlet.ShouldProcess($File, 'Converting yaml file')) {
|
||||
Write-Verbose -Message "Converting $File from Yaml"]
|
||||
$parsedYaml = (ConvertFrom-Yaml (Get-Content $File -Raw))
|
||||
Write-Output $parsedYaml
|
||||
}
|
||||
}
|
||||
}
|
||||
END { }
|
||||
}
|
||||
|
||||
function Invoke-AtomicTest {
|
||||
[CmdletBinding()]
|
||||
[CmdletBinding(DefaultParameterSetName = 'technique',
|
||||
SupportsShouldProcess = $true,
|
||||
PositionalBinding = $false,
|
||||
ConfirmImpact = 'Medium')]
|
||||
Param(
|
||||
[Parameter(Mandatory = $true,
|
||||
Position = 0,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[ValidateNotNull()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[System.Collections.Hashtable]
|
||||
$AtomicTechnique,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
Position = 1,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[switch]
|
||||
$GenerateOnly
|
||||
)
|
||||
BEGIN {}
|
||||
BEGIN { } # Intentionally left blank and can be removed
|
||||
PROCESS {
|
||||
Write-Verbose -Message 'Attempting to run Atomic Techniques'
|
||||
|
||||
$techniqueCount = 0
|
||||
foreach ($Technique in $AtomicTechnique) {
|
||||
$AtomicTest = $Technique.atomic_tests
|
||||
$techniqueCount++
|
||||
Write-Progress -Activity "Running $($Technique.display_name.ToString()) Technique" -Status 'Progress:' -PercentComplete ($techniqueCount / ($AtomicTechnique).Count * 100)
|
||||
Write-Debug -Message "Gathering tests for Technique $Technique"
|
||||
|
||||
foreach ($Test in $AtomicTest) {
|
||||
#Only Process Windows Tests For Now
|
||||
$testCount = 0
|
||||
foreach ($Test in $Technique.atomic_tests) {
|
||||
$testCount++
|
||||
Write-Progress -Activity 'Running Atomic Tests' -Status 'Progress:' -PercentComplete ($testCount / ($Technique.atomic_tests).Count * 100)
|
||||
|
||||
Write-Verbose -Message 'Determining tests for Windows'
|
||||
if (-Not $Test.supported_platforms.Contains('windows')) {
|
||||
return
|
||||
Write-Verbose -Message 'Unable to run non-Windows tests'
|
||||
continue
|
||||
}
|
||||
|
||||
#Reject Manual Tests
|
||||
Write-Verbose -Message 'Determining manual tests'
|
||||
if ($Test.executor.name.Contains('manual')) {
|
||||
return
|
||||
Write-Verbose -Message 'Unable to run manual tests'
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Host ("[********BEGIN TEST*******]`n" +
|
||||
$Technique.display_name.ToString(), $Technique.attack_technique.ToString())
|
||||
Write-Host $Test.name.ToString()
|
||||
Write-Host $Test.description.ToString()
|
||||
Write-Information -MessageData ("[********BEGIN TEST*******]`n" +
|
||||
$Technique.display_name.ToString(), $Technique.attack_technique.ToString()) -Tags 'Details'
|
||||
|
||||
Write-Information -MessageData $Test.name.ToString() -Tags 'Details'
|
||||
Write-Information -MessageData $Test.description.ToString() -Tags 'Details'
|
||||
|
||||
Write-Debug -Message 'Gathering final executation command'
|
||||
$finalCommand = $Test.executor.command
|
||||
|
||||
if ($Test.input_arguments.Count -gt 0) {
|
||||
#Replace InputArgs with default values
|
||||
Write-Verbose -Message 'Replacing InputArgs with default values'
|
||||
$InputArgs = [Array]($Test.input_arguments.Keys).Split(" ")
|
||||
$InputDefaults = [Array]($Test.input_arguments.Values | ForEach-Object {$_.default }).Split(" ")
|
||||
|
||||
@@ -111,37 +160,41 @@ function Invoke-AtomicTest {
|
||||
}
|
||||
}
|
||||
|
||||
#Get Executor and Build Command Script
|
||||
Write-Debug -Message 'Getting executor and build command script'
|
||||
if ($GenerateOnly) {
|
||||
Write-Host $finalCommand -Foreground Green
|
||||
Write-Information -MessageData $finalCommand -Tags 'Command'
|
||||
}
|
||||
else {
|
||||
switch ($Test.executor.name) {
|
||||
Write-Verbose -Message 'Invoking Atomic Tests using defined executor'
|
||||
if ($pscmdlet.ShouldProcess(($Test.name.ToString()), 'Execute Atomic Test')) {
|
||||
switch ($Test.executor.name) {
|
||||
|
||||
"command_prompt" {
|
||||
Write-Host "Command Prompt:`n $finalCommand" -Foreground Green
|
||||
$execCommand = $finalCommand.Split("`n")
|
||||
$execCommand | ForEach-Object { Invoke-Expression "cmd.exe /c `"$_`" " }
|
||||
break
|
||||
}
|
||||
"powershell" {
|
||||
Write-Host "PowerShell`n $finalCommand" -Foreground Cyan
|
||||
$execCommand = "Invoke-Command -ScriptBlock {$finalCommand}"
|
||||
Invoke-Expression $execCommand
|
||||
break
|
||||
}
|
||||
default {
|
||||
"Unable to generate or execute the command line properly."
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"command_prompt" {
|
||||
Write-Information -MessageData "Command Prompt:`n $finalCommand" -Tags 'AtomicTest'
|
||||
$execCommand = $finalCommand.Split("`n")
|
||||
$execCommand | ForEach-Object { Invoke-Expression "cmd.exe /c `"$_`" " }
|
||||
continue
|
||||
}
|
||||
"powershell" {
|
||||
Write-Information -MessageData "PowerShell`n $finalCommand" -Tags 'AtomicTest'
|
||||
$execCommand = "Invoke-Command -ScriptBlock {$finalCommand}"
|
||||
Invoke-Expression $execCommand
|
||||
continue
|
||||
}
|
||||
default {
|
||||
Write-Warning -Message "Unable to generate or execute the command line properly."
|
||||
continue
|
||||
}
|
||||
} # End of executor switch
|
||||
} # End of if ShouldProcess block
|
||||
} # End of else statement
|
||||
} # End of foreach Test in single Atomic Technique
|
||||
|
||||
Write-Host "[!!!!!!!!END TEST!!!!!!!]`n`n" -Foreground Yellow
|
||||
}
|
||||
}
|
||||
END { }
|
||||
Write-Information -MessageData "[!!!!!!!!END TEST!!!!!!!]`n`n" -Tags 'Details'
|
||||
|
||||
} # End of foreach Technique in Atomic Tests
|
||||
} # End of PROCESS block
|
||||
END { } # Intentionally left blank and can be removed
|
||||
}
|
||||
|
||||
Confirm-Dependencies
|
||||
Confirm-Dependencies
|
||||
@@ -1,29 +1,85 @@
|
||||
Requires Installation of PowerShell-Yaml
|
||||
# Invoke-AtomicRedTeam
|
||||
|
||||
Install-Module powershell-yaml
|
||||
## Requires Installation of PowerShell-Yaml
|
||||
|
||||
```powershell
|
||||
Install-Module -Name powershell-yaml
|
||||
```
|
||||
|
||||
For Additional Details:
|
||||
[PowerShell-Yaml](https://github.com/cloudbase/powershell-yaml)
|
||||
|
||||
Basic usage Examples:
|
||||
## Basic usage Examples
|
||||
|
||||
- Load PowerShell Script:
|
||||
`Import-Module .\Invoke-AtomicRedTeam.ps1`
|
||||
#### Load PowerShell Script
|
||||
|
||||
- Execute Single Test:
|
||||
```powershell
|
||||
Import-Module .\Invoke-AtomicRedTeam.ps1`
|
||||
```
|
||||
|
||||
`$T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml`
|
||||
`Invoke-AtomicTest $T1117`
|
||||
#### Execute Single Test
|
||||
|
||||
- Generate All Tests
|
||||
```powershell
|
||||
$T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
Invoke-AtomicTest $T1117
|
||||
```
|
||||
|
||||
`[System.Collections.HashTable]$AllAtomicTests = @{};`
|
||||
`$AtomicFilePath = 'C:\AtomicRedTeam\atomics\';`
|
||||
`Get-Childitem $AtomicFilePath -Recurse -Filter *.yaml -File | ForEach-Object {`
|
||||
`$currentTechnique = [System.IO.Path]::GetFileNameWithoutExtension($_.FullName);`
|
||||
`$parsedYaml = (ConvertFrom-Yaml (Get-Content $_.FullName -Raw ));`
|
||||
`$AllAtomicTests.Add($currentTechnique, $parsedYaml); }`
|
||||
`$AllAtomicTests.GetEnumerator() | %{ Invoke-AtomicTest $_.Value -GenerateOnly }`
|
||||
## Additional Examples
|
||||
|
||||
If you would like output when running tests using the following:
|
||||
|
||||
- Feedback Welcome
|
||||
#### Informational Stream
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest $T1117 -InformationAction Continue
|
||||
```
|
||||
|
||||
#### Verbose Stream
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest $T1117 -Verbose
|
||||
```
|
||||
|
||||
#### Debug Stream
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest $T1117 -Debug
|
||||
```
|
||||
|
||||
#### WhatIf
|
||||
|
||||
If you would like to see what would happen without running the test
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest $T1117 -WhatIf
|
||||
```
|
||||
|
||||
#### Confirm
|
||||
|
||||
To run all tests without confirming them run using the Confirm switch to false
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest $T1117 -Confirm:$false
|
||||
```
|
||||
|
||||
Or you can set your `$ConfirmPreference` to 'Medium'
|
||||
|
||||
```powershell
|
||||
$ConfirmPreference = 'Medium'
|
||||
Invoke-AtomicTest $T1117
|
||||
```
|
||||
|
||||
## Generate All Tests
|
||||
|
||||
```powershell
|
||||
[System.Collections.HashTable]$AllAtomicTests = @{}
|
||||
$AtomicFilePath = 'C:\AtomicRedTeam\atomics\'
|
||||
Get-ChildItem $AtomicFilePath -Recurse -Filter *.yaml -File | ForEach-Object {
|
||||
$currentTechnique = [System.IO.Path]::GetFileNameWithoutExtension($_.FullName)
|
||||
$parsedYaml = (ConvertFrom-Yaml (Get-Content $_.FullName -Raw ))
|
||||
$AllAtomicTests.Add($currentTechnique, $parsedYaml);
|
||||
}
|
||||
$AllAtomicTests.GetEnumerator() | Foreach-Object { Invoke-AtomicTest $_.Value -GenerateOnly }
|
||||
```
|
||||
|
||||
### Feedback Welcome
|
||||
|
||||
Reference in New Issue
Block a user