Merge pull request #339 from MSAdministrator/modified_execution_functions_and_readme
Modified Invoke-AtomicRedTeam functions and README
This commit is contained in:
@@ -1,147 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This script will iterate over the Atomic Red Team yaml files, create objects for each test.
|
||||
The aim is to allow defenders to excercise MITRE ATT&CK Techniques to test defenses.
|
||||
|
||||
Function: Invoke-AtomicRedTeam
|
||||
Author: Casey Smith @subTee
|
||||
License: http://opensource.org/licenses/MIT
|
||||
Required Dependencies: powershell-yaml , Install-Module powershell-yaml #https://github.com/cloudbase/powershell-yaml
|
||||
Optional Dependencies: None
|
||||
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
|
||||
$T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
.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
|
||||
$T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
Invoke-AtomicTest $T1117
|
||||
.NOTES
|
||||
This script converts Atomic Tests Expressed in YAML into PowerShell Objects.
|
||||
|
||||
.LINK
|
||||
Blog: http://subt0x11.blogspot.com/2018/08/invoke-atomictest-automating-mitre-att.html
|
||||
Github repo: https://github.com/redcanaryco/atomic-red-team
|
||||
|
||||
#>
|
||||
|
||||
function Confirm-Dependencies {
|
||||
|
||||
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}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-AtomicTechnique {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
# Returns A HashTable For Each File Passed In
|
||||
BEGIN { }
|
||||
PROCESS {
|
||||
foreach ($File in $Path) {
|
||||
$parsedYaml = (ConvertFrom-Yaml (Get-Content $File -Raw ))
|
||||
Write-Output $parsedYaml
|
||||
}
|
||||
}
|
||||
END { }
|
||||
}
|
||||
|
||||
function Invoke-AtomicTest {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[System.Collections.Hashtable]
|
||||
$AtomicTechnique,
|
||||
|
||||
[switch]
|
||||
$GenerateOnly
|
||||
)
|
||||
BEGIN {}
|
||||
PROCESS {
|
||||
foreach ($Technique in $AtomicTechnique) {
|
||||
$AtomicTest = $Technique.atomic_tests
|
||||
|
||||
foreach ($Test in $AtomicTest) {
|
||||
#Only Process Windows Tests For Now
|
||||
if (-Not $Test.supported_platforms.Contains('windows')) {
|
||||
return
|
||||
}
|
||||
|
||||
#Reject Manual Tests
|
||||
if ($Test.executor.name.Contains('manual')) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host ("[********BEGIN TEST*******]`n" +
|
||||
$Technique.display_name.ToString(), $Technique.attack_technique.ToString())
|
||||
Write-Host $Test.name.ToString()
|
||||
Write-Host $Test.description.ToString()
|
||||
|
||||
$finalCommand = $Test.executor.command
|
||||
if ($Test.input_arguments.Count -gt 0) {
|
||||
#Replace InputArgs with default values
|
||||
$InputArgs = [Array]($Test.input_arguments.Keys).Split(" ")
|
||||
$InputDefaults = [Array]($Test.input_arguments.Values | ForEach-Object {$_.default }).Split(" ")
|
||||
|
||||
for ($i = 0; $i -lt $InputArgs.Length; $i++) {
|
||||
$findValue = '#{' + $InputArgs[$i] + '}'
|
||||
$finalCommand = $finalCommand.Replace($findValue, $InputDefaults[$i])
|
||||
}
|
||||
}
|
||||
|
||||
#Get Executor and Build Command Script
|
||||
if ($GenerateOnly) {
|
||||
Write-Host $finalCommand -Foreground Green
|
||||
}
|
||||
else {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "[!!!!!!!!END TEST!!!!!!!]`n`n" -Foreground Yellow
|
||||
}
|
||||
}
|
||||
END { }
|
||||
}
|
||||
|
||||
Confirm-Dependencies
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
#
|
||||
# Module manifest for module 'Invoke-AtomicRedTeam'
|
||||
#
|
||||
# Generated by: Josh Rickard
|
||||
#
|
||||
# Generated on: 09/13/2018
|
||||
#
|
||||
|
||||
@{
|
||||
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'Invoke-AtomicRedTeam.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '1.0.0.0'
|
||||
|
||||
# Supported PSEditions
|
||||
CompatiblePSEditions = @('Desktop')
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = '8f492621-18f8-432e-9532-b1d54d3e90bd'
|
||||
|
||||
# Author of this module
|
||||
Author = 'Casey Smith @subTee, Josh Rickard @MS_dministrator'
|
||||
|
||||
# Company or vendor of this module
|
||||
CompanyName = 'Red Canary'
|
||||
|
||||
# Copyright statement for this module
|
||||
Copyright = '(c) 2018 Red Canary. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
Description = 'A PowerShell module that runs Atomic Red Team tests from yaml definition files.'
|
||||
|
||||
# Minimum version of the Windows PowerShell engine required by this module
|
||||
PowerShellVersion = '3.0'
|
||||
|
||||
# Name of the Windows PowerShell host required by this module
|
||||
# PowerShellHostName = ''
|
||||
|
||||
# Minimum version of the Windows PowerShell host required by this module
|
||||
# PowerShellHostVersion = ''
|
||||
|
||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# DotNetFrameworkVersion = ''
|
||||
|
||||
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# CLRVersion = ''
|
||||
|
||||
# Processor architecture (None, X86, Amd64) required by this module
|
||||
# ProcessorArchitecture = ''
|
||||
|
||||
# Modules that must be imported into the global environment prior to importing this module
|
||||
# RequiredModules = @()
|
||||
|
||||
# Assemblies that must be loaded prior to importing this module
|
||||
# RequiredAssemblies = @()
|
||||
|
||||
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
||||
# ScriptsToProcess = @()
|
||||
|
||||
# Type files (.ps1xml) to be loaded when importing this module
|
||||
# TypesToProcess = @()
|
||||
|
||||
# Format files (.ps1xml) to be loaded when importing this module
|
||||
# FormatsToProcess = @()
|
||||
|
||||
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||
# NestedModules = @()
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = @()
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = @()
|
||||
|
||||
# Variables to export from this module
|
||||
VariablesToExport = '*'
|
||||
|
||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||
AliasesToExport = @()
|
||||
|
||||
# DSC resources to export from this module
|
||||
# DscResourcesToExport = @()
|
||||
|
||||
# List of all modules packaged with this module
|
||||
# ModuleList = @()
|
||||
|
||||
# List of all files packaged with this module
|
||||
# FileList = @()
|
||||
|
||||
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
||||
PrivateData = @{
|
||||
|
||||
PSData = @{
|
||||
|
||||
# Tags applied to this module. These help with module discovery in online galleries.
|
||||
Tags = @('Red Canary', 'Atomic', 'Red Team', 'MITRE', 'ATT&CK', 'ART')
|
||||
|
||||
# A URL to the license for this module.
|
||||
LicenseUri = 'https://github.com/redcanaryco/atomic-red-team/blob/master/LICENSE.txt'
|
||||
|
||||
# A URL to the main website for this project.
|
||||
ProjectUri = 'https://github.com/redcanaryco/atomic-red-team'
|
||||
|
||||
# A URL to an icon representing this module.
|
||||
# IconUri = ''
|
||||
|
||||
# ReleaseNotes of this module
|
||||
ReleaseNotes = 'http://subt0x11.blogspot.com/2018/08/invoke-atomictest-automating-mitre-att.html'
|
||||
|
||||
} # End of PSData hashtable
|
||||
|
||||
} # End of PrivateData hashtable
|
||||
|
||||
# HelpInfo URI of this module
|
||||
# HelpInfoURI = ''
|
||||
|
||||
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
||||
# DefaultCommandPrefix = ''
|
||||
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#requires -Version 3.0
|
||||
|
||||
#Get public and private function definition files.
|
||||
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -Recurse -ErrorAction SilentlyContinue )
|
||||
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -Recurse -ErrorAction SilentlyContinue )
|
||||
|
||||
#Dot source the files
|
||||
Foreach ($import in @($Public + $Private)) {
|
||||
Try {
|
||||
. $import.fullname
|
||||
}
|
||||
Catch {
|
||||
Write-Error -Message "Failed to import function $($import.fullname): $_"
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function $Public.Basename
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Confirms and imports Invoke-AtomicRedTeam dependencies
|
||||
.DESCRIPTION
|
||||
Confirms and imports Invoke-AtomicRedTeam dependencies. You can specify an alternative ModulePath of powershell-yaml module.
|
||||
.EXAMPLE Default Confirm-Dependencies
|
||||
PS/> Confirm-Dependencies
|
||||
.EXAMPLE Specify ModulePath of powershell-yaml module
|
||||
PS/> Confirm-Dependencies -ModulePath C:\some\path\to\module\powershell-yaml.psm1
|
||||
.NOTES
|
||||
Create Atomic Tests from yaml files described in Atomic Red Team. https://github.com/redcanaryco/atomic-red-team
|
||||
.LINK
|
||||
Blog: http://subt0x11.blogspot.com/2018/08/invoke-atomictest-automating-mitre-att.html
|
||||
Github repo: https://github.com/redcanaryco/atomic-red-team
|
||||
#>
|
||||
function Confirm-Dependencies {
|
||||
[CmdletBinding(DefaultParameterSetName = 'dependencies',
|
||||
SupportsShouldProcess = $true,
|
||||
ConfirmImpact = 'Medium')]
|
||||
Param(
|
||||
[Parameter(Mandatory = $false,
|
||||
Position = 0,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'dependencies')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$ModulePath
|
||||
)
|
||||
|
||||
Write-Verbose -Message 'Checking whether powershell-yaml is installed'
|
||||
|
||||
try {
|
||||
if ($PSBoundParameters.ContainsKey('ModulePath')) {
|
||||
Import-Module $ModulePath
|
||||
}
|
||||
else {
|
||||
Write-Error -ErrorRecord $Error[0] -RecommendedAction 'Could not import the provided module. Please ensure you can access the ModulePath location.' -ErrorAction Stop
|
||||
}
|
||||
|
||||
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'
|
||||
|
||||
Write-Verbose -Message 'Importing powershell-yaml module'
|
||||
Import-Module -Name powershell-yaml -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error -ErrorRecord $Error[0] -RecommendedAction 'Please install powershell-yaml before continuing' -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get Atomic Technique
|
||||
.DESCRIPTION
|
||||
Gets Atomic Technique(s) based on the provided path
|
||||
.EXAMPLE Get Atomic Technique
|
||||
PS/> $T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
.NOTES
|
||||
Create Atomic Tests from yaml files described in Atomic Red Team. https://github.com/redcanaryco/atomic-red-team
|
||||
.LINK
|
||||
Blog: http://subt0x11.blogspot.com/2018/08/invoke-atomictest-automating-mitre-att.html
|
||||
Github repo: https://github.com/redcanaryco/atomic-red-team
|
||||
#>
|
||||
function Get-AtomicTechnique {
|
||||
[CmdletBinding(DefaultParameterSetName = 'technique',
|
||||
SupportsShouldProcess = $true,
|
||||
PositionalBinding = $false,
|
||||
ConfirmImpact = 'Medium')]
|
||||
Param(
|
||||
[Parameter(Mandatory = $true,
|
||||
Position = 0,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
|
||||
Write-Debug -Message "Getting atomic technique from $Path"
|
||||
|
||||
Process
|
||||
{
|
||||
Write-Verbose -Message 'Attempting to convert files from yaml'
|
||||
foreach ($file in $Path) {
|
||||
if ($pscmdlet.ShouldProcess($file, 'Converting yaml file')) {
|
||||
Write-Verbose -Message "Converting $file from Yaml"]
|
||||
$parsedYaml = ConvertFrom-Yaml (Get-Content $file -Raw)
|
||||
Write-Output $parsedYaml
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Invokes provided Atomic test(s)
|
||||
.DESCRIPTION
|
||||
Invokes provided Atomic tests(s). Optionally, you can specify if you want to generate Atomic test(s) only.
|
||||
.EXAMPLE Invokes Atomic Test
|
||||
PS/> $T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
PS/> Invoke-AtomicTest $T1117
|
||||
.EXAMPLE Generate Atomic Test
|
||||
PS/> $T1117 = Get-AtomicTechnique -Path ..\..\atomics\T1117\T1117.yaml
|
||||
PS/> Invoke-AtomicTest $T1117 -GenerateOnly
|
||||
.NOTES
|
||||
Create Atomic Tests from yaml files described in Atomic Red Team. https://github.com/redcanaryco/atomic-red-team
|
||||
.LINK
|
||||
Blog: http://subt0x11.blogspot.com/2018/08/invoke-atomictest-automating-mitre-att.html
|
||||
Github repo: https://github.com/redcanaryco/atomic-red-team
|
||||
#>
|
||||
function Invoke-AtomicTest {
|
||||
[CmdletBinding(DefaultParameterSetName = 'technique',
|
||||
SupportsShouldProcess = $true,
|
||||
PositionalBinding = $false,
|
||||
ConfirmImpact = 'Medium')]
|
||||
Param(
|
||||
[Parameter(Mandatory = $true,
|
||||
Position = 0,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[System.Collections.Hashtable]
|
||||
$AtomicTechnique,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
Position = 1,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[switch]
|
||||
$GenerateOnly
|
||||
)
|
||||
BEGIN { } # Intentionally left blank and can be removed
|
||||
PROCESS {
|
||||
Write-Verbose -Message 'Attempting to run Atomic Techniques'
|
||||
|
||||
$techniqueCount = 0
|
||||
foreach ($technique in $AtomicTechnique) {
|
||||
|
||||
$techniqueCount++
|
||||
|
||||
$props = @{
|
||||
Activity = "Running $($technique.display_name.ToString()) Technique"
|
||||
Status = 'Progress:'
|
||||
PercentComplete = ($techniqueCount / ($AtomicTechnique).Count * 100)
|
||||
}
|
||||
Write-Progress @props
|
||||
|
||||
Write-Debug -Message "Gathering tests for Technique $technique"
|
||||
|
||||
$testCount = 0
|
||||
foreach ($test in $technique.atomic_tests) {
|
||||
$testCount++
|
||||
|
||||
$props = @{
|
||||
Activity = 'Running Atomic Tests'
|
||||
Status = 'Progress:'
|
||||
PercentComplete = ($testCount / ($technique.atomic_tests).Count * 100)
|
||||
}
|
||||
Write-Progress @props
|
||||
|
||||
Write-Verbose -Message 'Determining tests for Windows'
|
||||
|
||||
if (-Not $test.supported_platforms.Contains('windows')) {
|
||||
Write-Verbose -Message 'Unable to run non-Windows tests'
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Verbose -Message 'Determining manual tests'
|
||||
|
||||
if ($test.executor.name.Contains('manual')) {
|
||||
Write-Verbose -Message 'Unable to run manual tests'
|
||||
continue
|
||||
}
|
||||
|
||||
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 Atomic test command'
|
||||
|
||||
$finalCommand = $test.executor.command
|
||||
|
||||
if ($test.input_arguments.Count -gt 0) {
|
||||
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(" ")
|
||||
|
||||
for ($i = 0; $i -lt $inputArgs.Length; $i++) {
|
||||
$findValue = '#{' + $inputArgs[$i] + '}'
|
||||
$finalCommand = $finalCommand.Replace($findValue, $inputDefaults[$i])
|
||||
}
|
||||
}
|
||||
|
||||
Write-Debug -Message 'Getting executor and build command script'
|
||||
|
||||
if ($GenerateOnly) {
|
||||
Write-Information -MessageData $finalCommand -Tags 'Command'
|
||||
}
|
||||
else {
|
||||
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-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-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
|
||||
}
|
||||
@@ -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.psm1`
|
||||
```
|
||||
|
||||
`$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
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
$TemplatePowerShellModule = 'Invoke-AtomicRedTeam'
|
||||
|
||||
$here = "$(Split-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -Parent)\$TemplatePowerShellModule"
|
||||
|
||||
Describe "$TemplatePowerShellModule PowerShell Module Tests" {
|
||||
Context 'Module Setup' {
|
||||
It "has the root module $TemplatePowerShellModule.psm1" {
|
||||
"$here\$TemplatePowerShellModule.psm1" | Should -Exist
|
||||
}
|
||||
It "has the manifest file $TemplatePowerShellModule.psd1" {
|
||||
"$here\$TemplatePowerShellModule.psd1" | should exist
|
||||
}
|
||||
It "$TemplatePowerShellModule has functions" {
|
||||
"$here\Public\*.ps1" | Should exist
|
||||
}
|
||||
It "$TemplatePowerShellModule is valid PowerShell Code" {
|
||||
$psFile = Get-Content -Path "$here\$TemplatePowerShellModule.psm1" -ErrorAction Stop
|
||||
$errors = $null
|
||||
$null = [System.Management.Automation.PSParser]::Tokenize($psFile, [ref]$errors)
|
||||
$errors.count | Should be 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pubFunctions = ('Confirm-Dependencies', 'Get-AtomicTechnique', 'Invoke-AtomicTest')
|
||||
|
||||
$folders = ( 'Public')
|
||||
|
||||
foreach ($folder in $folders) {
|
||||
Describe 'Folders Tests' {
|
||||
It "$folder should exist" {
|
||||
"$here\$Folder" | Should Exist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Function Tests' {
|
||||
foreach ($function in $pubFunctions) {
|
||||
Context 'Public Functions' {
|
||||
It "$function.ps1 should exist" {
|
||||
"$here\Public\$function.ps1" | Should Exist
|
||||
}
|
||||
It "$function.ps1 should have help block" {
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch '<#'
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch '#>'
|
||||
}
|
||||
It "$function.ps1 should have a SYNOPSIS section in the help block" {
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch '.SYNOPSIS'
|
||||
}
|
||||
It "$function.ps1 should have a DESCRIPTION section in the help block" {
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch '.DESCRIPTION'
|
||||
}
|
||||
It "$function.ps1 should have a EXAMPLE section in the help block" {
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch '.EXAMPLE'
|
||||
}
|
||||
It "$function.ps1 should be an advanced function" {
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch 'function'
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch 'CmdLetBinding'
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch 'param'
|
||||
}
|
||||
It "$function.ps1 should contain Write-Verbose blocks" {
|
||||
"$here\Public\$function.ps1" | Should -FileContentMatch 'Write-Verbose'
|
||||
}
|
||||
It "$function.ps1 is valid PowerShell code" {
|
||||
$psFile = Get-Content -Path "$here\Public\$function.ps1" -ErrorAction Stop
|
||||
$errors = $null
|
||||
$null = [System.Management.Automation.PSParser]::Tokenize($psFile, [ref]$errors)
|
||||
$errors.count | Should be 0
|
||||
}
|
||||
}# Context Public Function Tests
|
||||
} # end of Public function foreach
|
||||
} # end of describe block
|
||||
Reference in New Issue
Block a user