diff --git a/PowerHuntShares.psm1 b/PowerHuntShares.psm1
index 0743a22..a57094b 100644
--- a/PowerHuntShares.psm1
+++ b/PowerHuntShares.psm1
@@ -4,7 +4,7 @@
#--------------------------------------
# Author: Scott Sutherland, 2024 NetSPI
# License: 3-clause BSD
-# Version: v1.118
+# Version: v1.119
# 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
{
@@ -2510,10 +2510,10 @@ function Invoke-HuntSMBShares
# ----------------------------------------------------------------------
# Set Counters
- $LowAcesCounter = 0
- $MediumAcesCounter = 0
- $HighAcesCounter = 0
- $CriticalAcesCounter = 0
+ $LowShareCounter = 0
+ $MediumShareCounter = 0
+ $HighShareCounter = 0
+ $CriticalShareCounter = 0
# Create date series variables
$DataSeriesComputers = ""
@@ -2555,49 +2555,55 @@ function Invoke-HuntSMBShares
}
# Get start and end dates for all
- $AcesFirstDate = $UniqueDates | select -First 1
- $AcesLastDate = $UniqueDates | select -Last 1
+ $ShareFirstDate = $UniqueDates | select -First 1
+ $ShareLastDate = $UniqueDates | select -Last 1
+
+ # Set color check to 0
+ $ShareCriticalHighCheck = 0
# Get start and end dates for all high
- $ACEHighCountBlah = $AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | measure | select count -ExpandProperty count
- If($ACEHighCountBlah -gt 0)
+ $ShareHighCountBlah = $AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | select SharePath -Unique | measure | select count -ExpandProperty count
+ If($ShareHighCountBlah -gt 0)
{
- [datetime]$HighFirstDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | Select-Object -First 1).CreationDate
+ [datetime]$HighFirstDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | Sort | Select-Object -First 1).CreationDate
$HighFirstDateS = $HighFirstDateD.ToString('MM/dd/yyyy')
- [datetime]$HighLastDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | Select-Object -Last 1).CreationDate
+ [datetime]$HighLastDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | Sort | Select-Object -Last 1).CreationDate
$HighLastDateS = $HighLastDateD.ToString('MM/dd/yyyy')
- #$ACEHighTime = "Shares configured with high risk ACEs were created between $HighFirstDateS and $HighLastDateS."
- $ACEHighTime = ""
+ $ShareHighTime = "Shares configured with high risk ACEs were created between $HighFirstDateS and $HighLastDateS."
+ # $ShareHighTime = ""
+ $ShareCriticalHighCheck = 1
}else{
- $HighFirstDateS = "NA"
- $HighLastDateS = "NA"
- $ACEHighTime = ""
+ # $HighFirstDateS = "NA"
+ # $HighLastDateS = "NA"
+ $ShareHighTime = "No shares were found configured with high risk ACEs."
}
-
-
# Get start and end dates for all critical
- $ACECriticalCountBlah = $AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | measure | select count -ExpandProperty count
- If($ACECriticalCountBlah -gt 0)
+ $ShareCriticalCountBlah = $AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | select SharePath -Unique | measure | select count -ExpandProperty count
+ If($ShareCriticalCountBlah -gt 0)
{
- [datetime]$CriticalFirstDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | Select-Object -First 1).CreationDate
+ [datetime]$CriticalFirstDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | Sort | Select-Object -First 1).CreationDate
$CriticalFirstDateS = $CriticalFirstDateD.ToString('MM/dd/yyyy')
- [datetime]$CriticalLastDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | Select-Object -Last 1).CreationDate
+ [datetime]$CriticalLastDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | Sort | Select-Object -Last 1).CreationDate
$CriticalLastDateS = $CriticalLastDateD.ToString('MM/dd/yyyy')
- #$ACECriticalTime = "Shares configured with critical risk ACEs were created between $CriticalFirstDateS and $CriticalLastDateS."
- $ACECriticalTime = ""
+ $ShareCriticalTime = "Shares configured with critical risk ACEs were created between $CriticalFirstDateS and $CriticalLastDateS."
+ # $ShareCriticalTime = ""
+ $ShareCriticalHighCheck = 1
}else{
- $CriticalFirstDateS = "NA"
- $CriticalLastDateS = "NA"
- $ACECriticalTime = ""
+ # $CriticalFirstDateS = "NA"
+ # $CriticalLastDateS = "NA"
+ $ShareCriticalTime = "No shares were found configured with critical risk ACEs."
+ }
+
+ if($ShareCriticalHighCheck -eq 1){
+ $ShareCriticalHighLine = "The orange and red trend areas reflect the cumulative number of critical and high risk shares in the environment so you can easily observe when/if they were introduced."
}
-
# Iterate through unique dates and count ACEs efficiently
$UniqueDates | ForEach-Object {
@@ -2622,38 +2628,38 @@ function Invoke-HuntSMBShares
$DataSeriesComputers = $DataSeriesComputers + ", $TargetAcesComputerCount"
# Get share count
- $TargetAcesShareCount = $TargetAces | select SharePath -unique | measure | select count -expandproperty count
+ $TargetAcesShareCount = $TargetAces | select SharePath -unique | measure | select count -expandproperty count
# Add share count to series
$DataSeriesShares = $DataSeriesShares + ", $TargetAcesShareCount"
# Check for lows and increase counter
- $LowAceCount = $TargetAces | where RiskLevel -eq 'Low' | measure | select count -expandproperty count
- if($LowAceCount -gt 0){
- $LowAcesCounter = $LowAcesCounter + $LowAceCount
+ $LowShareCount = $TargetAces | where RiskLevel -eq 'Low' | select SharePath -Unique | measure | select count -expandproperty count
+ if($LowShareCount -gt 0){
+ $LowShareCounter = $LowShareCounter + $LowShareCount
}
- $DataSeriesLow = $DataSeriesLow + ", $LowAcesCounter"
+ $DataSeriesLow = $DataSeriesLow + ", $LowShareCounter"
# Check for mediums and increase counter
- $MediumAceCount = $TargetAces | where RiskLevel -eq 'Medium' | measure | select count -expandproperty count
- if($MediumAceCount -gt 0){
- $MediumAcesCounter = $MediumAcesCounter + $MediumAceCount
+ $MediumShareCount = $TargetAces | where RiskLevel -eq 'Medium' | select SharePath -Unique | measure | select count -expandproperty count
+ if($MediumShareCount -gt 0){
+ $MediumShareCounter = $MediumShareCounter + $MediumShareCount
}
- $DataSeriesMedium = $DataSeriesMedium + ", $MediumAcesCounter"
+ $DataSeriesMedium = $DataSeriesMedium + ", $MediumShareCounter"
# Check for highs and increase counter
- $HighAceCount = $TargetAces | where RiskLevel -eq 'High' | measure | select count -expandproperty count
- if($HighAceCount -gt 0){
- $HighAcesCounter = $HighAcesCounter + $HighAceCount
+ $HighShareCount = $TargetAces | where RiskLevel -eq 'High' | select SharePath -Unique | measure | select count -expandproperty count
+ if($HighShareCount -gt 0){
+ $HighShareCounter = $HighShareCounter + $HighShareCount
}
- $DataSeriesHigh = $DataSeriesHigh + ", $HighAcesCounter"
+ $DataSeriesHigh = $DataSeriesHigh + ", $HighShareCounter"
# Check for critical and increase counter
- $CriticalAceCount = $TargetAces | where RiskLevel -eq 'Critical' | measure | select count -expandproperty count
- if($CriticalAceCount -gt 0){
- $CriticalAcesCounter = $CriticalAcesCounter + $CriticalAceCount
+ $CriticalShareCount = $TargetAces | where RiskLevel -eq 'Critical' | select SharePath -Unique | measure | select count -expandproperty count
+ if($CriticalShareCount -gt 0){
+ $CriticalShareCounter = $CriticalShareCounter + $CriticalShareCount
}
- $DataSeriesCritical = $DataSeriesCritical + ", $CriticalAcesCounter"
+ $DataSeriesCritical = $DataSeriesCritical + ", $CriticalShareCounter"
}
# Final data series formatting
@@ -2673,18 +2679,18 @@ function Invoke-HuntSMBShares
$DataSeriesCritical = '[' + $DataSeriesCritical + ']'
# For ace count by date, get the max and average
- $DataSeriesAcesClean = $DataSeriesAces.TrimStart('[').TrimEnd(']')
- $DataSeriesAcesNum = $DataSeriesAcesClean -split ',\s*' | ForEach-Object { [int]$_ }
- $DataSeriesAceMax = $DataSeriesAcesNum | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum
- $DataSeriesAceAvg = [math]::Round(($DataSeriesAcesNum | Measure-Object -Maximum -Average | Select-Object -ExpandProperty Average),2)
+ $DataSeriesSharesClean = $DataSeriesShares.TrimStart('[').TrimEnd(']')
+ $DataSeriesSharesNum = $DataSeriesSharesClean -split ',\s*' | ForEach-Object { [int]$_ }
+ $DataSeriesSharesMax = $DataSeriesSharesNum | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum
+ $DataSeriesSharesAvg = [math]::Round(($DataSeriesSharesNum | Measure-Object -Maximum -Average | Select-Object -ExpandProperty Average),2)
# Get standard deviation number and standard deviation x2 number from mean
- $DataSeriesAceVariance = ($DataSeriesAcesNum | ForEach-Object { [math]::Pow($_ - $DataSeriesAceAvg, 2) } | Measure-Object -Average).Average
- $DataSeriesAceSD = [math]::Round([math]::Sqrt($DataSeriesAceVariance),2)
- $DataSeriesAceSDtwo = $DataSeriesAceSD * 2 + $DataSeriesAceAvg
+ $DataSeriesSharesVariance = ($DataSeriesSharesNum | ForEach-Object { [math]::Pow($_ - $DataSeriesSharesAvg, 2) } | Measure-Object -Average).Average
+ $DataSeriesSharesSD = [math]::Round([math]::Sqrt($DataSeriesSharesVariance),2)
+ $DataSeriesSharesSDtwo = $DataSeriesSharesSD * 2 + $DataSeriesSharesAvg
# Get number of records/days past the
- $DataSeriesAceAnomalyCount = ($DataSeriesAcesNum| Where-Object { $_ -ge $DataSeriesAceSDtwo }) | Measure-Object | select count -ExpandProperty count
+ $DataSeriesSharesAnomalyCount = ($DataSeriesSharesNum | Where-Object { $_ -ge $DataSeriesSharesSDtwo }) | Measure-Object | select count -ExpandProperty count
# ----------------------------------------------------------------------
# Create ShareGraph Nodes and Edges
@@ -5770,7 +5776,9 @@ input[type="checkbox"]:checked::before {
- The chart below illustrates the relationship between networks, computers, shares, and the ACEs configured with excessive privileges. Each network contains computers with assigned IP addresses. Each computer may host multiple shares and each share is configured with ACEs that allow remote access. As a result, ACEs represent the individual points of remediation that will need to be addressed to reduce exposure and risk.
+ Affected Assets
+ $ExcessiveSharePrivsCount ACL entries, on $ExcessiveSharesCount shares, hosted by $ComputerWithExcessive computers were found configured with excessive privileges on the $TargetDomain domain. Overall, $IdentityReferenceListCount identities/groups had excessive privileges assigned to them.
+ The chart below illustrates the relationship between networks, computers, shares, and the ACEs configured with excessive privileges. Each network contains computers with assigned IP addresses. Each computer may host multiple shares and each share is configured with ACEs that allow remote access. As a result, ACEs represent the individual points of remediation that will need to be addressed to reduce exposure and risk.
- Remediation Prioritization
- Consider remediating share ACEs by risk level, starting with critical and high risks. Consider reviewing the share creation timeline for additional contenxt. Next, prioritize remediating groups of shares to speed up the process. Prioritize by folder group (shares containing exactly the same files) or by share names that have a high similarity score.
- Prioritizing those groups may help reduce remediation actions by as much as $RemediationSavings percent for this environment. Below is a summary of the potential task reduction for each approach.
-
- Below is a summary of the computers, shares, and ACEs associated with shares configured with excessive privileges.
- $ExcessiveSharePrivsCount ACL entries, on $ExcessiveSharesCount shares, hosted by $ComputerWithExcessive computers were found configured with excessive privileges on the $TargetDomain domain. Overall, $IdentityReferenceListCount identities were assigned excessive privileges. Click the "Exposure Summary" or the titles on the cards below to explore the details.
+ Below is a time series chart to help provide a sense of when shares were created and at what point critical and high risk shares were introduced into the environment.
+ By reading the chart left to right, you can see that shares were created in this environment between $ShareFirstDate and $ShareLastDate. You can zoom into any section of the chart by clicking or using the chart controls in the upper right hand corner of the chart.
+ $ShareCriticalTime
+ $ShareHighTime
+ $ShareCriticalHighLine
+ The chart also includes two horizontal lines. The "avg" line shows the average number of created shares and everything above the "+2 Std Dev" line is considered anomolous in the context of this report. $DataSeriessharesAnomalyCount anomalies were found that represent days when share creation counts were twice the standard deviation.
-
-
-
-
Share Creation Timeline
-
- Below is a time series chart to help provide a sense of when shares were created and at what point high-risk and critical-risk shares were introduced into the environment.
- Shares were found created in this environment between $AcesFirstDate and $AcesLastDate.
- The average number of ACEs associated with shares created on the same day is $DataSeriesAceAvg, the max is $DataSeriesAceMax, and the standard deviation is $DataSeriesAceSD.
- $DataSeriesAceAnomalyCount anomalies were found that represent days when shares were created with ACE counts twice the standard deviation.
- $ACEHighTime
- $ACECriticalTime
+ Consider remediating share ACEs by risk level, starting with critical and high risks. Consider reviewing the share creation timeline and data details from the other sections for additional context. Next, prioritize remediating groups of shares to speed up the process. Prioritize by folder group (shares containing exactly the same files) or by share names that have a high similarity score.
+ Prioritizing those groups may help reduce remediation actions by as much as $RemediationSavings percent for this environment. Below is a summary of the potential task reduction for each approach.
+