Skip to content

Commit

Permalink
Merge pull request #179 from cyberbuff/psscriptanalyzer
Browse files Browse the repository at this point in the history
PSScript Analyzer fixes
  • Loading branch information
clr2of8 authored Dec 26, 2023
2 parents 70f8d47 + 47be37d commit ee5746d
Show file tree
Hide file tree
Showing 29 changed files with 319 additions and 287 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Lint
on: pull_request

jobs:
install-invoke:
name: Install Invoke-Atomic
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
- name: Run lint checks
shell: pwsh
run: |
Install-Module -Name PSScriptAnalyzer -Force
Invoke-ScriptAnalyzer -Recurse ./ -Settings ./PSScriptAnalyzerSettings.psd1 -Fix
- name: Check whether there are any file changes
shell: bash
run: |
git diff --exit-code
14 changes: 7 additions & 7 deletions Invoke-AtomicRedTeam.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
PowerShellVersion = '5.0'

# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @('powershell-yaml')
RequiredModules = @('powershell-yaml')

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# AtomicClassSchema.ps1 needs to be present in the caller's scope in order for the built-in classes to surface properly.
ScriptsToProcess = @('Private\AtomicClassSchema.ps1','Public\config.ps1')
ScriptsToProcess = @('Private\AtomicClassSchema.ps1', 'Public\config.ps1')

# 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 = @(
Expand All @@ -53,26 +53,26 @@
# Variables to export from this module
VariablesToExport = '*'

NestedModules = @(
NestedModules = @(
"Public\Default-ExecutionLogger.psm1",
"Public\Attire-ExecutionLogger.psm1",
"Public\Syslog-ExecutionLogger.psm1",
"Public\WinEvent-ExecutionLogger.psm1"
)
)

# 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 = @('Security', 'Defense')
Tags = @('Security', 'Defense')

# A URL to the license for this module.
LicenseUri = 'https://github.com/redcanaryco/invoke-atomicredteam/blob/master/LICENSE.txt'
LicenseUri = 'https://github.com/redcanaryco/invoke-atomicredteam/blob/master/LICENSE.txt'

# A URL to the main website for this project.
ProjectUri = 'https://github.com/redcanaryco/invoke-atomicredteam'
ProjectUri = 'https://github.com/redcanaryco/invoke-atomicredteam'

# A URL to an icon representing this module.
# IconUri = ''
Expand Down
5 changes: 5 additions & 0 deletions PSScriptAnalyzerSettings.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# PSScriptAnalyzerSettings.psd1
@{
ExcludeRules=@('PSUseSingularNouns',
'PSAvoidUsingWriteHost')
}
4 changes: 2 additions & 2 deletions Private/AtomicClassSchema.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class AtomicExecutorBase {
[Bool] $elevation_required

# Implemented to facilitate improved PS object display
[String] ToString(){
[String] ToString() {
return $this.Name
}
}
Expand Down Expand Up @@ -43,7 +43,7 @@ class AtomicTest {
[AtomicExecutorBase] $executor

# Implemented to facilitate improved PS object display
[String] ToString(){
[String] ToString() {
return $this.name
}
}
Expand Down
4 changes: 2 additions & 2 deletions Private/Get-PrereqExecutor.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function Get-PrereqExecutor ($test) {
if ($nul -eq $test.dependency_executor_name) { $executor = $test.executor.name }
function Get-PrereqExecutor ($test) {
if ($nul -eq $test.dependency_executor_name) { $executor = $test.executor.name }
else { $executor = $test.dependency_executor_name }
$executor
}
15 changes: 8 additions & 7 deletions Private/Get-TargetInfo.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function Get-TargetInfo($Session) {
function Get-TargetInfo($Session) {
$tmpDir = "$env:TEMP\"
$isElevated = $false
$targetHostname = hostname
Expand All @@ -10,14 +10,15 @@ function Get-TargetInfo($Session) {
$targetHostname = hostname
$targetUser = whoami
if ($IsLinux) { $targetPlatform = "linux" }
elseif ($IsMacOS) { $targetPlatform = "macos" }
else { # windows
elseif ($IsMacOS) { $targetPlatform = "macos" }
else {
# windows
$tmpDir = "$env:TEMP\"
$isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
if ($IsLinux -or $IsMacOS) {
$isElevated = $false
$privid = id -u
$privid = id -u
if ($privid -eq 0) { $isElevated = $true }
}
$targetPlatform, $isElevated, $tmpDir, $targetHostname, $targetUser
Expand All @@ -28,15 +29,15 @@ function Get-TargetInfo($Session) {
if ($IsLinux -or $IsMacOS) {
$tmpDir = "/tmp/"
$isElevated = $false
$privid = id -u
$privid = id -u
if ($privid -eq 0) { $isElevated = $true }
if ($IsMacOS) { $targetPlatform = "macos" }
}
else {
$targetPlatform = "windows"
$isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

}
$targetPlatform, $isElevated, $tmpDir, $targetHostname, $targetUser
}
}
2 changes: 1 addition & 1 deletion Private/Invoke-CheckPrereqs.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function Invoke-CheckPrereqs ($test, $isElevated, $executionPlatform, $customInp
foreach ($dep in $test.dependencies) {
$executor = Get-PrereqExecutor $test
$final_command = Merge-InputArgs $dep.prereq_command $test $customInputArgs $PathToAtomicsFolder
if($executor -ne "powershell") { $final_command = ($final_Command.trim()).Replace("`n", " && ") }
if ($executor -ne "powershell") { $final_command = ($final_Command.trim()).Replace("`n", " && ") }
$res = Invoke-ExecuteCommand $final_command $executor $executionPlatform $TimeoutSeconds $session
$description = Merge-InputArgs $dep.description $test $customInputArgs $PathToAtomicsFolder
if ($res.ExitCode -ne 0) {
Expand Down
45 changes: 23 additions & 22 deletions Private/Invoke-ExecuteCommand.ps1
Original file line number Diff line number Diff line change
@@ -1,52 +1,53 @@
function Invoke-ExecuteCommand ($finalCommand, $executor, $executionPlatform, $TimeoutSeconds, $session = $null, $interactive) {
function Invoke-ExecuteCommand ($finalCommand, $executor, $executionPlatform, $TimeoutSeconds, $session = $null, $interactive) {
$null = @(
if ($null -eq $finalCommand) { return 0 }
$finalCommand = $finalCommand.trim()
Write-Verbose -Message 'Invoking Atomic Tests using defined executor'
if ($executor -eq "command_prompt" -or $executor -eq "sh" -or $executor -eq "bash") {
$execPrefix = "-c"
$execExe = $executor
if ($executor -eq "command_prompt") {
$execPrefix = "/c";
$execExe = "cmd.exe";
$execCommand = $finalCommand -replace "`n", " & "
$arguments = $execPrefix,"$execCommand"
}
if ($executor -eq "command_prompt") {
$execPrefix = "/c";
$execExe = "cmd.exe";
$execCommand = $finalCommand -replace "`n", " & "
$arguments = $execPrefix, "$execCommand"
}
else {
$finalCommand = $finalCommand -replace "[\\](?!;)", "`\$&"
$finalCommand = $finalCommand -replace "[`"]", "`\$&"
$execCommand = $finalCommand -replace "(?<!;)\n", "; "
$arguments = "$execPrefix `"$execCommand`""
$finalCommand = $finalCommand -replace "[\\](?!;)", "`\$&"
$finalCommand = $finalCommand -replace "[`"]", "`\$&"
$execCommand = $finalCommand -replace "(?<!;)\n", "; "
$arguments = "$execPrefix `"$execCommand`""

}
}
elseif ($executor -eq "powershell") {
$execCommand = $finalCommand -replace "`"", "`\`"`""
if ($session) {
if ($executionPlatform -eq "windows") {
$execExe = "powershell.exe"
$execExe = "powershell.exe"
}
else {
$execExe = "pwsh"
$execExe = "pwsh"
}
}
else {
$execExe = "powershell.exe"; if ($IsLinux -or $IsMacOS) { $execExe = "pwsh" }
}
if ($execExe -eq "pwsh"){
if ($execExe -eq "pwsh") {
$arguments = "-Command $execCommand"
}else{
}
else {
$arguments = "& {$execCommand}"
}
}
else {
Write-Warning -Message "Unable to generate or execute the command line properly. Unknown executor"
return [PSCustomObject]@{
StandardOutput = ""
ErrorOutput = ""
ExitCode = -1
IsTimeOut = $false
}
StandardOutput = ""
ErrorOutput = ""
ExitCode = -1
IsTimeOut = $false
}
}

# Write-Host -ForegroundColor Magenta "$execExe $arguments"
Expand All @@ -56,7 +57,7 @@ function Invoke-ExecuteCommand ($finalCommand, $executor, $executionPlatform, $T
$fp2 = Join-Path $scriptParentPath "Invoke-KillProcessTree.ps1"
invoke-command -Session $session -FilePath $fp
invoke-command -Session $session -FilePath $fp2
$res = invoke-command -Session $session -ScriptBlock { Invoke-Process -filename $Using:execExe -Arguments $Using:arguments -TimeoutSeconds $Using:TimeoutSeconds -stdoutFile "art-out.txt" -stderrFile "art-err.txt" }
$res = invoke-command -Session $session -ScriptBlock { Invoke-Process -filename $Using:execExe -Arguments $Using:arguments -TimeoutSeconds $Using:TimeoutSeconds -stdoutFile "art-out.txt" -stderrFile "art-err.txt" }
}
else {
if ($interactive) {
Expand All @@ -67,7 +68,7 @@ function Invoke-ExecuteCommand ($finalCommand, $executor, $executionPlatform, $T
else {
# Local execution that DO NOT contain interactive prompts
# In this situation, capture the stdout/stderr for Invoke-AtomicTest to send to the caller
$res = Invoke-Process -filename $execExe -Arguments $arguments -TimeoutSeconds $TimeoutSeconds -stdoutFile "art-out.txt" -stderrFile "art-err.txt"
$res = Invoke-Process -filename $execExe -Arguments $arguments -TimeoutSeconds $TimeoutSeconds -stdoutFile "art-out.txt" -stderrFile "art-err.txt"
}
}
)
Expand Down
Loading

0 comments on commit ee5746d

Please sign in to comment.