Skip to content

Commit

Permalink
Add Invoke-ATHCorProfiler (#4)
Browse files Browse the repository at this point in the history
Adding Invoke-ATHCorProfiler, Pester Tests, updating Readme.md, and AtomicTestHarnesses.psd1
  • Loading branch information
jessecbrown authored Jun 4, 2021
1 parent 1eab118 commit 560cd82
Show file tree
Hide file tree
Showing 4 changed files with 713 additions and 1 deletion.
9 changes: 8 additions & 1 deletion AtomicTestHarnesses.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
RootModule = 'AtomicTestHarnesses.psm1'

# Version number of this module.
ModuleVersion = '1.5.0.0'
ModuleVersion = '1.6.0.0'

# ID used to uniquely identify this module
GUID = '195a1637-d4a4-4cb3-8d80-5b5d4e3e930a'
Expand All @@ -27,12 +27,14 @@ PowerShellVersion = '5.0'
# 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-ATHHTMLApplication',
'Invoke-ATHCompiledHelp',
'Invoke-ATHCorProfiler',
'Invoke-ATHInjectedThread',
'Invoke-ATHMSBuild',
'Invoke-ATHRemoteFXvGPUDisablementCommand',
'Out-ATHPowerShellCommandLineParameter',
'Start-ATHProcessHerpaderp',
'Start-ATHProcessUnderSpecificParent'


# 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 = @{
Expand All @@ -50,6 +52,11 @@ PrivateData = @{

# ReleaseNotes of this module
ReleaseNotes = @'
1.6.0
-----
Added:
* Invoke-ATHCorProfiler
1.5.0
-----
Added:
Expand Down
1 change: 1 addition & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Specific groups of tests can be run rather than running all available tests. The
9. `T1218.001` - [Signed Binary Proxy Execution: Compiled HTML File](https://attack.mitre.org/techniques/T1218/001/)
10. `T1218` - [Signed Binary Proxy Execution](https://attack.mitre.org/techniques/T1218/)
11. `T1218.005` - [Signed Binary Proxy Execution: Mshta](https://attack.mitre.org/techniques/T1218/005/)
12. `T1574.012` - [Hijack Execution Flow: COR_PROFILER](https://attack.mitre.org/techniques/T1574/012/)

## Running Tests

Expand Down
197 changes: 197 additions & 0 deletions TestHarnesses/T1574.012_COR_PROFILER/LoadCORProfiler.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
Set-StrictMode -Version Latest

$TestScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
$ModuleRoot = Resolve-Path "$TestScriptRoot\..\..\"
$ModuleManifest = "$ModuleRoot\AtomicTestHarnesses.psd1"

Remove-Module [A]tomicTestHarnesses
Import-Module $ModuleManifest -Force -ErrorAction Stop

Describe 'Invoke-ATHCORProfiler' {
BeforeAll {
$Help = Get-Help -Name Invoke-ATHCORProfiler -Full

$ExpectedTechniqueID = $null

if ($Help.Synopsis.Split("`r`n")[-1] -match '^(?-i:Technique ID: )(?<TechniqueID>\S+) (?<TechniqueDescription>\(.+\))$') {
$ExpectedTechniqueID = $Matches['TechniqueID']
}
}

Context 'Validating error conditions' -Tag 'Unit', 'T1574.012' {
It 'should not accept malformed test guids' -Tag 'Unit', 'T1574.012' {
$BogusTestGuid = 'asdfasdfasdfasdfasdfaasdf'

{ Invoke-ATHCORProfiler -TestGuid $BogusTestGuid } | Should -Throw
}

It 'should not accept malformed Profiler CLSIDs with registered profilers' -Tag 'Unit', 'T1574.012' {
$BogusProfilerCLSID = 'asdfasdfasdfasdfasdfasdf'

{ Invoke-ATHCORProfiler -RegisteredProfilerScope User -ProfilerCLSID $BogusProfilerCLSID } | Should -Throw
}

It 'should not accept process scoped registered profilers' -Tag 'Unit', 'T1574.012' {
{ Invoke-ATHCORProfiler -RegisteredProfilerScope Process } | Should -Throw
}

It 'should not accept a profiler path in a non-existant directory' -Tag 'Unit', 'T1574.012' {
$BogusPath = 'C:\dsdfsiuhsdrfsawgfds\sdlfksdjflksdj'

Test-Path -Path $BogusPath -PathType Container -ErrorAction SilentlyContinue | Should -BeFalse

{ Invoke-ATHCORProfiler -ProfilerPath $BogusPath -ErrorAction Stop } | Should -Throw
}
}

Context 'Expected artifacts and behaviors when exercising the attack technique' -Tag 'Technique', 'T1574.012' {
BeforeAll {
$FixedTestGuid = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
}

It 'should execute without any arguments' -Tag 'Technique', 'T1574.012' {
$Result = Invoke-ATHCORProfiler -Force

$Result | Should -Not -BeNullOrEmpty

$Result.TechniqueID | Should -BeExactly $ExpectedTechniqueID
$Result.TestSuccess | Should -BeTrue
$Result.TestGuid | Should -Not -BeNullOrEmpty
$Result.ProfilerScope | Should -BeExactly 'User'
$Result.ProfilerType | Should -BeExactly 'RegistrationFree'
$Result.ProfilerCLSID | Should -Not -BeNullOrEmpty
$Result.ProfilerDllPath | Should -Match 'Profiler.dll'
$Result.ProfilerDllFileSHA256Hash | Should -Not -BeNullOrEmpty
$Result.TargetProcessId | Should -Not -BeNullOrEmpty
$Result.TargetProcessPath | Should -Match 'powershell.exe'
$Result.TargetProcessCommandLine | Should -Match 'powershell.exe'
$Result.ChildProcessId | Should -Not -BeNullOrEmpty
$Result.ChildProcessCommandLine | Should -Not -BeNullOrEmpty
$Result.RegisteredProfilerRegistryCOMClassValueName | Should -BeNullOrEmpty
$Result.RegisteredProfilerRegistryCOMClassNameValue | Should -BeNullOrEmpty
$Result.CorEnableProfilingEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorEnableProfilingEnvVarRegistryValueName | Should -BeExactly 'COR_ENABLE_PROFILING'
$Result.CorEnableProfilingEnvVarRegistryNameValue | Should -BeExactly 1
$Result.CorProfilerEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorProfilerEnvVarRegistryValueName | Should -BeExactly 'COR_PROFILER'
$Result.CorProfilerEnvVarRegistryNameValue | Should -BeExactly $Result.ProfilerCLSID
$Result.CorProfilerPathEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorProfilerPathEnvVarRegistryValueName | Should -BeExactly 'COR_PROFILER_PATH'
$Result.CorProfilerPathEnvVarRegistryNameValue | Should -Match 'Profiler.dll'

$Result
}

It 'should simulate registered execution ( RegisteredProfilerScope: <RegisteredProfilerScope>)' {
if (($RegisteredProfilerScope -eq 'Machine') -and (-not (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) {
Set-ItResult -Skipped -Because 'This test requires an elevated instance of PowerShell.'
} else {
$Result = Invoke-ATHCORProfiler -RegisteredProfilerScope $RegisteredProfilerScope -ProfilerCLSID $FixedTestGuid -Force -TestGuid $FixedTestGuid
$Result | Should -Not -BeNullOrEmpty

$Result.TechniqueID | Should -BeExactly $ExpectedTechniqueID
$Result.TestSuccess | Should -BeTrue
$Result.TestGuid | Should -BeExactly $FixedTestGuid
$Result.ProfilerScope | Should -BeExactly $RegisteredProfilerScope
$Result.ProfilerType | Should -BeExactly 'Registered'
$Result.ProfilerCLSID | Should -BeExactly "{$FixedTestGuid}"
$Result.ProfilerDllPath | Should -Match 'Profiler.dll'
$Result.ProfilerDllFileSHA256Hash | Should -Not -BeNullOrEmpty
$Result.TargetProcessId | Should -Not -BeNullOrEmpty
$Result.TargetProcessPath | Should -Match 'powershell.exe'
$Result.TargetProcessCommandLine | Should -Match 'powershell.exe'
$Result.ChildProcessId | Should -Not -BeNullOrEmpty
$Result.ChildProcessCommandLine | Should -Not -BeNullOrEmpty
$Result.RegisteredProfilerRegistryCOMClassValueName.EndsWith('InprocServer32') | Should -BeTrue
$Result.RegisteredProfilerRegistryCOMClassNameValue.EndsWith('Profiler.dll') | Should -BeTrue
$Result.CorEnableProfilingEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorEnableProfilingEnvVarRegistryValueName | Should -BeExactly 'COR_ENABLE_PROFILING'
$Result.CorEnableProfilingEnvVarRegistryNameValue | Should -BeExactly 1
$Result.CorProfilerEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorProfilerEnvVarRegistryValueName | Should -BeExactly 'COR_PROFILER'
$Result.CorProfilerEnvVarRegistryNameValue | Should -BeExactly "{$FixedTestGuid}"
$Result.CorProfilerPathEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorProfilerPathEnvVarRegistryValueName | Should -BeExactly 'COR_PROFILER_PATH'
$Result.CorProfilerPathEnvVarRegistryNameValue | Should -Match 'Profiler.dll'

$Result
}
} -TestCases @(
@{ RegisteredProfilerScope = 'Machine' },
@{ RegisteredProfilerScope = 'User' }
)

It 'should simulate registration free execution which produce environment variable artifacts in the registry (RegistrationFreeProfilerScope: <RegistrationFreeProfilerScope>)' {
if (($RegistrationFreeProfilerScope -eq 'Machine') -and (-not (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) {
Set-ItResult -Skipped -Because 'This test requires an elevated instance of PowerShell.'
} else {
$Result = Invoke-ATHCORProfiler -RegistrationFreeProfilerScope $RegistrationFreeProfilerScope -ProfilerCLSID $FixedTestGuid -Force -TestGuid $FixedTestGuid
$Result | Should -Not -BeNullOrEmpty

$Result.TechniqueID | Should -BeExactly $ExpectedTechniqueID
$Result.TestSuccess | Should -BeTrue
$Result.TestGuid | Should -BeExactly $FixedTestGuid
$Result.ProfilerScope | Should -BeExactly $RegistrationFreeProfilerScope
$Result.ProfilerType | Should -BeExactly 'RegistrationFree'
$Result.ProfilerCLSID | Should -BeExactly "{$FixedTestGuid}"
$Result.ProfilerDllPath | Should -Match 'Profiler.dll'
$Result.ProfilerDllFileSHA256Hash | Should -Not -BeNullOrEmpty
$Result.TargetProcessId | Should -Not -BeNullOrEmpty
$Result.TargetProcessPath | Should -Match 'powershell.exe'
$Result.TargetProcessCommandLine | Should -Match 'powershell.exe'
$Result.ChildProcessId | Should -Not -BeNullOrEmpty
$Result.ChildProcessCommandLine | Should -Not -BeNullOrEmpty
$Result.RegisteredProfilerRegistryCOMClassValueName | Should -BeNullOrEmpty
$Result.RegisteredProfilerRegistryCOMClassNameValue | Should -BeNullOrEmpty
$Result.CorEnableProfilingEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorEnableProfilingEnvVarRegistryValueName | Should -BeExactly 'COR_ENABLE_PROFILING'
$Result.CorEnableProfilingEnvVarRegistryNameValue | Should -BeExactly 1
$Result.CorProfilerEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorProfilerEnvVarRegistryValueName | Should -BeExactly 'COR_PROFILER'
$Result.CorProfilerEnvVarRegistryNameValue | Should -BeExactly "{$FixedTestGuid}"
$Result.CorProfilerPathEnvVarRegistrySubKey.EndsWith('Environment') | Should -BeTrue
$Result.CorProfilerPathEnvVarRegistryValueName | Should -BeExactly 'COR_PROFILER_PATH'
$Result.CorProfilerPathEnvVarRegistryNameValue | Should -Match 'Profiler.dll'

$Result
}
} -TestCases @(
@{ RegistrationFreeProfilerScope = 'Machine' },
@{ RegistrationFreeProfilerScope = 'User' }
)

It 'should simulate registration free Process scoped execution (RegistrationFreeProfilerScope: <RegistrationFreeProfilerScope>)' {
$Result = Invoke-ATHCORProfiler -RegistrationFreeProfilerScope $RegistrationFreeProfilerScope -ProfilerCLSID $FixedTestGuid -Force -TestGuid $FixedTestGuid
$Result | Should -Not -BeNullOrEmpty

$Result.TechniqueID | Should -BeExactly $ExpectedTechniqueID
$Result.TestSuccess | Should -BeTrue
$Result.TestGuid | Should -BeExactly $FixedTestGuid
$Result.ProfilerScope | Should -BeExactly $RegistrationFreeProfilerScope
$Result.ProfilerType | Should -BeExactly 'RegistrationFree'
$Result.ProfilerCLSID | Should -BeExactly "{$FixedTestGuid}"
$Result.ProfilerDllPath | Should -Match 'Profiler.dll'
$Result.ProfilerDllFileSHA256Hash | Should -Not -BeNullOrEmpty
$Result.TargetProcessId | Should -Not -BeNullOrEmpty
$Result.TargetProcessPath | Should -Match 'powershell.exe'
$Result.TargetProcessCommandLine | Should -Match 'powershell.exe'
$Result.ChildProcessId | Should -Not -BeNullOrEmpty
$Result.ChildProcessCommandLine | Should -Not -BeNullOrEmpty
$Result.RegisteredProfilerRegistryCOMClassValueName | Should -BeNullOrEmpty
$Result.RegisteredProfilerRegistryCOMClassNameValue | Should -BeNullOrEmpty
$Result.CorEnableProfilingEnvVarRegistrySubKey | Should -BeNullOrEmpty
$Result.CorEnableProfilingEnvVarRegistryValueName | Should -BeNullOrEmpty
$Result.CorEnableProfilingEnvVarRegistryNameValue | Should -BeNullOrEmpty
$Result.CorProfilerEnvVarRegistrySubKey | Should -BeNullOrEmpty
$Result.CorProfilerEnvVarRegistryValueName | Should -BeNullOrEmpty
$Result.CorProfilerEnvVarRegistryNameValue | Should -BeNullOrEmpty
$Result.CorProfilerPathEnvVarRegistrySubKey | Should -BeNullOrEmpty
$Result.CorProfilerPathEnvVarRegistryValueName | Should -BeNullOrEmpty
$Result.CorProfilerPathEnvVarRegistryNameValue | Should -BeNullOrEmpty

$Result
} -TestCases @(
@{ RegistrationFreeProfilerScope = 'Process' }
)
}
}
Loading

0 comments on commit 560cd82

Please sign in to comment.