Tests/Pester.MaliciousContent.Tests.ps1
function RunRuleForCommand { param([String] $Command) $outputPath = Join-Path $env:TEMP ([IO.Path]::GetRandomFileName() + ".ps1") try { Set-Content -Path $outputPath -Value $Command Invoke-ScriptAnalyzer -Path $outputPath ` -CustomizedRulePath (Resolve-Path $PSScriptRoot\..\MaliciousContentRules.psm1) ` -ExcludeRule PS* } finally { Remove-Item $outputPath } } Describe "Tests for validating malicious content techniques" { It "Should detect suspicious commands (Invoke-Expression)" { $result = RunRuleForCommand '$content = "A"; Invoke-Expression $content' $result.RuleName | Should be "MaliciousContent.DangerousCommand" } It "Should detect suspicious commands (Add-Type)" { $result = RunRuleForCommand '$content = "A"; Add-Type $content' $result.RuleName | Should be "MaliciousContent.DangerousCommand" } It "Should detect dynamic script block" { $result = RunRuleForCommand '& ([ScriptBlock]::Create("1+2"))' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocation" } It "Should detect dynamic script block - NewScriptBlock" { $result = RunRuleForCommand '$a = "A"; $ExecutionContext.InvokeCommand.NewScriptBlock($a)' $result.RuleName | Should be "MaliciousContent.SuspiciousContentText" } It "Should detect dynamic script block - InvokeScript" { $result = RunRuleForCommand '$a = "A"; $ExecutionContext.InvokeCommand.InvokeScript($a)' $result.RuleName | Should be "MaliciousContent.SuspiciousContentText" } It "Should detect dynamic script block - ExpandString" { $result = RunRuleForCommand '$a = "A"; $ExecutionContext.InvokeCommand.ExpandString($a)' $result.RuleName | Should be "MaliciousContent.SuspiciousContentText" } It "Should detect dynamic script block - GetPowerShell" { $result = RunRuleForCommand '$a = { "A" }.GetPowerShell()' $result.RuleName | Should be "MaliciousContent.SuspiciousContentText" } It "Should detect dynamic method invocation" { $result = RunRuleForCommand '[Object]::("Equ" + "als")(1, 2)' $result.RuleName | Should be "MaliciousContent.DynamicMethodInvocation" } It "Should detect dynamic method invocation variable" { $result = RunRuleForCommand '$method = "Equals"; [Object]::$method(1, 2)' $result.RuleName | Should be "MaliciousContent.DynamicMethodInvocation" } It "Should detect access to [Type] via cast" { $result = RunRuleForCommand '$foo = [Type] "Object"' $result.RuleName | Should be "MaliciousContent.DynamicTypeConversion" } It "Should detect access to [Type] via -as" { $result = RunRuleForCommand '$foo = "Object" -as [Type]' $result.RuleName | Should be "MaliciousContent.DynamicTypeCast" } It "Should detect dynamic member access variable" { $result = RunRuleForCommand '$member = "CommandLine"; [Environment]::$member' $result.RuleName | Should be "MaliciousContent.DynamicMemberAccess" } It "Should detect dynamic member access" { $result = RunRuleForCommand '[Environment]::("Command" + "Line")' $result.RuleName | Should be "MaliciousContent.DynamicMemberAccess" } It "Should detect static access on a variable" { $result = RunRuleForCommand '$foo = [Environment]; $foo::CommandLine' $result.RuleName | Should be "MaliciousContent.DynamicMemberAccess" } It "Should not flag unobfuscated static access" { $result = RunRuleForCommand '[Environment]::CommandLine' $result | Should be $null } It "Should detect suspicious token" { $result = RunRuleForCommand '[System.Runtime.InteropServices.Marshal]::ReadIntPtr(0)' $result.RuleName | Should be "MaliciousContent.SuspiciousContentText" } It "Should detect suspicious token case insenstive" { $result = RunRuleForCommand '[system.runtime.interopservices.marshal]::readintptr(0)' $result.RuleName | Should be "MaliciousContent.SuspiciousContentText" } It "Should detect multiple suspicious tokens" { $results = RunRuleForCommand '[system.runtime.interopservices.marshal]::readintptr(0); Add-Type Foo' ($results.Count -gt 2) | Should be $true } It "Should detect command indirection - invocation" { $result = RunRuleForCommand '$command = "Add-" + "Type"; & $command' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocation" } It "Should detect command indirection - new alias" { $result = RunRuleForCommand 'New-Alias Foo ("Add-" + "Type")' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocationNewAlias" } It "Should detect command indirection - import alias" { $result = RunRuleForCommand 'Import-Alias c:\temp\aliases.clixml' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocationImportAlias" } It "Should detect command indirection - Set-Content provider syntax for aliases" { $result = RunRuleForCommand '$Alias:blah = ("Add-" + "Type")' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocationNewAliasProviderSyntax" } It "Should detect command indirection - Set-Content cmdlet on aliases" { $result = RunRuleForCommand 'Set-Content alias:\foo -Value ("Add-" + "Type")' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocationNewAliasProviderCmdlet" } It "Should detect command indirection - New-Item cmdlet on aliases" { $result = RunRuleForCommand 'New-Item alias:\foo -Value ("Add-" + "Type")' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocationNewAliasProviderCmdlet" } It "Should detect command indirection - New-PSDrive for aliases" { $result = RunRuleForCommand 'New-PSDrive -Name Secret -PSProvider Alias -Root ""' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocationNewAliasNewDrive" } It "Should detect command indirection - New-PSDrive for aliases with variable" { $result = RunRuleForCommand '$drive = "Ali" + "as"; New-PSDrive Secret $drive ""' $result.RuleName | Should be "MaliciousContent.DynamicCommandInvocationNewAliasNewDriveVariable" } ## Possible attacks ## We've put some non-malicious warnings on an ignore list: ## - And they do something (i.e.: insert some lines) to invalidate the whole ignore list ## - And they add some new content (maybe under the same parent?) that gets also ignored by the ignore list ## We've ignored a non-malicious type conversion (for example), but then they change it to be malicious without ## chaging the raw hit. I.e.: $type = [String]; $type.GetProperties() -> $type = [Type]; $type.GetProperties() } |