diff options
Diffstat (limited to 'Tests')
| -rw-r--r-- | Tests/Exfiltration.tests.ps1 | 54 | ||||
| -rw-r--r-- | Tests/Privesc.tests.ps1 | 261 | 
2 files changed, 315 insertions, 0 deletions
| diff --git a/Tests/Exfiltration.tests.ps1 b/Tests/Exfiltration.tests.ps1 new file mode 100644 index 0000000..e4f60d5 --- /dev/null +++ b/Tests/Exfiltration.tests.ps1 @@ -0,0 +1,54 @@ +Set-StrictMode -Version Latest + +$TestScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +$ModuleRoot = Resolve-Path "$TestScriptRoot\.." +$ModuleManifest = "$ModuleRoot\Exfiltration\Exfiltration.psd1" + +Remove-Module [E]xfiltration +Import-Module $ModuleManifest -Force -ErrorAction Stop + +Describe 'Get-Keystrokes' { +     +    if (Test-Path "$($env:TEMP)\key.log") { Remove-Item -Force "$($env:TEMP)\key.log" } +    $WindowTitle = (Get-Process -Id $PID).MainWindowTitle +     +    $Shell = New-Object -ComObject wscript.shell +    $Shell.AppActivate($WindowTitle) +     +    $KeyLogger = Get-Keystrokes -PassThru +    Start-Sleep -Seconds 1 + +    $Shell.SendKeys("Pester`b`b`b`b`b`b") +    $KeyLogger.Dispose() + +    It 'Should output to file' { Test-Path "$($env:TEMP)\key.log" | Should Be $true } +     +    $KeyObjects = Get-Content -Path "$($env:TEMP)\key.log" | ConvertFrom-Csv + +    It 'Should log keystrokes' { +        $FileLength = (Get-Item "$($env:TEMP)\key.log").Length +        $FileLength | Should BeGreaterThan 14 +    } + +    It 'Should get foreground window title' { +        $KeyObjects[0].WindowTitle | Should Be $WindowTitle +    } + +    It 'Should log time of key press' { +        $KeyTime = [DateTime]::Parse($KeyObjects[0].Time) +        $KeyTime.GetType().Name | Should Be 'DateTime' +    } + +    It 'Should stop logging after timeout' { +         +        $Timeout = 0.05 +        $KeyLogger = Get-Keystrokes -Timeout $Timeout -PassThru +         +        Start-Sleep -Seconds 4 + +        $KeyLogger.Runspace.RunspaceAvailability | Should Be 'Available' +        $KeyLogger.Dispose() +    } + +    Remove-Item -Force "$($env:TEMP)\key.log" +} diff --git a/Tests/Privesc.tests.ps1 b/Tests/Privesc.tests.ps1 index 095c946..999d712 100644 --- a/Tests/Privesc.tests.ps1 +++ b/Tests/Privesc.tests.ps1 @@ -74,6 +74,137 @@ Describe 'Get-ModifiableFile' {      }  } +Describe 'Test-ServiceDaclPermission' { + +    if(-not $(Test-IsAdmin)) {  +        Throw "'Test-ServiceDaclPermission' Pester test needs local administrator privileges." +    } +     +    It "Should fail finding 'sc.exe'." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        $DirectoryName = Get-RandomName +        $env:SystemRoot = 'C:\\' + $DirectoryName +        { Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' } | Should Throw "sc.exe not found" +         +        sc.exe delete $ServiceName | Should Match "SUCCESS" +        $env:SystemRoot = 'C:\Windows' +    } +     +    It "Should succeed finding 'sc.exe'." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        $DirectoryName = Get-RandomName +        New-Item -Path $env:Temp -Name "$DirectoryName\System32" -ItemType Directory +        New-Item -Path $env:Temp -Name "$DirectoryName\System32\sc.exe" -ItemType File +        $env:SystemRoot = $env:Temp + "\$DirectoryName" +        Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' | Should Be $True +         +        Remove-Item -Recurse -Force "$env:Temp\$DirectoryName" +        $env:SystemRoot = 'C:\Windows' +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    } +     +    It "Should fail querying WMI for a non-existent service." { +        $ServiceName = Get-RandomName +        { Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' } | Should Throw "not found on the machine" +    } +     +    It "Should succeed querying WMI for an existenting service." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' | Should Be $True +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    } +     +    It "Should fail querying WMI for an existing service due to insufficient DACL permissions." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +        $UserSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.value +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        sc.exe sdset $ServiceName "D:(A;;CCDCSWRPWPDTLOCRSDRCWDWO;;;$UserSid)" | Should Match "SUCCESS" +        { Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' } | Should Throw "not found on the machine" +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    } +     +    It "Should succeed querying WMI for an existing service due to sufficient DACL permissions." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +        $UserSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.value +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        sc.exe sdset $ServiceName "D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$UserSid)" | Should Match "SUCCESS" +        Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' | Should Be $True +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    }  +     +    It "Should fail running 'sc.exe sdshow' due to insufficient permissions." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +        $UserSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.value +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        sc.exe sdset $ServiceName "D:(A;;CCDCLCSWRPWPDTLOCRSDWDWO;;;$UserSid)" | Should Match "SUCCESS" +        { Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' } | Should Throw "Could not retrieve DACL permissions" +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    } +     +    It "Should succeed running 'sc.exe sdshow' due to sufficient permissions." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +        $UserSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.value +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        sc.exe sdset $ServiceName "D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$UserSid)" | Should Match "SUCCESS" +        Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'DC' | Should Be $True +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    } +     +    it "Should fail finding the service DACL value of 'WP' for the current user." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        sc.exe sdset $ServiceName "D:(A;;CCDCLCSWRPDTLOCRSDRCWDWO;;;S-1-5-4)" | Should Match "SUCCESS" +        Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'WP' | Should Be $False +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    } +     +    it "Should succeed finding the service DACL value of 'WP' for the current user." { +        $ServiceName = Get-RandomName +        $ServicePath = "C:\Program Files\service.exe" +         +        sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" +        Start-Sleep -Seconds 1 +         +        sc.exe sdset $ServiceName "D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-4)" | Should Match "SUCCESS" +        Test-ServiceDaclPermission -ServiceName $ServiceName -Dacl 'WP' | Should Be $True +        sc.exe delete $ServiceName | Should Match "SUCCESS" +    } +}  ########################################################  # @@ -568,3 +699,133 @@ Describe 'Invoke-AllChecks' {          $Null = Remove-Item -Path $HtmlReportFile -Force -ErrorAction SilentlyContinue      }  } + +Describe 'Get-SiteListPassword' { +    BeforeEach { +        $Xml = '<?xml version="1.0" encoding="UTF-8"?><ns:SiteLists xmlns:ns="naSiteList" Type="Client"><SiteList Default="1" Name="SomeGUID"><HttpSite Type="fallback" Name="McAfeeHttp" Order="26" Enabled="1" Local="0" Server="update.nai.com:80"><RelativePath>Products/CommonUpdater</RelativePath><UseAuth>0</UseAuth><UserName></UserName><Password Encrypted="1">jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q==</Password></HttpSite><UNCSite Type="repository" Name="Paris" Order="13" Server="paris001" Enabled="1" Local="0"><ShareName>Repository$</ShareName><RelativePath></RelativePath><UseLoggedonUserAccount>0</UseLoggedonUserAccount><DomainName>companydomain</DomainName><UserName>McAfeeService</UserName><Password Encrypted="0">Password123!</Password></UNCSite><UNCSite Type="repository" Name="Tokyo" Order="18" Server="tokyo000" Enabled="1" Local="0"><ShareName>Repository$</ShareName><RelativePath></RelativePath><UseLoggedonUserAccount>0</UseLoggedonUserAccount><DomainName>companydomain</DomainName><UserName>McAfeeService</UserName><Password Encrypted="1">jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q==</Password></UNCSite></SiteList></ns:SiteLists>' +        $Xml | Out-File -FilePath "${Home}\SiteList.xml" -Force +    } +    AfterEach { +        Remove-Item -Force "${Home}\SiteList.xml" +    } + +    It 'Should correctly parse a SiteList.xml found in a searched path.' { + +        $Credentials = Get-SiteListPassword +         +        $Credentials | Where-Object {$_.Name -eq 'McAfeeHttp'} | ForEach-Object { +            # HTTP site +            $_.Enabled | Should Be '1' +            $_.Server | Should Be 'update.nai.com:80' +            $_.Path | Should Be 'Products/CommonUpdater' +            $_.EncPassword | Should Be 'jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q==' +            $_.DecPassword | Should Be 'MyStrongPassword!' +            $_.UserName | Should BeNullOrEmpty +            $_.DomainName | Should BeNullOrEmpty             +        }  +         + +        $Credentials | Where-Object {$_.Name -eq 'Paris'} | ForEach-Object { +            # UNC site with unencrypted password +            $_.Enabled | Should Be '1' +            $_.Server | Should Be 'paris001' +            $_.Path | Should Be 'Repository$' +            $_.EncPassword | Should Be 'Password123!' +            $_.DecPassword | Should Be 'Password123!' +            $_.UserName | Should Be 'McAfeeService' +            $_.DomainName | Should Be 'companydomain' +        } + +        $Credentials | Where-Object {$_.Name -eq 'Tokyo'} | ForEach-Object { +            # UNC site with encrypted password +            $_.Enabled | Should Be '1' +            $_.Server | Should Be 'tokyo000' +            $_.Path | Should Be 'Repository$' +            $_.EncPassword | Should Be 'jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q==' +            $_.DecPassword | Should Be 'MyStrongPassword!' +            $_.UserName | Should Be 'McAfeeService' +            $_.DomainName | Should Be 'companydomain' +        } +    } + +    It 'Should correctly parse a SiteList.xml on a searched path.' { +         +        $Credentials = Get-SiteListPassword -SiteListFilePath "${Home}\SiteList.xml" +         +        $Credentials | Where-Object {$_.Name -eq 'McAfeeHttp'} | ForEach-Object { +            # HTTP site +            $_.Enabled | Should Be '1' +            $_.Server | Should Be 'update.nai.com:80' +            $_.Path | Should Be 'Products/CommonUpdater' +            $_.EncPassword | Should Be 'jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q==' +            $_.DecPassword | Should Be 'MyStrongPassword!' +            $_.UserName | Should BeNullOrEmpty +            $_.DomainName | Should BeNullOrEmpty             +        }  +         + +        $Credentials | Where-Object {$_.Name -eq 'Paris'} | ForEach-Object { +            # UNC site with unencrypted password +            $_.Enabled | Should Be '1' +            $_.Server | Should Be 'paris001' +            $_.Path | Should Be 'Repository$' +            $_.EncPassword | Should Be 'Password123!' +            $_.DecPassword | Should Be 'Password123!' +            $_.UserName | Should Be 'McAfeeService' +            $_.DomainName | Should Be 'companydomain' +        } + +        $Credentials | Where-Object {$_.Name -eq 'Tokyo'} | ForEach-Object { +            # UNC site with encrypted password +            $_.Enabled | Should Be '1' +            $_.Server | Should Be 'tokyo000' +            $_.Path | Should Be 'Repository$' +            $_.EncPassword | Should Be 'jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q==' +            $_.DecPassword | Should Be 'MyStrongPassword!' +            $_.UserName | Should Be 'McAfeeService' +            $_.DomainName | Should Be 'companydomain' +        } +    } +} + + +Describe 'Get-System' { + +    if(-not $(Test-IsAdmin)) {  +        Throw "'Get-System' Pester test needs local administrator privileges." +    } + +    AfterEach { +        Get-System -RevToSelf +    } + +    It 'Should not throw with default parameters and should elevate to SYSTEM.' { +        { Get-System } | Should Not Throw +        "$([Environment]::UserName)" | Should Be 'SYSTEM' +    } + +    It 'Named pipe impersonation should accept an alternate service and pipe name.' { +        { Get-System -Technique NamedPipe -ServiceName 'testing123' -PipeName 'testpipe' } | Should Not Throw +        "$([Environment]::UserName)" | Should Be 'SYSTEM' +    } + +    It 'Should elevate to SYSTEM using token impersonation.' { +        { Get-System -Technique Token } | Should Not Throw +        "$([Environment]::UserName)" | Should Be 'SYSTEM' +    } + +    It '-WhoAmI should display the current user.' { +        { Get-System -Technique Token } | Should Not Throw +        { Get-System -WhoAmI } | Should Match 'SYSTEM' +    } + +    It 'RevToSelf should revert privileges.' { +        { Get-System -Technique Token } | Should Not Throw +        { Get-System -RevToSelf } | Should Not Throw +        "$([Environment]::UserName)" | Should Not Match 'SYSTEM' +    } + +    It 'Token impersonation should throw with incompatible parameters.' { +        { Get-System -Technique Token -WhoAmI } | Should Throw +    } +} |