Tests/Recon.tests.ps1
$TestScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent $ModuleRoot = Resolve-Path "$TestScriptRoot\.." $ModuleManifest = "$ModuleRoot\Recon\Recon.psd1" Remove-Module [R]econ Import-Module $ModuleManifest -Force -ErrorAction Stop # import PowerView.ps1 manually so we expose the helper functions for testing $PowerViewFile = "$ModuleRoot\Recon\PowerView.ps1" Import-Module $PowerViewFile -Force -ErrorAction Stop # Get the local IP address for later testing $IPregex = "(?<Address>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))" $LocalIP = (gwmi Win32_NetworkAdapterConfiguration | ? { $_.IPAddress -match $IPregex}).ipaddress[0] ######################################################## # # PowerView functions. # ######################################################## Describe 'Export-PowerViewCSV' { It 'Should Not Throw and should produce .csv output.' { {Get-Process | Export-PowerViewCSV -OutFile process_test.csv} | Should Not Throw '.\process_test.csv' | Should Exist Remove-Item -Force .\process_test.csv } } Describe 'Set-MacAttribute' { BeforeEach { New-Item MacAttribute.test.txt -Type file } AfterEach { Remove-Item -Force MacAttribute.test.txt } It 'Should clone MAC attributes of existing file' { Set-MacAttribute -FilePath MacAttribute.test.txt -All '01/01/2000 12:00 am' $File = (Get-Item MacAttribute.test.txt) $Date = Get-Date -Date '2000-01-01 00:00:00' if ($File.LastWriteTime -ne $Date) { Throw 'File LastWriteTime does Not match' } elseif($File.LastAccessTime -ne $Date) { Throw 'File LastAccessTime does Not match' } elseif($File.CreationTime -ne $Date) { Throw 'File CreationTime does Not match' } } } Describe 'Get-IPAddress' { $IPregex = "(?<Address>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))" It 'Should return local IP address' { if( $(Get-IPAddress) -notmatch $IPRegex ) { Throw 'Invalid local IP address returned' } } It 'Should accept -ComputerName argument' { if( $(Get-IPAddress -ComputerName $env:COMPUTERNAME) -notmatch $IPRegex ) { Throw 'Invalid -ComputerName IP address returned' } } } Describe 'Convert-SidToName' { It 'Should resolve built in SIDs' { Convert-SidToName -SID 'S-1-5-32-545' | Should Be 'BUILTIN\Users' } It 'Should accept pipeline input' { 'S-1-5-32-552' | Convert-SidToName | Should Be 'BUILTIN\Replicators' } It 'Should return a unresolvable SID' { Convert-SidToName -SID 'S-1-5-32-1337' | Should Be 'S-1-5-32-1337' } } Describe 'Get-Proxy' { It 'Should Not Throw' { {Get-Proxy} | Should Not Throw } It 'Should accept -ComputerName argument' { {Get-Proxy -ComputerName $env:COMPUTERNAME} | Should Not Throw } } Describe 'Get-PathAcl' { It 'Should Not Throw' { {Get-PathAcl C:\} | Should Not Throw } It 'Should return correct ACLs' { $Output = Get-PathAcl -Path C:\Windows | ?{$_.IdentityReference -eq "Creator Owner"} if(-not $Output) { Throw "Output Not returned" } if($Output.FileSystemRights -ne 'GenericAll') { Throw "Incorrect FileSystemRights returned" } } } Describe 'Get-NameField' { It 'Should extract dnshostname field from custom object' { $Object = New-Object -TypeName PSObject -Property @{'dnshostname' = 'testing1'} if ( (Get-NameField -Object $Object) -ne 'testing1') { Throw "'dnshostname' field Not parsed correctly" } } It 'Should extract name field from custom object' { $Object = New-Object -TypeName PSObject -Property @{'name' = 'testing2'} if ( (Get-NameField -Object $Object) -ne 'testing2') { Throw "'name' field Not parsed correctly" } } It 'Should handle plaintext strings' { if ( (Get-NameField -Object 'testing3') -ne 'testing3') { Throw 'Plaintext string Not parsed correctly' } } It 'Should accept pipeline input' { $Object = New-Object -TypeName PSObject -Property @{'dnshostname' = 'testing4'} if ( ($Object | Get-NameField) -ne 'testing4') { Throw 'Pipeline input Not processed correctly' } } } Describe 'Invoke-ThreadedFunction' { It "Should allow threaded ping" { $Hosts = ,"localhost" * 100 $Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}} $Hosts = Invoke-ThreadedFunction -NoImports -ComputerName $Hosts -ScriptBlock $Ping -Threads 20 if($Hosts.length -ne 100) { Throw 'Error in using Invoke-ThreadedFunction to ping localhost' } } } Describe "Get-NetLocalGroup" { It "Should return results for local machine administrators" { if ( (Get-NetLocalGroup | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } It "Should return results for listing local groups" { if ( (Get-NetLocalGroup -ListGroups | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } # TODO: -ComputerList It "Should accept -GroupName argument" { {Get-NetLocalGroup -GroupName "Remote Desktop Users"} | Should Not Throw } It "Should accept NETBIOS -ComputerName argument" { if ( (Get-NetLocalGroup -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } It "Should accept IP -ComputerName argument" { if ( (Get-NetLocalGroup -ComputerName $LocalIP | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } It "Should accept pipeline input" { if ( ( "$env:computername" | Get-NetLocalGroup | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } } Describe "Get-NetShare" { It "Should return results for the local host" { if ( (Get-NetShare | Measure-Object).count -lt 1) { Throw "Incorrect share results returned" } } It "Should accept NETBIOS -ComputerName argument" { if ( (Get-NetShare -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } It "Should accept IP -ComputerName argument" { if ( (Get-NetShare -ComputerName $LocalIP | Measure-Object).count -lt 1) { Throw "Incorrect share results returned" } } It "Should accept pipeline input" { if ( ( "$env:computername" | Get-NetShare | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } } Describe "Get-NetLoggedon" { It "Should return results for the local host" { if ( (Get-NetLoggedon | Measure-Object).count -lt 1) { Throw "Incorrect loggedon results returned" } } It "Should accept NETBIOS -ComputerName argument" { if ( (Get-NetLoggedon -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Incorrect loggedon results returned" } } It "Should accept IP -ComputerName argument" { if ( (Get-NetLoggedon -ComputerName $LocalIP | Measure-Object).count -lt 1) { Throw "Incorrect loggedon results returned" } } It "Should accept pipeline input" { if ( ( "$env:computername" | Get-NetLoggedon | Measure-Object).count -lt 1) { Throw "Incorrect local administrators returned" } } } Describe "Get-NetSession" { It "Should return results for the local host" { if ( (Get-NetSession | Measure-Object).count -lt 1) { Throw "Incorrect session results returned" } } It "Should accept NETBIOS -ComputerName argument" { if ( (Get-NetSession -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Incorrect session results returned" } } It "Should accept IP -ComputerName argument" { if ( (Get-NetSession -ComputerName $LocalIP | Measure-Object).count -lt 1) { Throw "Incorrect session results returned" } } It "Should accept the -UserName argument" { {Get-NetSession -UserName 'Administrator'} | Should Not Throw } It "Should accept pipeline input" { {"$env:computername" | Get-NetSession} | Should Not Throw } } Describe "Get-NetRDPSession" { It "Should return results for the local host" { if ( (Get-NetRDPSession | Measure-Object).count -lt 1) { Throw "Incorrect session results returned" } } It "Should accept NETBIOS -ComputerName argument" { if ( (Get-NetRDPSession -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Incorrect session results returned" } } It "Should accept IP -ComputerName argument" { if ( (Get-NetRDPSession -ComputerName $LocalIP | Measure-Object).count -lt 1) { Throw "Incorrect session results returned" } } It "Should accept pipeline input" { {"$env:computername" | Get-NetRDPSession} | Should Not Throw } } Describe "Invoke-CheckLocalAdminAccess" { It "Should Not Throw for localhost" { {Invoke-CheckLocalAdminAccess} | Should Not Throw } It "Should accept NETBIOS -ComputerName argument" { {Invoke-CheckLocalAdminAccess -ComputerName "$env:computername"} | Should Not Throw } It "Should accept IP -ComputerName argument" { {Invoke-CheckLocalAdminAccess -ComputerName $LocalIP} | Should Not Throw } It "Should accept pipeline input" { {"$env:computername" | Invoke-CheckLocalAdminAccess} | Should Not Throw } } Describe "Get-LastLoggedOn" { It "Should return results for the local host" { if ( (Get-LastLoggedOn | Measure-Object).count -lt 1) { Throw "Incorrect loggedon results returned" } } It "Should accept NETBIOS -ComputerName argument" { if ( (Get-LastLoggedOn -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Incorrect loggedon results returned" } } It "Should accept IP -ComputerName argument" { if ( (Get-LastLoggedOn -ComputerName $LocalIP | Measure-Object).count -lt 1) { Throw "Incorrect loggedon results returned" } } It "Should accept pipeline input" { {"$env:computername" | Get-LastLoggedOn} | Should Not Throw } } Describe "Get-CachedRDPConnection" { It "Should Not Throw" { {Get-CachedRDPConnection} | Should Not Throw } It "Should accept NETBIOS -ComputerName argument" { {Get-CachedRDPConnection -ComputerName "$env:computername"} | Should Not Throw } It "Should accept IP -ComputerName argument" { {Get-CachedRDPConnection -ComputerName $LocalIP} | Should Not Throw } It "Should accept pipeline input" { {"$env:computername" | Get-CachedRDPConnection} | Should Not Throw } } Describe "Get-NetProcess" { It "Should return results for the local host" { if ( (Get-NetProcess | Measure-Object).count -lt 1) { Throw "Incorrect process results returned" } } It "Should accept NETBIOS -ComputerName argument" { if ( (Get-NetProcess -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Incorrect process results returned" } } It "Should accept IP -ComputerName argument" { if ( (Get-NetProcess -ComputerName $LocalIP | Measure-Object).count -lt 1) { Throw "Incorrect process results returned" } } # TODO: RemoteUserName/RemotePassword It "Should accept pipeline input" { {"$env:computername" | Get-NetProcess} | Should Not Throw } } Describe "Find-InterestingFile" { #TODO: implement } Describe "Invoke-UserHunter" { It "Should accept -ComputerName argument" { if ( (Invoke-UserHunter -ShowAll -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } try { It "Should accept -ComputerFile argument" { "$env:computername","$env:computername" | Out-File -Encoding ASCII targets.txt if ( (Invoke-UserHunter -ComputerFile ".\targets.txt" -ShowAll | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } finally { Remove-Item -Force ".\targets.txt" } It "Should accept -NoPing flag" { if ( (Invoke-UserHunter -ComputerName "$env:computername" -UserName $env:USERNAME -NoPing | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -Delay and -Jitter arguments" { if ( (Invoke-UserHunter -ShowAll -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername", "$env:computername") | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } Describe "Invoke-StealthUserHunter" { # simple test of the splatting It "Should accept splatting for Invoke-UserHunter" { {Invoke-StealthUserHunter -ShowAll -ComputerName "$env:computername"} | Should Not Throw } } Describe "Invoke-ProcessHunter" { It "Should accept -ComputerName and -UserName arguments" { if ( (Invoke-ProcessHunter -UserName $env:USERNAME -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } try { It "Should accept -ComputerFile argument" { "$env:computername","$env:computername" | Out-File -Encoding ASCII targets.txt if ( (Invoke-ProcessHunter -ComputerFile ".\targets.txt" -UserName $env:USERNAME | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } finally { Remove-Item -Force ".\targets.txt" } It "Should accept -ProcessName argument" { if ( (Invoke-ProcessHunter -ComputerName "$env:computername" -ProcessName powershell | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } try { It "Should accept -UserFile argument" { "$env:USERNAME" | Out-File -Encoding ASCII target_users.txt if ( (Invoke-ProcessHunter -ComputerName "$env:computername" -UserFile ".\target_users.txt" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } finally { Remove-Item -Force ".\target_users.txt" } It "Should accept -NoPing flag" { if ( (Invoke-ProcessHunter -ComputerName "$env:computername" -UserName $env:USERNAME -NoPing | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -Delay and -Jitter arguments" { if ( (Invoke-ProcessHunter -UserName $env:USERNAME -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername", "$env:computername") | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } Describe "Invoke-ShareFinder" { It "Should accept -ComputerName argument" { if ( (Invoke-ShareFinder -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } try { It "Should accept -ComputerFile argument" { "$env:computername","$env:computername" | Out-File -Encoding ASCII targets.txt if ( (Invoke-ShareFinder -ComputerFile ".\targets.txt" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } finally { Remove-Item -Force ".\targets.txt" } It "Should accept -ExcludeStandard argument" { {Invoke-ShareFinder -ComputerName "$env:computername" -ExcludeStandard} | Should Not Throw } It "Should accept -ExcludePrint argument" { if ( (Invoke-ShareFinder -ComputerName "$env:computername" -ExcludePrint | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -ExcludeIPC argument" { if ( (Invoke-ShareFinder -ComputerName "$env:computername" -ExcludeIPC | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -CheckShareAccess argument" { if ( (Invoke-ShareFinder -ComputerName "$env:computername" -CheckShareAccess | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -CheckAdmin argument" { if ( (Invoke-ShareFinder -ComputerName "$env:computername" -CheckAdmin | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -NoPing argument" { if ( (Invoke-ShareFinder -NoPing -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -Delay and -Jitter arguments" { if ( (Invoke-ShareFinder -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername", "$env:computername") | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } Describe "Invoke-FileFinder" { It "Should accept -ComputerName argument" { {Invoke-FileFinder -ComputerName "$env:computername"} | Should Not Throw } try { It "Should accept -ComputerFile argument" { "$env:computername","$env:computername" | Out-File -Encoding ASCII targets.txt {Invoke-FileFinder -ComputerFile ".\targets.txt"} | Should Not Throw } } finally { Remove-Item -Force ".\targets.txt" } try { It "Should accept -ShareList argument" { "\\$($env:computername)\\IPC$" | Out-File -Encoding ASCII shares.txt {Invoke-FileFinder -ShareList ".\shares.txt"} | Should Not Throw } } finally { Remove-Item -Force ".\shares.txt" } It "Should accept -Terms argument" { {Invoke-FileFinder -Terms secret,testing -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -OfficeDocs argument" { {Invoke-FileFinder -OfficeDocs -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -FreshEXEs argument" { {Invoke-FileFinder -FreshEXEs -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -LastAccessTime argument" { {Invoke-FileFinder -LastAccessTime "01/01/2000" -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -LastWriteTime argument" { {Invoke-FileFinder -LastWriteTime "01/01/2000" -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -ExcludeFolders argument" { {Invoke-FileFinder -ExcludeFolders -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -ExcludeHidden argument" { {Invoke-FileFinder -ExcludeHidden -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -CreationTime argument" { {Invoke-FileFinder -CreationTime "01/01/2000" -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -OutFile argument" { {Invoke-FileFinder -ComputerName "$env:computername" -OutFile "found_files.csv"} | Should Not Throw if(Test-Path -Path .\found_files.csv) { $Null = Remove-Item -Force .\found_files.csv } } It "Should accept -NoPing argument" { {Invoke-FileFinder -NoPing -ComputerName "$env:computername"} | Should Not Throw } It "Should accept -Delay and -Jitter arguments" { {Invoke-FileFinder -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername","$env:computername")} | Should Not Throw } } Describe "Find-LocalAdminAccess" { It "Should accept -ComputerName argument" { if ( (Find-LocalAdminAccess -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } try { It "Should accept -ComputerFile argument" { "$env:computername","$env:computername" | Out-File -Encoding ASCII targets.txt if ( (Find-LocalAdminAccess -ComputerFile ".\targets.txt" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } finally { Remove-Item -Force ".\targets.txt" } It "Should accept -NoPing argument" { if ( (Find-LocalAdminAccess -NoPing -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -Delay and -Jitter arguments" { if ( (Find-LocalAdminAccess -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername","$env:computername") | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } Describe "Invoke-EnumerateLocalAdmin" { It "Should accept -ComputerName argument" { if ( (Invoke-EnumerateLocalAdmin -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } try { It "Should accept -ComputerFile argument" { "$env:computername","$env:computername" | Out-File -Encoding ASCII targets.txt if ( (Invoke-EnumerateLocalAdmin -ComputerFile ".\targets.txt" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } } finally { Remove-Item -Force ".\targets.txt" } It "Should accept -NoPing argument" { if ( (Invoke-EnumerateLocalAdmin -NoPing -ComputerName "$env:computername" | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -Delay and -Jitter arguments" { if ( (Invoke-EnumerateLocalAdmin -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername","$env:computername") | Measure-Object).count -lt 1) { Throw "Insuffient results returned" } } It "Should accept -Outfile argument" { Invoke-EnumerateLocalAdmin -ComputerName "$env:computername" -OutFile "local_admins.csv" ".\local_admins.csv" | Should Exist Remove-Item -Force .\local_admins.csv } } |