Asynchronous Attack Execution and other handy things (#790)
* execute attack in separate process * install from custom repoOwner and branch * remove zip after install * added showdetails brief and sleep for linux output * remove positional param spec * replacing special PathToAtomicsFolder in commands * use pwsh on linux * kill proc tree linux * include path in remove-item * update readme * update readme * update readme Co-authored-by: Tony M Lambert <ForensicITGuy@users.noreply.github.com>
This commit is contained in:
committed by
Tony M Lambert
parent
3ef533126a
commit
0dcde71a15
@@ -36,7 +36,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Windows Credential Editor must exist on disk at specified location (#{gsecdump_exe})
|
||||
prereq_command: |
|
||||
if (Test-Path #{gsecdump_exe}) {0} else {1}
|
||||
if (Test-Path #{gsecdump_exe}) {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
Write-Host Automated installer not implemented yet
|
||||
|
||||
@@ -75,7 +75,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Windows Credential Editor must exist on disk at specified location (#{wce_exe})
|
||||
prereq_command: |
|
||||
if (Test-Path #{wce_exe}) {0} else {1}
|
||||
if (Test-Path #{wce_exe}) {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
$parentpath = Split-Path "#{wce_exe}"; $zippath = "$parentpath\wce.zip"
|
||||
if(Invoke-WebRequestVerifyHash "#{wce_url}" "$zippath" #{wce_zip_hash}){
|
||||
@@ -131,7 +131,7 @@ atomic_tests:
|
||||
- description: |
|
||||
ProcDump tool from Sysinternals must exist on disk at specified location (#{procdump_exe})
|
||||
prereq_command: |
|
||||
if (Test-Path #{procdump_exe}) {0} else {1}
|
||||
if (Test-Path #{procdump_exe}) {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
Invoke-WebRequest "https://download.sysinternals.com/files/Procdump.zip" -OutFile "$env:TEMP\Procdump.zip"
|
||||
Expand-Archive $env:TEMP\Procdump.zip $env:TEMP\Procdump -Force
|
||||
@@ -308,7 +308,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Computer must be domain joined
|
||||
prereq_command: |
|
||||
if((Get-CIMInstance -Class Win32_ComputerSystem).PartOfDomain) {0} else {1}
|
||||
if((Get-CIMInstance -Class Win32_ComputerSystem).PartOfDomain) {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
Write-Host Joining this computer to a domain must be done manually
|
||||
|
||||
@@ -340,14 +340,14 @@ atomic_tests:
|
||||
- description: |
|
||||
Get-GPPPassword PowerShell Script must exist at #{gpp_script_path}
|
||||
prereq_command: |
|
||||
if(Test-Path "#{gpp_script_path}") { 0 } else { 1 }
|
||||
if(Test-Path "#{gpp_script_path}") {exit 0 } else {exit 1 }
|
||||
get_prereq_command: |
|
||||
New-Item -ItemType Directory (Split-Path "#{gpp_script_path}") -Force | Out-Null
|
||||
Invoke-WebRequest #{gpp_script_url} -OutFile "#{gpp_script_path}"
|
||||
- description: |
|
||||
Computer must be domain joined
|
||||
prereq_command: |
|
||||
if((Get-CIMInstance -Class Win32_ComputerSystem).PartOfDomain) {0} else {1}
|
||||
if((Get-CIMInstance -Class Win32_ComputerSystem).PartOfDomain) {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
Write-Host Joining this computer to a domain must be done manually
|
||||
|
||||
@@ -385,7 +385,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Invoke-NinjaCopy PowerShell Script must exist at #{ninjacopy_script_path}
|
||||
prereq_command: |
|
||||
if(Test-Path "#{ninjacopy_script_path}") { 0 } else { 1 }
|
||||
if(Test-Path "#{ninjacopy_script_path}") {exit 0 } else {exit 1 }
|
||||
get_prereq_command: |
|
||||
New-Item -ItemType Directory (Split-Path "#{ninjacopy_script_path}") -Force | Out-Null
|
||||
Invoke-WebRequest #{ninjacopy_script_url} -OutFile "#{ninjacopy_script_path}"
|
||||
|
||||
@@ -45,7 +45,7 @@ atomic_tests:
|
||||
- description: |
|
||||
PsExec tool from Sysinternals must exist on disk at specified location (#{psexec_exe})
|
||||
prereq_command: |
|
||||
if (Test-Path "#{psexec_exe}"") {0} else {1}
|
||||
if (Test-Path "#{psexec_exe}"") { exit 0} else { exit 1}
|
||||
get_prereq_command: |
|
||||
Invoke-WebRequest "https://download.sysinternals.com/files/PSTools.zip" -OutFile "$env:TEMP\PsTools.zip"
|
||||
Expand-Archive $env:TEMP\PsTools.zip $env:TEMP\PsTools -Force
|
||||
|
||||
@@ -37,7 +37,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Computer must be domain joined
|
||||
prereq_command: |
|
||||
if((Get-CIMInstance -Class Win32_ComputerSystem).PartOfDomain) {0} else {1}
|
||||
if((Get-CIMInstance -Class Win32_ComputerSystem).PartOfDomain) { exit 0} else { exit 1}
|
||||
get_prereq_command: |
|
||||
Write-Host Joining this computer to a domain must be done manually
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ atomic_tests:
|
||||
- description: |
|
||||
PowerShell version 2 must be installed
|
||||
prereq_command: |
|
||||
if(2 -in $PSVersionTable.PSCompatibleVersions.Major) {0} else {1}
|
||||
if(2 -in $PSVersionTable.PSCompatibleVersions.Major) {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
Write-Host Automated installer not implemented yet, please install PowerShell v2 manually
|
||||
|
||||
@@ -233,7 +233,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Homedrive must be an NTFS drive
|
||||
prereq_command: |
|
||||
if((Get-Volume -DriveLetter $env:HOMEDRIVE[0]).FileSystem -contains "NTFS") {0} else {1}
|
||||
if((Get-Volume -DriveLetter $env:HOMEDRIVE[0]).FileSystem -contains "NTFS") {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
Write-Host Prereq's for this test cannot be met automatically
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ atomic_tests:
|
||||
executor:
|
||||
name: powershell
|
||||
prereq_command: |
|
||||
if(Test-Path C:\Windows\System32\inetsrv\appcmd.exe) {0} else {1}
|
||||
if(Test-Path C:\Windows\System32\inetsrv\appcmd.exe) {exit 0} else {exit 1}
|
||||
command: |
|
||||
C:\Windows\System32\inetsrv\appcmd.exe set config "#{website_name}" /section:httplogging /dontLog:true
|
||||
cleanup_command: |
|
||||
@@ -166,7 +166,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Sysmon executable must be available
|
||||
prereq_command: |
|
||||
if(cmd /c where sysmon) {0} else {1}
|
||||
if(cmd /c where sysmon) {exit 0} else {exit 1}
|
||||
get_prereq_command: |
|
||||
$parentpath = Split-Path "#{sysmon_exe}"; $zippath = "$parentpath\Sysmon.zip"
|
||||
New-Item -ItemType Directory $parentpath -Force | Out-Null
|
||||
@@ -176,7 +176,7 @@ atomic_tests:
|
||||
- description: |
|
||||
Sysmon must be installed
|
||||
prereq_command: |
|
||||
if(cmd /c sc query sysmon) {0} else {1}
|
||||
if(cmd /c sc query sysmon) { exit 0} else { exit 1}
|
||||
get_prereq_command: |
|
||||
cmd /c sysmon -i -accepteula
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ atomic_tests:
|
||||
command: |
|
||||
Start-BitsTransfer -Priority foreground -Source #{remote_file} -Destination #{local_file}
|
||||
cleanup_command: |
|
||||
Remove-Item #{local_file}
|
||||
Remove-Item #{local_file} -ErrorAction Ignore
|
||||
|
||||
- name: Persist, Download, & Execute
|
||||
description: |
|
||||
|
||||
+4
-3
@@ -1,4 +1,4 @@
|
||||
function Invoke-CheckPrereqs ($test, $isElevated, $customInputArgs, $PathToAtomicsFolder) {
|
||||
function Invoke-CheckPrereqs ($test, $isElevated, $customInputArgs, $PathToAtomicsFolder, $TimeoutSeconds) {
|
||||
$FailureReasons = New-Object System.Collections.ArrayList
|
||||
if ($test.executor.elevation_required -and -not $isElevated) {
|
||||
$FailureReasons.add("Elevation required but not provided`n") | Out-Null
|
||||
@@ -6,9 +6,10 @@ function Invoke-CheckPrereqs ($test, $isElevated, $customInputArgs, $PathToAtomi
|
||||
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
|
||||
$final_command = ($final_Command.trim()).Replace("`n", " && ")
|
||||
$res = Invoke-ExecuteCommand $final_command $executor $TimeoutSeconds
|
||||
$description = Merge-InputArgs $dep.description $test $customInputArgs $PathToAtomicsFolder
|
||||
if (-not $success) {
|
||||
if ($res -ne 0) {
|
||||
$FailureReasons.add($description) | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
+13
-21
@@ -1,33 +1,25 @@
|
||||
function Invoke-ExecuteCommand ($finalCommand, $executor) {
|
||||
$null = @(
|
||||
$success = $true
|
||||
if($null -eq $finalCommand) { return $success}
|
||||
if($null -eq $finalCommand){return 0}
|
||||
$finalCommand = $finalCommand.trim()
|
||||
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
|
||||
$execCommand = $finalCommand.Replace("`n", " & ")
|
||||
$execPrefix = "-c"
|
||||
$execExe = $executor
|
||||
if ($executor -eq "command_prompt") { $execPrefix = "/c"; $execExe = "cmd.exe" }
|
||||
$res = Invoke-Process -filename $execExe -Arguments "$execPrefix `"$execCommand`"" -TimeoutSeconds $TimeoutSeconds
|
||||
}
|
||||
elseif ($executor -eq "powershell") {
|
||||
$finalCommand = $finalCommand.trim()
|
||||
$execCommand = "Invoke-Command -ScriptBlock {$finalCommand}"
|
||||
$res = Invoke-Expression $execCommand
|
||||
$success = [string]::IsNullOrEmpty($finalCommand) -or $res -eq 0
|
||||
$execCommand = $finalCommand -replace "`"", "`\`"`""
|
||||
$execExe = "powershell.exe"; if ($IsLinux -or $IsMacOS) { $execExe = "pwsh" }
|
||||
$res = Invoke-Process -filename $execExe -Arguments "& {$execCommand}" -TimeoutSeconds $TimeoutSeconds
|
||||
|
||||
}
|
||||
else {
|
||||
Write-Warning -Message "Unable to generate or execute the command line properly. Unknown executor"
|
||||
$success = $false
|
||||
$res = -1
|
||||
}
|
||||
)
|
||||
$success
|
||||
$res
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
function Invoke-KillProcessTree {
|
||||
Param([int]$ppid)
|
||||
if ($IsLinux -or $IsMacOS) {
|
||||
sh -c pkill -9 -P $ppid
|
||||
}
|
||||
else {
|
||||
while ($null -ne ($gcim = Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq $ppid })) {
|
||||
$gcim | ForEach-Object { Invoke-KillProcessTree $_.ProcessId; Start-Sleep -Seconds 0.5 }
|
||||
}
|
||||
Stop-Process -Id $ppid -ErrorAction Ignore
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# The Invoke-Process function is loosely based on code from https://github.com/guitarrapc/PowerShellUtil/blob/master/Invoke-Process/Invoke-Process.ps1
|
||||
function Invoke-Process {
|
||||
[OutputType([PSCustomObject])]
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $false, Position = 0)]
|
||||
[string]$FileName = "PowerShell.exe",
|
||||
|
||||
[Parameter(Mandatory = $false, Position = 1)]
|
||||
[string]$Arguments = "",
|
||||
|
||||
[Parameter(Mandatory = $false, Position = 2)]
|
||||
[string]$WorkingDirectory = ".",
|
||||
|
||||
[Parameter(Mandatory = $false, Position = 3)]
|
||||
[Int]$TimeoutSeconds = 120
|
||||
)
|
||||
|
||||
end {
|
||||
try {
|
||||
# new Process
|
||||
$process = Start-Process -FilePath $FileName -ArgumentList $Arguments -WorkingDirectory $WorkingDirectory -NoNewWindow -PassThru
|
||||
$handle = $process.Handle # cache process.Handle, otherwise ExitCode is null from powershell processes
|
||||
|
||||
# wait for complete
|
||||
$Timeout = [System.TimeSpan]::FromSeconds(($TimeoutSeconds))
|
||||
if (-not $process.WaitForExit($Timeout.TotalMilliseconds)) {
|
||||
Write-Host -ForegroundColor Red "Process Timed out after $TimeoutSeconds seconds, use '-TimeoutSeconds' to specify a different timeout"
|
||||
Invoke-KillProcessTree $process.id
|
||||
}
|
||||
|
||||
if ($IsLinux -or $IsMacOS) {
|
||||
Start-Sleep -Seconds 5 # On nix, the last 4 lines of stdout get overwritten upon return so pause for a bit to ensure user can view results
|
||||
}
|
||||
|
||||
# Get Process result
|
||||
return $process.ExitCode
|
||||
}
|
||||
finally {
|
||||
if ($null -ne $process) { $process.Dispose() }
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -10,10 +10,6 @@ function Get-InputArgs([hashtable]$ip, $customInputArgs, $PathToAtomicsFolder) {
|
||||
$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
|
||||
}
|
||||
|
||||
@@ -27,5 +23,9 @@ function Merge-InputArgs($finalCommand, $test, $customInputArgs, $PathToAtomicsF
|
||||
$finalCommand = $finalCommand.Replace($findValue, $inputArgs[$key])
|
||||
}
|
||||
}
|
||||
|
||||
# Replace $PathToAtomicsFolder or PathToAtomicsFolder with the actual -PathToAtomicsFolder value
|
||||
$finalCommand = ($finalCommand -replace "\`$PathToAtomicsFolder", $PathToAtomicsFolder) -replace "PathToAtomicsFolder", $PathToAtomicsFolder
|
||||
|
||||
$finalCommand
|
||||
}
|
||||
}
|
||||
+36
-20
@@ -32,12 +32,17 @@ function Invoke-AtomicTest {
|
||||
$AtomicTechnique,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
Position = 1,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[switch]
|
||||
$ShowDetails,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
ValueFromPipelineByPropertyName = $true,
|
||||
ParameterSetName = 'technique')]
|
||||
[switch]
|
||||
$ShowDetailsBrief,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
ParameterSetName = 'technique')]
|
||||
[String[]]
|
||||
@@ -89,7 +94,12 @@ function Invoke-AtomicTest {
|
||||
[Parameter(Mandatory = $false,
|
||||
ParameterSetName = 'technique')]
|
||||
[HashTable]
|
||||
$InputArgs
|
||||
$InputArgs,
|
||||
|
||||
[Parameter(Mandatory = $false,
|
||||
ParameterSetName = 'technique')]
|
||||
[Int]
|
||||
$TimeoutSeconds = 120
|
||||
)
|
||||
BEGIN { } # Intentionally left blank and can be removed
|
||||
PROCESS {
|
||||
@@ -166,38 +176,43 @@ function Invoke-AtomicTest {
|
||||
continue
|
||||
}
|
||||
|
||||
$testId = "$AT-$testCount $($test.name)"
|
||||
if ($ShowDetails) {
|
||||
Show-Details $test $testCount $technique $InputArgs $PathToAtomicsFolder
|
||||
continue
|
||||
}
|
||||
if($ShowDetailsBrief){
|
||||
Write-KeyValue $testId
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Debug -Message 'Gathering final Atomic test command'
|
||||
$testId = "$AT-$testCount $($test.name)"
|
||||
|
||||
|
||||
if ($CheckPrereqs) {
|
||||
Write-KeyValue "CheckPrereq's for: " $testId
|
||||
$failureReasons = Invoke-CheckPrereqs $test $isElevated $InputArgs $PathToAtomicsFolder
|
||||
$failureReasons = Invoke-CheckPrereqs $test $isElevated $InputArgs $PathToAtomicsFolder $TimeoutSeconds
|
||||
Write-PrereqResults $FailureReasons $testId
|
||||
}
|
||||
elseif ($GetPrereqs) {
|
||||
Write-KeyValue "GetPrereq's for: " $testId
|
||||
if ($nul -eq $test.dependencies) { Write-KeyValue "No Preqs Defined"; continue}
|
||||
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_prereq = ($final_command_prereq.trim()).Replace("`n", " && ")
|
||||
$final_command_get_prereq = Merge-InputArgs $dep.get_prereq_command $test $InputArgs $PathToAtomicsFolder
|
||||
$success = Invoke-ExecuteCommand $final_command_prereq $executor
|
||||
if ($success) {
|
||||
$res = Invoke-ExecuteCommand $final_command_prereq $executor $TimeoutSeconds
|
||||
|
||||
if ($res -eq 0) {
|
||||
Write-KeyValue "Prereq already met: " $description
|
||||
}
|
||||
else {
|
||||
|
||||
$retval = Invoke-ExecuteCommand $final_command_get_prereq $executor
|
||||
$success = Invoke-ExecuteCommand $final_command_prereq $executor
|
||||
if ($success) {
|
||||
$res = Invoke-ExecuteCommand $final_command_get_prereq $executor $TimeoutSeconds
|
||||
$res = Invoke-ExecuteCommand $final_command_prereq $executor $TimeoutSeconds
|
||||
if ($res -eq 0) {
|
||||
Write-KeyValue "Prereq successfully met: " $description
|
||||
}
|
||||
else {
|
||||
@@ -210,18 +225,18 @@ function Invoke-AtomicTest {
|
||||
}
|
||||
}
|
||||
elseif ($Cleanup) {
|
||||
Write-KeyValue "Executing Cleanup for Test: " $testId
|
||||
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"
|
||||
$res = Invoke-ExecuteCommand $final_command $test.executor.name $TimeoutSeconds
|
||||
Write-KeyValue "Done executing cleanup for test: " $testId
|
||||
}
|
||||
else {
|
||||
Write-KeyValue "Executing Test: " $testId
|
||||
Write-KeyValue "Executing test: " $testId
|
||||
$startTime = get-date
|
||||
$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"
|
||||
$res = Invoke-ExecuteCommand $final_command $test.executor.name $TimeoutSeconds
|
||||
Write-ExecutionLog $startTime $AT $testCount $testName $ExecutionLogPath $TimeoutSeconds
|
||||
Write-KeyValue "Done executing test: " $testId
|
||||
}
|
||||
|
||||
} # End of foreach Test in single Atomic Technique
|
||||
@@ -238,7 +253,7 @@ function Invoke-AtomicTest {
|
||||
$AllAtomicTests.GetEnumerator() | Foreach-Object { Invoke-AtomicTestSingle $_ }
|
||||
}
|
||||
|
||||
if ( ($Force -or $CheckPrereqs -or $ShowDetails -or $GetPrereqs) -or $psCmdlet.ShouldContinue( 'Do you wish to execute all tests?',
|
||||
if ( ($Force -or $CheckPrereqs -or $ShowDetails -or $ShowDetailsBrief -or $GetPrereqs) -or $psCmdlet.ShouldContinue( 'Do you wish to execute all tests?',
|
||||
"Highway to the danger zone, Executing All Atomic Tests!" ) ) {
|
||||
Invoke-AllTests
|
||||
}
|
||||
@@ -249,4 +264,5 @@ function Invoke-AtomicTest {
|
||||
|
||||
} # End of PROCESS block
|
||||
END { } # Intentionally left blank and can be removed
|
||||
}
|
||||
}
|
||||
# Invoke-AtomicTest t1003 -TestNumbers 13 -GetPrereqs
|
||||
@@ -46,6 +46,16 @@ Force
|
||||
|
||||
`Install-AtomicRedTeam -Force`
|
||||
|
||||
RepoOwner
|
||||
- Install ART from another repo. Default RepoOwner is "redcanaryco"
|
||||
|
||||
`Install-AtomicRedTeam -RepoOwner clr2of8`
|
||||
|
||||
Branch
|
||||
- Install ART from another branch. Default Branch is "master"
|
||||
|
||||
`Install-AtomicRedTeam -RepoOwner clr2of8 -Branch start-process-branch`
|
||||
|
||||
### Manual Installation
|
||||
|
||||
|
||||
@@ -69,12 +79,26 @@ Import-Module C:\AtomicRedTeam\execution-frameworks\Invoke-AtomicRedTeam\Invoke-
|
||||
|
||||
Note: Your path to the **_Invoke-AtomicRedTeam.psm1_** may be different.
|
||||
|
||||
#### Execute All Tests
|
||||
|
||||
Execute all Atomic tests:
|
||||
#### Display Test Details for the given Technique Number without Executing any Tests
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All
|
||||
Invoke-AtomicTest T1089 -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.
|
||||
|
||||
#### Display Only Test Names and Numbers
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All -ShowDetailsBrief
|
||||
```
|
||||
|
||||
#### Execute All Attacks for a Given Technique
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117
|
||||
```
|
||||
|
||||
This assumes your atomics folder is in the default location of `<BASEPATH>\AtomicRedTeam\atomics`
|
||||
@@ -89,29 +113,6 @@ $PSDefaultParameterValues = @{"Invoke-AtomicTest:PathToAtomicsFolder"="C:\Users\
|
||||
|
||||
Tip: Add this to your PowerShell profile so it is always set to your preferred default value.
|
||||
|
||||
#### Execute All Tests - Specific Directory
|
||||
|
||||
Specify a path to atomics folder, example C:\AtomicRedTeam\atomics
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All -PathToAtomicsFolder C:\AtomicRedTeam\atomics
|
||||
```
|
||||
|
||||
#### Display Test Details without Executing the Test
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All -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.
|
||||
|
||||
#### Execute All Attacks for a Given Technique
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117
|
||||
```
|
||||
|
||||
#### Execute Specific Attacks (by Attack Number) for a Given Technique
|
||||
|
||||
```powershell
|
||||
@@ -124,7 +125,29 @@ Invoke-AtomicTest T1117 -TestNumbers 1, 2
|
||||
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.
|
||||
#### Speficy a Process Timeout
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest T1117 -TimeoutSeconds 15
|
||||
```
|
||||
|
||||
If the attack commands do not exit (return) within in the specified `-TimeoutSeconds`, the process and it's children will be forcefully terminated. The default value of `-TimeoutSeconds` is 120. This allows the `Invoke-AtomicTest` script to move on to the next test.
|
||||
|
||||
#### Execute All Tests
|
||||
|
||||
Execute all Atomic tests:
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All
|
||||
```
|
||||
|
||||
#### Execute All Tests from a Specific Directory
|
||||
|
||||
Specify a path to atomics folder, example C:\AtomicRedTeam\atomics
|
||||
|
||||
```powershell
|
||||
Invoke-AtomicTest All -PathToAtomicsFolder C:\AtomicRedTeam\atomics
|
||||
```
|
||||
|
||||
#### Specify an Alternate Path for the Execution Log
|
||||
|
||||
@@ -142,7 +165,7 @@ 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 }**
|
||||
For the "powershell" executor, the prereq_command's are run as a script block and the script must exit 0 if the pre-requisites are met. Example: **if(Test-Path C:\Windows\System32\cmd.exe) { exit 0 } else { exit 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.
|
||||
|
||||
|
||||
@@ -41,6 +41,12 @@ function Install-AtomicRedTeam {
|
||||
[Parameter(Mandatory = $False, Position = 1)]
|
||||
[string]$DownloadPath = $( if ($IsLinux -or $IsMacOS) { $Env:HOME + "/AtomicRedTeam" } else { $env:HOMEDRIVE + "\AtomicRedTeam" }),
|
||||
|
||||
[Parameter(Mandatory = $False, Position = 2)]
|
||||
[string]$RepoOwner = "redcanaryco",
|
||||
|
||||
[Parameter(Mandatory = $False, Position = 3)]
|
||||
[string]$Branch = "master",
|
||||
|
||||
[Parameter(Mandatory = $False)]
|
||||
[switch]$Force = $False # delete the existing install directory and reinstall
|
||||
)
|
||||
@@ -60,19 +66,20 @@ function Install-AtomicRedTeam {
|
||||
New-Item -ItemType directory -Path $InstallPath | Out-Null
|
||||
|
||||
write-verbose "Setting variables for remote URL and download Path"
|
||||
$url = "https://github.com/redcanaryco/atomic-red-team/archive/master.zip"
|
||||
$path = Join-Path $DownloadPath "master.zip"
|
||||
$url = "https://github.com/$RepoOwner/atomic-red-team/archive/$Branch.zip"
|
||||
$path = Join-Path $DownloadPath "$Branch.zip"
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$webClient = new-object System.Net.WebClient
|
||||
write-verbose "Beginning download from Github"
|
||||
$webClient.DownloadFile( $url, $path )
|
||||
|
||||
write-verbose "Extracting ART to $InstallPath"
|
||||
$lp = Join-Path "$DownloadPath" "master.zip"
|
||||
$lp = Join-Path "$DownloadPath" "$Branch.zip"
|
||||
expand-archive -LiteralPath $lp -DestinationPath "$InstallPath" -Force:$Force
|
||||
$unzipPath = Join-Path $InstallPath "atomic-red-team-master"
|
||||
$unzipPath = Join-Path $InstallPath "atomic-red-team-$Branch"
|
||||
Get-ChildItem $unzipPath -Force | Move-Item -dest $InstallPath
|
||||
Remove-Item $unzipPath
|
||||
Remove-Item $path
|
||||
|
||||
if (-not (Get-InstalledModule -Name "powershell-yaml" -ErrorAction:SilentlyContinue)) {
|
||||
write-verbose "Installing powershell-yaml"
|
||||
@@ -83,7 +90,7 @@ function Install-AtomicRedTeam {
|
||||
Import-Module $modulePath -Force
|
||||
|
||||
Write-Host "Installation of Invoke-AtomicRedTeam is complete. You can now use the Invoke-AtomicTest function" -Fore Yellow
|
||||
Write-Host "See README at https://github.com/redcanaryco/atomic-red-team/tree/master/execution-frameworks/Invoke-AtomicRedTeam for complete details" -Fore Yellow
|
||||
Write-Host "See README at https://github.com/$RepoOwner/atomic-red-team/tree/$Branch/execution-frameworks/Invoke-AtomicRedTeam for complete details" -Fore Yellow
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user