Add Dependencies section to test Yaml and support to use them in the PS execution framework (#772)
* first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * first draft at dependencies * lowercase url
This commit is contained in:
committed by
Michael Haag
parent
550ba03c22
commit
511bb87af2
+1
-2
@@ -70,8 +70,7 @@
|
||||
|
||||
# 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 = @(
|
||||
'Invoke-AtomicTest',
|
||||
'Write-ExeutionLog'
|
||||
'Invoke-AtomicTest'
|
||||
)
|
||||
|
||||
# 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.
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
function Get-PrereqExecutor ($test) {
|
||||
if ($nul -eq $test.dependency_executor_name) { $executor = $test.executor.name }
|
||||
else { $executor = $test.dependency_executor_name }
|
||||
$executor
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
function Invoke-CheckPrereqs ($test, $isElevated, $customInputArgs, $PathToAtomicsFolder) {
|
||||
$FailureReasons = New-Object System.Collections.ArrayList
|
||||
if ($test.executor.elevation_required -and -not $isElevated) {
|
||||
$FailureReasons.add("Elevation required but not provided`n") | Out-Null
|
||||
}
|
||||
foreach ($dep in $test.dependencies) {
|
||||
$executor = Get-PrereqExecutor $test
|
||||
$final_command = Merge-InputArgs $dep.prereq_command $test $customInputArgs $PathToAtomicsFolder
|
||||
$success = Invoke-ExecuteCommand $final_command $executor
|
||||
$description = Merge-InputArgs $dep.description $test $customInputArgs $PathToAtomicsFolder
|
||||
if (-not $success) {
|
||||
$FailureReasons.add($description) | Out-Null
|
||||
}
|
||||
}
|
||||
$FailureReasons
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
function Invoke-ExecuteCommand ($finalCommand, $executor) {
|
||||
$null = @(
|
||||
$success = $true
|
||||
Write-Verbose -Message 'Invoking Atomic Tests using defined executor'
|
||||
$finalCommandEscaped = $finalCommand -replace "`"", "```""
|
||||
if ($executor -eq "command_prompt" -or $executor -eq "sh" -or $executor -eq "bash") {
|
||||
$execCommand = $finalCommandEscaped.Split("`n") | Where-Object { $_ -ne "" }
|
||||
$exitCodes = New-Object System.Collections.ArrayList
|
||||
$execPrefix = "cmd.exe /c"
|
||||
if ($executor -eq "sh") { $execPrefix = "sh -c" }
|
||||
if ($executor -eq "bash") { $execPrefix = "bash -c" }
|
||||
$execCommand | ForEach-Object {
|
||||
$retval = Invoke-Expression "$execPrefix `"$_`" "
|
||||
if ($nul -ne $retval) { $retval | Write-Host }
|
||||
$exitCodes.Add($LASTEXITCODE) | Out-Null
|
||||
}
|
||||
$nonZeroExitCodes = $exitCodes | Where-Object { $_ -ne 0 }
|
||||
$success = $nonZeroExitCodes.Count -eq 0
|
||||
}
|
||||
elseif ($executor -eq "powershell") {
|
||||
$finalCommand = $finalCommand.trim()
|
||||
$execCommand = "Invoke-Command -ScriptBlock {$finalCommand}"
|
||||
$res = Invoke-Expression $execCommand
|
||||
$success = [string]::IsNullOrEmpty($finalCommand) -or $res -eq 0
|
||||
}
|
||||
else {
|
||||
Write-Warning -Message "Unable to generate or execute the command line properly. Unknown executor"
|
||||
$success = $false
|
||||
}
|
||||
)
|
||||
$success
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
function Get-InputArgs([hashtable]$ip, $customInputArgs, $PathToAtomicsFolder) {
|
||||
$defaultArgs = @{ }
|
||||
foreach ($key in $ip.Keys) {
|
||||
$defaultArgs[$key] = $ip[$key].default
|
||||
}
|
||||
# overwrite defaults with any user supplied values
|
||||
foreach ($key in $customInputArgs.Keys) {
|
||||
if ($defaultArgs.Keys -contains $key) {
|
||||
# replace default with user supplied
|
||||
$defaultArgs.set_Item($key, $customInputArgs[$key])
|
||||
}
|
||||
}
|
||||
# Replace $PathToAtomicsFolder or PathToAtomicsFolder with the actual -PathToAtomicsFolder value
|
||||
foreach ($key in $defaultArgs.Clone().Keys) {
|
||||
$defaultArgs.set_Item($key, ($defaultArgs[$key] -replace "\`$PathToAtomicsFolder", $PathToAtomicsFolder -replace "PathToAtomicsFolder", $PathToAtomicsFolder))
|
||||
}
|
||||
$defaultArgs
|
||||
}
|
||||
|
||||
function Merge-InputArgs($finalCommand, $test, $customInputArgs, $PathToAtomicsFolder) {
|
||||
if (($null -ne $finalCommand) -and ($test.input_arguments.Count -gt 0)) {
|
||||
Write-Verbose -Message 'Replacing inputArgs with user specified values, or default values if none provided'
|
||||
$inputArgs = Get-InputArgs $test.input_arguments $customInputArgs $PathToAtomicsFolder
|
||||
|
||||
foreach ($key in $inputArgs.Keys) {
|
||||
$findValue = '#{' + $key + '}'
|
||||
$finalCommand = $finalCommand.Replace($findValue, $inputArgs[$key])
|
||||
}
|
||||
}
|
||||
$finalCommand
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
function Show-Details ($test, $testCount, $technique, $customInputArgs, $PathToAtomicsFolder) {
|
||||
# Header info
|
||||
$tName = $technique.display_name.ToString() + " " + $technique.attack_technique.ToString()
|
||||
Write-KeyValue "[********BEGIN TEST*******]`nTechnique: " $tName
|
||||
Write-KeyValue "Atomic Test Name: " $test.name.ToString()
|
||||
Write-KeyValue "Atomic Test Number: " $testCount
|
||||
Write-KeyValue "Description: " $test.description.ToString().trim()
|
||||
|
||||
# Attack Commands
|
||||
Write-Host -ForegroundColor Yellow "Attack Commands:"
|
||||
$elevationRequired = $false
|
||||
if ($nul -ne $test.executor.elevation_required ) { $elevationRequired = $test.executor.elevation_required }
|
||||
$executor_name = $test.executor.name
|
||||
Write-KeyValue "Executor: " $executor_name
|
||||
Write-KeyValue "ElevationRequired: " $elevationRequired
|
||||
$final_command = Merge-InputArgs $test.executor.command $test $customInputArgs $PathToAtomicsFolder
|
||||
Write-KeyValue "Command:`n" $test.executor.command.trim()
|
||||
if ($test.executor.command -ne $final_command) { Write-KeyValue "Command (with inputs):`n" $final_command.trim() }
|
||||
|
||||
# Cleanup Commands
|
||||
if ($nul -ne $test.executor.cleanup_command) {
|
||||
Write-Host -ForegroundColor Yellow "Cleanup Commands:"
|
||||
$final_command = Merge-InputArgs $test.executor.cleanup_command $test $customInputArgs $PathToAtomicsFolder
|
||||
Write-KeyValue "Command:`n" $test.executor.cleanup_command.trim()
|
||||
if ($test.executor.command -ne $final_command) { Write-KeyValue "Command (with inputs):`n" $final_command.trim() }
|
||||
}
|
||||
|
||||
# Dependencies
|
||||
if ($nul -ne $test.dependencies) {
|
||||
Write-Host -ForegroundColor Yellow "Dependencies:"
|
||||
foreach ($dep in $test.dependencies) {
|
||||
$final_command_prereq = Merge-InputArgs $dep.prereq_command $test $customInputArgs $PathToAtomicsFolder
|
||||
$final_command_get_prereq = Merge-InputArgs $dep.get_prereq_command $test $customInputArgs $PathToAtomicsFolder
|
||||
$description = Merge-InputArgs $dep.description $test $customInputArgs $PathToAtomicsFolder
|
||||
Write-KeyValue "Description: " $description.trim()
|
||||
Write-KeyValue "Check Prereq Command:`n" $dep.prereq_command.trim()
|
||||
if ( $dep.prereq_command -ne $final_command_prereq ) { Write-KeyValue "Check Prereq Command (with inputs):`n" $final_command_prereq.trim() }
|
||||
Write-KeyValue "Get Prereq Command:`n" $dep.get_prereq_command.trim()
|
||||
if ( $dep.get_prereq_command -ne $final_command_get_prereq ) { Write-KeyValue "Get Prereq Command (with inputs):`n" $final_command_get_prereq.trim() }
|
||||
}
|
||||
}
|
||||
# Footer
|
||||
Write-Host -Fore Cyan "[!!!!!!!!END TEST!!!!!!!]`n`n"
|
||||
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
function Write-KeyValue ($key, $value) {
|
||||
Write-Host -ForegroundColor Cyan -NoNewline $key
|
||||
Write-Host -ForegroundColor Green $value
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
function Write-PrereqResults ($FailureReasons, $testId) {
|
||||
if ($FailureReasons.Count -eq 0) {
|
||||
Write-KeyValue "Prerequisites met: " $testId
|
||||
}
|
||||
else {
|
||||
Write-Host -ForegroundColor Red "Prerequisites not met: $testId"
|
||||
foreach ($reason in $FailureReasons) {
|
||||
Write-Host -ForegroundColor Yellow -NoNewline "`t[*] $reason"
|
||||
}
|
||||
Write-Host -ForegroundColor Yellow -NoNewline "`nTry installing prereq's with the "
|
||||
Write-Host -ForegroundColor Cyan -NoNewline "-GetPrereqs"
|
||||
Write-Host -ForegroundColor Yellow " switch"
|
||||
}
|
||||
}
|
||||
+54
-107
@@ -59,6 +59,12 @@ function Invoke-AtomicTest {
|
||||
[switch]
|
||||
$CheckPrereqs = $false,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[switch]
|
||||
$GetPrereqs = $false,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
@@ -88,7 +94,7 @@ function Invoke-AtomicTest {
|
||||
BEGIN { } # Intentionally left blank and can be removed
|
||||
PROCESS {
|
||||
Write-Verbose -Message 'Attempting to run Atomic Techniques'
|
||||
if ($ShowDetails -or $InformationPreference -eq "Continue") { $info = $true } else { $info = $false }
|
||||
Write-Host -ForegroundColor Cyan "PathToAtomicsFolder = $PathToAtomicsFolder`n"
|
||||
|
||||
$isElevated = $false
|
||||
$targetPlatform = "linux"
|
||||
@@ -101,45 +107,7 @@ function Invoke-AtomicTest {
|
||||
$targetPlatform = "windows"
|
||||
$isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
Write-Host -ForegroundColor Cyan "PathToAtomicsFolder = $PathToAtomicsFolder`n"
|
||||
|
||||
function Get-InputArgs([hashtable]$ip) {
|
||||
$defaultArgs = @{ }
|
||||
foreach ($key in $ip.Keys) {
|
||||
$defaultArgs[$key] = $ip[$key].default
|
||||
}
|
||||
# overwrite defaults with any user supplied values
|
||||
foreach ($key in $InputArgs.Keys) {
|
||||
if ($defaultArgs.Keys -contains $key) {
|
||||
# replace default with user supplied
|
||||
$defaultArgs.set_Item($key, $InputArgs[$key])
|
||||
}
|
||||
}
|
||||
# Replace $PathToAtomicsFolder or PathToAtomicsFolder with the actual -PathToAtomicsFolder value
|
||||
foreach ($key in $defaultArgs.Clone().Keys) {
|
||||
$defaultArgs.set_Item($key, ($defaultArgs[$key] -replace "\`$PathToAtomicsFolder", $PathToAtomicsFolder -replace "PathToAtomicsFolder", $PathToAtomicsFolder))
|
||||
}
|
||||
$defaultArgs
|
||||
}
|
||||
|
||||
function Write-PrereqResults ($success) {
|
||||
if ($CheckPrereqs ) {
|
||||
if ($test.executor.elevation_required -and -not $isElevated) {
|
||||
Write-Host -ForegroundColor Red "Prerequisites not met: $testId (elevation required but not provided)"
|
||||
}
|
||||
elseif ($success) {
|
||||
Write-Host -ForegroundColor Green "Prerequisites met: $testId"
|
||||
}
|
||||
else {
|
||||
Write-Host -ForegroundColor Red "Prerequisites not met: $testId"
|
||||
}
|
||||
}
|
||||
elseif ($test.executor.elevation_required -and -not $isElevated) {
|
||||
Write-Host -ForegroundColor yellow "Warning: Test '$testId' should be run from an elevated context but wasn't. Try running this test with administrative privileges. "
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Invoke-AtomicTestSingle ($AT) {
|
||||
|
||||
$AT = $AT.ToUpper()
|
||||
@@ -198,85 +166,64 @@ function Invoke-AtomicTest {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($info) {
|
||||
Write-Host -Fore Blue ("[********BEGIN TEST*******]`nTechnique: " +
|
||||
$technique.display_name.ToString(), $technique.attack_technique.ToString())
|
||||
Write-Host -Fore Blue "Atomic Test Name: " $test.name.ToString()
|
||||
Write-Host -Fore Blue "Atomic Test Number: " $testCount
|
||||
Write-Host -Fore Blue "Description: " $test.description.ToString().trim()
|
||||
if ($ShowDetails) {
|
||||
Show-Details $test $testCount $technique $InputArgs $PathToAtomicsFolder
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Debug -Message 'Gathering final Atomic test command'
|
||||
$testId = "$AT-$testCount $($test.name)"
|
||||
|
||||
$prereqCommand = $test.executor.prereq_command
|
||||
$command = $test.executor.command
|
||||
$cleanupCommand = $test.executor.cleanup_command
|
||||
|
||||
if ($CheckPrereqs) {
|
||||
$finalCommand = $prereqCommand
|
||||
}
|
||||
elseif ($Cleanup) {
|
||||
$finalCommand = $cleanupCommand
|
||||
}
|
||||
else {
|
||||
$finalCommand = $command
|
||||
Write-KeyValue "CheckPrereq's for: " $testId
|
||||
$failureReasons = Invoke-CheckPrereqs $test $isElevated $InputArgs $PathToAtomicsFolder
|
||||
Write-PrereqResults $FailureReasons $testId
|
||||
}
|
||||
elseif ($GetPrereqs) {
|
||||
Write-KeyValue "GetPrereq's for: " $testId
|
||||
if ($nul -eq $test.dependencies) { Write-KeyValue "No Preqs Defined"; continue}
|
||||
foreach ($dep in $test.dependencies) {
|
||||
$executor = Get-PrereqExecutor $test
|
||||
$description = (Merge-InputArgs $dep.description $test $InputArgs $PathToAtomicsFolder).trim()
|
||||
Write-KeyValue "Attempting to satisfy prereq: " $description
|
||||
$final_command_prereq = Merge-InputArgs $dep.prereq_command $test $InputArgs $PathToAtomicsFolder
|
||||
$final_command_get_prereq = Merge-InputArgs $dep.get_prereq_command $test $InputArgs $PathToAtomicsFolder
|
||||
$success = Invoke-ExecuteCommand $final_command_prereq $executor
|
||||
if ($success) {
|
||||
Write-KeyValue "Prereq already met: " $description
|
||||
}
|
||||
else {
|
||||
|
||||
if (($null -ne $finalCommand) -and ($test.input_arguments.Count -gt 0)) {
|
||||
Write-Verbose -Message 'Replacing inputArgs with user specified values, or default values if none provided'
|
||||
$inputArgs = Get-InputArgs $test.input_arguments
|
||||
|
||||
foreach ($key in $inputArgs.Keys) {
|
||||
$findValue = '#{' + $key + '}'
|
||||
$finalCommand = $finalCommand.Replace($findValue, $inputArgs[$key])
|
||||
$retval = Invoke-ExecuteCommand $final_command_get_prereq $executor
|
||||
$success = Invoke-ExecuteCommand $final_command_prereq $executor
|
||||
if ($success) {
|
||||
Write-KeyValue "Prereq successfully met: " $description
|
||||
}
|
||||
else {
|
||||
Write-Host -ForegroundColor Red "Failed to meet prereq: $description"
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($test.executor.elevation_required -and -not $isElevated) {
|
||||
Write-Host -ForegroundColor Red "Elevation required but not provided"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Debug -Message 'Getting executor and build command script'
|
||||
|
||||
if ($ShowDetails -and ($null -ne $finalCommand)) {
|
||||
$executor_name = $test.executor.name
|
||||
Write-Host -Fore Blue "Executor: $executor_name"
|
||||
Write-Host -Fore Blue "ElevationRequired: $($($test.executor).elevation_required)`nCommands:`n"
|
||||
Write-Host -Fore cyan $finalCommand
|
||||
elseif ($Cleanup) {
|
||||
Write-KeyValue "Executing Cleanup for Test: " $testId
|
||||
$final_command = Merge-InputArgs $test.executor.cleanup_command $test $InputArgs $PathToAtomicsFolder
|
||||
Invoke-ExecuteCommand $final_command $test.executor.name | Out-Null
|
||||
Write-KeyValue "Done"
|
||||
}
|
||||
else {
|
||||
Write-KeyValue "Executing Test: " $testId
|
||||
$startTime = get-date
|
||||
Write-Verbose -Message 'Invoking Atomic Tests using defined executor'
|
||||
$testName = $test.name.ToString()
|
||||
if ($pscmdlet.ShouldProcess($testName, 'Execute Atomic Test')) {
|
||||
$testId = "$AT-$testCount $testName"
|
||||
$attackExecuted = $false
|
||||
$executor = $test.executor.name
|
||||
$finalCommandEscaped = $finalCommand -replace "`"", "```""
|
||||
if ($executor -eq "command_prompt" -or $executor -eq "sh" -or $executor -eq "bash") {
|
||||
$execCommand = $finalCommandEscaped.Split("`n") | Where-Object { $_ -ne "" }
|
||||
$exitCodes = New-Object System.Collections.ArrayList
|
||||
$execPrefix = "cmd.exe /c"
|
||||
if ($executor -eq "sh") { $execPrefix = "sh -c" }
|
||||
if ($executor -eq "bash") { $execPrefix = "bash -c" }
|
||||
$execCommand | ForEach-Object {
|
||||
Invoke-Expression "$execPrefix `"$_`" "
|
||||
$exitCodes.Add($LASTEXITCODE) | Out-Null
|
||||
}
|
||||
$nonZeroExitCodes = $exitCodes | Where-Object { $_ -ne 0 }
|
||||
$success = $nonZeroExitCodes.Count -eq 0
|
||||
}
|
||||
elseif ($executor -eq "powershell") {
|
||||
$execCommand = "Invoke-Command -ScriptBlock {$finalCommand}"
|
||||
$res = Invoke-Expression $execCommand
|
||||
$success = [string]::IsNullOrEmpty($finalCommand) -or $res -eq 0
|
||||
}
|
||||
else {
|
||||
Write-Warning -Message "Unable to generate or execute the command line properly."
|
||||
continue
|
||||
}
|
||||
if (!$CheckPrereqs -and !$Cleanup) { $attackExecuted = $true }
|
||||
Write-PrereqResults ($success) $testId
|
||||
if (-not $NoExecutionLog -and $attackExecuted) { Write-ExecutionLog $startTime $AT $testCount $testName $ExecutionLogPath }
|
||||
} # End of if ShouldProcess block
|
||||
} # End of else statement
|
||||
if ($info) { Write-Host -Fore Blue "[!!!!!!!!END TEST!!!!!!!]`n`n" }
|
||||
$final_command = Merge-InputArgs $test.executor.command $test $InputArgs $PathToAtomicsFolder
|
||||
Invoke-ExecuteCommand $final_command $test.executor.name | Out-Null
|
||||
Write-ExecutionLog $startTime $AT $testCount $testName $ExecutionLogPath
|
||||
Write-KeyValue "Done"
|
||||
}
|
||||
|
||||
} # End of foreach Test in single Atomic Technique
|
||||
} # End of foreach Technique in Atomic Tests
|
||||
} # End of Invoke-AtomicTestSingle function
|
||||
@@ -291,7 +238,7 @@ function Invoke-AtomicTest {
|
||||
$AllAtomicTests.GetEnumerator() | Foreach-Object { Invoke-AtomicTestSingle $_ }
|
||||
}
|
||||
|
||||
if ( ($Force -or $CheckPrereqs) -or $psCmdlet.ShouldContinue( 'Do you wish to execute all tests?',
|
||||
if ( ($Force -or $CheckPrereqs -or $ShowDetails -or $GetPrereqs) -or $psCmdlet.ShouldContinue( 'Do you wish to execute all tests?',
|
||||
"Highway to the danger zone, Executing All Atomic Tests!" ) ) {
|
||||
Invoke-AllTests
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
function Invoke-WebRequestVerifyHash ($url, $outfile, $hash) {
|
||||
$success = $false
|
||||
$null = @(
|
||||
New-Item -ItemType Directory (Split-Path $outfile) -Force | Out-Null
|
||||
$ms = New-Object IO.MemoryStream
|
||||
(New-Object System.Net.WebClient).OpenRead($url).copyto($ms)
|
||||
$ms.seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||
$actualHash = (Get-FileHash -InputStream $ms).Hash
|
||||
if ( $hash -eq $actualHash) {
|
||||
$ms.seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||
$fileStream = New-Object IO.FileStream $outfile, ([System.IO.FileMode]::Create)
|
||||
$ms.CopyTo($fileStream);
|
||||
$fileStream.Close()
|
||||
$success = $true
|
||||
}
|
||||
else {
|
||||
Write-Host -ForegroundColor red "File hash mismatch, expected: $hash, actual: $actualHash"
|
||||
}
|
||||
)
|
||||
$success
|
||||
}
|
||||
@@ -48,6 +48,9 @@ Force
|
||||
|
||||
### Manual Installation
|
||||
|
||||
|
||||
`set-executionpolicy Unrestricted`
|
||||
|
||||
[PowerShell-Yaml](https://github.com/cloudbase/powershell-yaml) is required to parse Atomic yaml files:
|
||||
|
||||
`Install-Module -Name powershell-yaml -Scope CurrentUser`
|
||||
@@ -96,24 +99,10 @@ Invoke-AtomicTest All -PathToAtomicsFolder C:\AtomicRedTeam\atomics
|
||||
|
||||
#### Display Test Details without Executing the Test
|
||||
|
||||
Show the attack commands:
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All -ShowDetails
|
||||
```
|
||||
|
||||
Show the Prereq commands:
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All -CheckPrereqs -ShowDetails
|
||||
```
|
||||
|
||||
Show the Cleanup commands:
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All -Cleanup -ShowDetails
|
||||
```
|
||||
|
||||
Using the `ShowDetails` switch causes the test details to be printed to the screen and allows for easy copy and paste execution.
|
||||
Note: you may need to change the path where the test definitions are found with the `PathToAtomicsFolder` parameter.
|
||||
|
||||
@@ -123,28 +112,6 @@ Note: you may need to change the path where the test definitions are found with
|
||||
Invoke-AtomicTest T1117
|
||||
```
|
||||
|
||||
By default, test execution details are written to `Invoke-AtomicTest-ExecutionLog.csv` in the current directory.
|
||||
|
||||
#### Specify an Alternate Path for the Execution Log
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -ExecutionLogPath 'C:\Temp\mylog.csv'
|
||||
```
|
||||
|
||||
By default, test execution details are written to `Invoke-AtomicTest-ExecutionLog.csv` in the current directory. Use the `-ExecutionLogPath` parameter to write to a different file. Nothing is logged in the execution log when only running pre-requisite checks with `-CheckPrereqs` or cleanup commands with `-Cleanup`. Use the `-NoExecutionLog` switch to not write execution details to disk.
|
||||
|
||||
#### Check that Prerequistes for a Given Technique are met
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -CheckPrereqs
|
||||
```
|
||||
|
||||
For the "command_prompt", "bash", and "sh" executors, 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 if the pre-requisites are met. Example: **if(Test-Path C:\Windows\System32\cmd.exe) { 0 } else { -1 }**
|
||||
|
||||
Pre-requisites will also be reported as not met if the test is defined with `elevation_required: true` but the current context is not elevated. You can still execute an attack even if the pre-requisites are not met but execution may fail.
|
||||
|
||||
#### Execute Specific Attacks (by Attack Number) for a Given Technique
|
||||
|
||||
```powershell
|
||||
@@ -156,6 +123,40 @@ Invoke-AtomicTest T1117 -TestNumbers 1, 2
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -TestNames "Regsvr32 remote COM scriptlet execution","Regsvr32 local DLL execution"
|
||||
```
|
||||
|
||||
By default, test execution details are written to `Invoke-AtomicTest-ExecutionLog.csv` in the current directory.
|
||||
|
||||
#### Specify an Alternate Path for the Execution Log
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -ExecutionLogPath 'C:\Temp\mylog.csv'
|
||||
```
|
||||
|
||||
By default, test execution details are written to `Invoke-AtomicTest-ExecutionLog.csv` in the current directory. Use the `-ExecutionLogPath` parameter to write to a different file. Execution is only logged in the execution log when the attack commands are run (not when `-ShowDetails` , `-CheckPrereqs`, `GetPrereqs`, or `-Cleanup` swiches are used). Use the `-NoExecutionLog` switch to not write execution details to disk.
|
||||
|
||||
#### Check that Prerequistes for a given test are met
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -TestNumber 1 -CheckPrereqs
|
||||
```
|
||||
|
||||
For the "command_prompt", "bash", and "sh" executors, 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 if the pre-requisites are met. Example: **if(Test-Path C:\Windows\System32\cmd.exe) { 0 } else { -1 }**
|
||||
|
||||
Pre-requisites will also be reported as not met if the test is defined with `elevation_required: true` but the current context is not elevated. You can still execute an attack even if the pre-requisites are not met but execution may fail.
|
||||
|
||||
#### Get Prerequistes
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -TestNumber 1 -GetPrereqs
|
||||
```
|
||||
|
||||
This will run the "Get Prereq Commands" listed in the Dependencies section for the test.
|
||||
|
||||
The execution framework provides a helpful PowerShell function called `Invoke-WebRequestVerifyHash` which only downloads and saves a file to disk if the file hash matches the specified value. Call this method by passing in the url of the file to download, the path where it should be saved, and lastly the expected Sha256 file hash.
|
||||
The function returns `$true` if the file was saved to disk, `$false` otherwise.
|
||||
|
||||
#### Specify Input Parameters on the Command Line
|
||||
|
||||
```powershell
|
||||
@@ -173,37 +174,17 @@ Invoke-AtomicTest T1089 -TestNames "Uninstall Sysmon" -Cleanup
|
||||
|
||||
## Additional Examples
|
||||
|
||||
If you would like output when running tests using the following:
|
||||
|
||||
#### Informational Stream
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -InformationAction Continue
|
||||
```
|
||||
|
||||
#### Verbose Stream
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -Verbose
|
||||
```
|
||||
|
||||
#### Debug Stream
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -Debug
|
||||
```
|
||||
|
||||
#### Confirm
|
||||
|
||||
To run all tests without confirming them run using the Confirm switch to false
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -Confirm:$false
|
||||
Invoke-AtomicTest All -Confirm:$false
|
||||
```
|
||||
|
||||
Or you can set your `$ConfirmPreference` to 'Medium'
|
||||
|
||||
```powershell
|
||||
$ConfirmPreference = 'Medium'
|
||||
Invoke-AtomicTest T1117
|
||||
Invoke-AtomicTest All
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user