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 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 | Should be 3
        $results[0].RuleName | Should be "MaliciousContent.SuspiciousContentText"
        $results[0].Extent.Text | Should match "marshal"

        $results[1].RuleName | Should be "MaliciousContent.SuspiciousContentText"
        $results[1].Extent.Text | Should match "readintptr"

        $results[2].RuleName | Should be "MaliciousContent.SuspiciousContentText"
        $results[2].Extent.Text | Should match 'Add-Type'
    }


    ## 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()
}