diff --git a/PowerHuntShares.psm1 b/PowerHuntShares.psm1 index e653062..ed4e4c7 100644 --- a/PowerHuntShares.psm1 +++ b/PowerHuntShares.psm1 @@ -4,7 +4,7 @@ #-------------------------------------- # Author: Scott Sutherland, 2024 NetSPI # License: 3-clause BSD -# Version: v1.80 +# Version: v1.85 # References: This script includes custom code and code taken and modified from the open source projects PowerView, Invoke-Ping, and Invoke-Parrell. function Invoke-HuntSMBShares { @@ -165,7 +165,7 @@ function Invoke-HuntSMBShares [Parameter(Mandatory = $false, HelpMessage = 'Number of items to sample for summary report.')] - [int]$SampleSum = 5, + [int]$SampleSum = 200, [Parameter(Mandatory = $false, HelpMessage = 'Runspace time out.')] @@ -196,12 +196,8 @@ function Invoke-HuntSMBShares [int] $DirLevel = 3, [Parameter(Mandatory = $false, - HelpMessage = 'Search for common files containing passwords on the c$ shares.')] - [switch] $FindFiles, - - [Parameter(Mandatory = $false, - HelpMessage = 'Path to file of file paths to search for. One path per line.')] - [string] $FindFilesList, + HelpMessage = 'Path to interesting files template to import file keywords to search for.')] + [string] $FileKeywordsPath, [Parameter(Mandatory = $false, HelpMessage = 'Do not perform ping scan.')] @@ -267,6 +263,18 @@ function Invoke-HuntSMBShares break } + # Check for keyword file path + If($FileKeywordsPath){ + + if(Test-Path $FileKeywordsPath){ + #Write-Output " [x]The target directory exists." + }else{ + Write-Output " [x] The $FileKeywordsPath did not exist." + Write-Output " [!] Aborting operation." + break + } + } + # ---------------------------------------------------------------------- # Import computers from file # ---------------------------------------------------------------------- @@ -1445,7 +1453,395 @@ function Invoke-HuntSMBShares #Write-Output " [*][$Time] - Summary report data generated." #Write-Output " [*][$Time] - $Top5ShareCountTotal of $AllAccessibleSharesCount ($DupPercent) shares are associated with the top 5 share names." + # ---------------------------------------------------------------------- + # Create Interesting Files Table + # ---------------------------------------------------------------------- + Write-Output " [*][$Time] Finding interesting files..." + + # Define common image and other formats to filter out later + $ImageFormats = @("*.jpg", "*.jpeg", "*.png", "*.gif", "*.bmp", "*.ico", "*.svg", "*.webp", "*.mif", "*.heic", "*.msi") + + # Create data table to hold interesting file keywords + $FileNamePatternsAll = New-Object system.data.datatable + $FileNamePatternsAll.Columns.Add("Keyword") | Out-Null # Keyword + $FileNamePatternsAll.Columns.Add("Description") | Out-Null # Summary of keyword. + $FileNamePatternsAll.Columns.Add("Instructions") | Out-Null # Used to instruct testing how to attack match. + $FileNamePatternsAll.Columns.Add("Category") | Out-Null # File name category: Secret (password), sensitive (data), binaries, script, backup, database + $FileNamePatternsAll.Columns.Add("SampleRegex") | Out-Null # Used to parse sample data from file matches. + + # Add rows to data table - Sensitive data + $FileNamePatternsAll.Rows.Add("*credit*","Credit card number and/or PII.","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*pci*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*social*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*ssn*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("human*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("finance*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("Health*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("Billing*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("patient*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("HR*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*ftp*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*Program Files*","","None.","Sensitive","") | Out-Null + + # Add rows to data table - Files containing passwords + $FileNamePatternsAll.Rows.Add("context.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("db2cli.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("ftpd.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("ftpusers*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("httpd.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("hudson.security.HudsonPrivateSecurityRealm.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("jboss-cli.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("jboss-logmanager.properties*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("jenkins.model.JenkinsLocationConfiguration.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("machine.config*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("my.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("mysql.user*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("nginx.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*ntds.dit*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("pg_hba.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("php.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("putty.reg*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("postgresql.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM-*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM_*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SYSTEM","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("server.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("shadow*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("standalone.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("tnsnames.ora*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("tomcat-users.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("sitemanager.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("users.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmx*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmdk*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.nvram*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmsd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmsn*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmss*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmem*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vhd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vhdx*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.avhd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.avhdx*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vsv*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vbox*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vbox-prev*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vdi*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.hdd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sav*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pvm*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pvs*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.qcow*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.qcow2*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.img*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*vcenter*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*vault*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*DefaultAppPool*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*WinSCP.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.kdbx","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("wp-config.php*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.config","","None.","Secret","") | Out-Null + + # Add rows to data table - Database files + $FileNamePatternsAll.Rows.Add("*database*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sql*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sqlite*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.idf*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.mdf*","","None.","Database","") | Out-Null + + # Add rows to data table - Backup files + $FileNamePatternsAll.Rows.Add("*.bak*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.bkf*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*backup*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.tar*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.zip*","","None.","Backup","") | Out-Null + + # Add rows to data table - Scripts + $FileNamePatternsAll.Rows.Add("*.ps1*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.psm1*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.bat*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sh*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vbs*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.cmd*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.wsh*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.wsf*","","None.","Script","") | Out-Null + + # Add rows to data table - Binaries + $FileNamePatternsAll.Rows.Add("*.dll","","None.","Binaries","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.exe","","None.","Binaries","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.msi","","None.","Binaries","") | Out-Null + + # Use keyword from define file instead + if($FileKeywordsPath){ + $FileNamePatternsAllTest = import-csv "$FileKeywordsPath" + $CheckFieldKeyword = $FileNamePatternsAllTest | gm | where name -like "keyword" | select name -ExpandProperty name + $CheckFieldCategory = $FileNamePatternsAllTest | gm | where name -like "category" | select name -ExpandProperty name + if($CheckFieldKeyword -and $CheckFieldCategory){ + # File found and columns exist + $FileNamePatternsAll = $FileNamePatternsAllTest + }else{ + # File columns do not exist + # Do nothing and fail back to hard coded list + } + } + + # Get unqiue categories + $FileNamePatternCategories = $FileNamePatternsAll | select Category -Unique + $FileNamePatternCategoriesCount = $FileNamePatternsAll | select Category -Unique | measure | select count -ExpandProperty count + + # Generate chart categories - Individual rows + # for each category - "var MyScriptsCount = countStringInDisplayedRows('Scripts');" + $ChartCategoryCatVars = $FileNamePatternCategories | + foreach{ + $ChartCatGenCat = $_.category + $ChartCatGenVar = "My"+ $ChartCatGenCat + "Count" + "var $ChartCatGenVar = countStringInDisplayedRows('$ChartCatGenCat');" + } + $ChartCategoryCatVarsFlat = $ChartCategoryCatVars -join "`n" + + # Generate chart categories - Category list + # once - categories: ['Sensitive', 'Secrets', 'Scripts'], + $ChartCategoryCommas = ($FileNamePatternCategories | Select-Object -ExpandProperty category | ForEach-Object { "'$_'" }) -join ", " + $ChartCategoryCat = "categories: [$ChartCategoryCommas]," + + # Generate chart categories - + # once - data: [MySensitiveCount, MySecretCount, MyScriptsCount] + $ChartCategoryCountFormat = ($FileNamePatternCategories | Select-Object -ExpandProperty category | ForEach-Object {"My"+ $_ + "Count"}) -join ", " + $ChartCategoryDat = "data: [$ChartCategoryCountFormat]" + + # Get a list of file names from each folder group for the target share name + $InterestingFilesAllFileNames = $ExcessiveSharePrivs | select FileList -Unique | foreach {$_.FileList -split "`r`n"} | Where-Object {$_ -ne ''} | foreach {$_.ToLower()}| select -Unique + + # Identify keyword matches in filenames + $InterestingFilesAllMatches = New-Object system.data.datatable + $InterestingFilesAllMatches.Columns.Add("FileName") | Out-Null + $InterestingFilesAllMatches.Columns.Add("Category") | Out-Null + $FileNamePatternsAll | + foreach { + $TargetKeywordValue = $_.Keyword + $TargetKeywordCategory = $_.Category + $InterestingFilesAllFileNames | + foreach { + + if($_ -like "$TargetKeywordValue"){ + + # check if file has already been labeled + $CheckForFile = $InterestingFilesAllMatches | where Filename -like "$_" + if(-not $CheckForFile){ + + # Add file + $InterestingFilesAllMatches.Rows.Add("$_","$TargetKeywordCategory")| Out-Null + } + } + } + } + + # Query for a list of information for each file name match + $InterestingFilesAllObjects = $InterestingFilesAllMatches | + foreach{ + + # Set variables + $TargetFileNameValue = $_.FileName + $TargetCategoryValue = $_.Category + + # Filter for records with the target file + $TargetKeywordMatches = $ExcessiveSharePrivs | where FileList -like "*$TargetFileNameValue*" | select ComputerName,ShareName,SharePath -Unique + + # Extend object to include a unc path to file + $TargetKeywordMatches | + foreach { + + # Select the propertity and make new ones + $TargetKeywordComputer = $_.ComputerName + $TargetKeywordShareName = $_.ShareName + $TargetKeywordSharePath = $_.SharePath + $TargetKeywordUNCPath = "$TargetKeywordSharePath\$TargetFileNameValue" + $TargetKeywordCategory = $TargetCategoryValue + + # Create updated object + $object = New-Object psobject + $object | add-member noteproperty ComputerName $TargetKeywordComputer + $object | add-member noteproperty ShareName $TargetKeywordShareName + $object | add-member noteproperty SharePath $TargetKeywordSharePath + $object | add-member noteproperty UncPath $TargetKeywordUNCPath + $object | add-member noteproperty FileName $TargetFileNameValue + $object | add-member noteproperty Category $TargetKeywordCategory + + # Return object + $object + } + } | select ComputerName,ShareName,SharePath,UncPath,FileName,Category -Unique + + <# + + # Define list of words associated with sensitive data + $FileNamePatternsSecrets = $FileNamePatternsAll | where category -like "*Secret*" | select Keyword -ExpandProperty keyword + + # Define list of words associated with password files + $FileNamePatternsData = $FileNamePatternsAll | where category -like "*Sensitive*" | select Keyword -ExpandProperty keyword + + # Get a list of file names from each folder group for the target share name + $InterestingFilesAllFileNames = $ExcessiveSharePrivs | select FileList -Unique | foreach {$_.FileList -split "`r`n"} | Where-Object {$_ -ne ''} | foreach {$_.ToLower()}| select -Unique + + # Identify Secrets + $InterestingFilesAllSecrets = $FileNamePatternsSecrets | + foreach { + $TargetSecret = $_ + $InterestingFilesAllFileNames | + foreach { + if($_ -like "$TargetSecret"){ + + # return file name match + $_ + } + } + } + + # Create new secret files objects + $InterestingFilesAllSecretsObjects = $InterestingFilesAllSecrets | + foreach{ + + # Set target file + $TargetSecretFile = $_ + + # Filter for record with the target file + $TargetSecretMatches = $ExcessiveSharePrivs | where FileList -like "*$TargetSecretFile*" | select ComputerName,ShareName,SharePath -Unique + $TargetSecretMatches | + foreach { + + # Select the propertity and make new ones + $TargetSecretComputer = $_.ComputerName + $TargetSecretShareName = $_.ShareName + $TargetSecretSharePath = $_.SharePath + $TargetSecretUNCPath = "$TargetSecretSharePath\$TargetSecretFile" + $TargetSecretType = "Secrets" + + # Create updated object + $object = New-Object psobject + $object | add-member noteproperty ComputerName $TargetSecretComputer + $object | add-member noteproperty ShareName $TargetSecretShareName + $object | add-member noteproperty SharePath $TargetSecretSharePath + $object | add-member noteproperty UncPath $TargetSecretUNCPath + $object | add-member noteproperty FileName $TargetSecretFile + $object | add-member noteproperty DataType $TargetSecretType + + # Return object + $object + } + } | select ComputerName,ShareName,SharePath,UncPath,FileName,DataType -Unique + + # Identify Data + $InterestingFilesAllData = $FileNamePatternsData | + foreach { + $TargetSecret = $_ + $InterestingFilesAllFileNames | + foreach { + if($_ -like "$TargetSecret"){ + + # return file name match + $_ + } + } + } + + # Create new data files objects + $InterestingFilesAllDataObjects = $InterestingFilesAllData | + foreach{ + + # Set target file + $TargetSecretFile = $_ + + # Filter for record with the target file + $TargetSecretMatches = $ExcessiveSharePrivs | where FileList -like "*$TargetSecretFile*" | select ComputerName,ShareName,SharePath -Unique + $TargetSecretMatches | + foreach { + + # Select the propertity and make new ones + $TargetSecretComputer = $_.ComputerName + $TargetSecretShareName = $_.ShareName + $TargetSecretSharePath = $_.SharePath + $TargetSecretUNCPath = "$TargetSecretSharePath\$TargetSecretFile" + $TargetSecretType = "Sensitive" + + # Create updated object + $object = New-Object psobject + $object | add-member noteproperty ComputerName $TargetSecretComputer + $object | add-member noteproperty ShareName $TargetSecretShareName + $object | add-member noteproperty SharePath $TargetSecretSharePath + $object | add-member noteproperty UncPath $TargetSecretUNCPath + $object | add-member noteproperty FileName $TargetSecretFile + $object | add-member noteproperty DataType $TargetSecretType + + # Return object + $object + } + } | select ComputerName,ShareName,SharePath,UncPath,FileName,DataType -Unique + + # Combine objects + $InterestingFilesAllObjects = $InterestingFilesAllSecretsObjects + $InterestingFilesAllDataObjects + + + # Count objects + $InterestingFilesAllSecretsFullCount = $InterestingFilesAllSecretsObjects | measure | select count -ExpandProperty count + $InterestingFilesAllSecretsFullCountU = $InterestingFilesAllSecretsObjects | select FileName -Unique | measure | select count -ExpandProperty count + $InterestingFilesAllDataFullcount = $InterestingFilesAllDataObjects | measure | select count -ExpandProperty count + $InterestingFilesAllDataFullcountU = $InterestingFilesAllDataObjects | select FileName -Unique | measure | select count -ExpandProperty count + #> + + # Outbout objects to file + $InterestingFilesAllObjects | Export-Csv -NoTypeInformation "$OutputDirectory\$TargetDomain-Shares-Interesting-Files.csv" + + # Get order list of interesting file names by count + $InterestingFilesAllFilesCount = $InterestingFilesAllObjects | measure | select count -ExpandProperty count + $InterestingFilesAllFilesCountU = $InterestingFilesAllObjects | select filename -Unique | measure | select count -ExpandProperty count + $InterestingFilesAllFilesGrouped = $InterestingFilesAllObjects | group filename | select count,name | sort count -Descending + + # Generate a row for each one + # Headers are Instance Count, FileName, Type, File Paths,Affected Computers, Affected Shares + $InterestingFilesAllFilesRows = $InterestingFilesAllFilesGrouped | + foreach{ + + # Get count + $IfFinalCount = $_.count + + # Get File Name + $IfFinalName = $_.name + + # Category + $IfFinalType = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | select Category -First 1 -ExpandProperty Category + + # Get File Paths + $IfFinalPaths = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | ForEach-Object { $ASDF = $_.UncPath; "$ASDF
" } | Out-String + + # Get Share Count for Name + # $IfFinalShareCount + $IfFinalShareCount = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | select SharePath -Unique | measure | select count -ExpandProperty count + + # Get Computer Count for Name + # $IfFinalcomputerCount + $IfFinalcomputerCount = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | select ComputerName -Unique | measure | select count -ExpandProperty count + + # Create Row + + $IfRow = @" + + $IfFinalCount + $IfFinalName + $IfFinalType + + +
+ $IfFinalPaths +
+ + +"@ + + # Return row + $IfRow + } # ---------------------------------------------------------------------- @@ -2996,8 +3392,21 @@ $NewHtmlReport = @" + Report