diff --git a/PowerHuntShares.psm1 b/PowerHuntShares.psm1 index c4438ec..0743a22 100644 --- a/PowerHuntShares.psm1 +++ b/PowerHuntShares.psm1 @@ -4,7 +4,7 @@ #-------------------------------------- # Author: Scott Sutherland, 2024 NetSPI # License: 3-clause BSD -# Version: v1.117 +# Version: v1.118 # 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 { @@ -2505,6 +2505,186 @@ function Invoke-HuntSMBShares $SanKeyLow = "" } + # ---------------------------------------------------------------------- + # Generate Share Creation Timeline Data Series Objects + # ---------------------------------------------------------------------- + + # Set Counters + $LowAcesCounter = 0 + $MediumAcesCounter = 0 + $HighAcesCounter = 0 + $CriticalAcesCounter = 0 + + # Create date series variables + $DataSeriesComputers = "" + $DataSeriesShares = "" + $DataSeriesAces = "" + $DataSeriesLow = "" + $DataSeriesMedium = "" + $DataSeriesHigh = "" + $DataSeriesCritical = "" + + # Get unique dates from final inventory + $UniqueDates = $ExcessiveSharePrivsFinal | select CreationDate -Unique | + foreach { + + # Get date + $dateTimeString = $_.CreationDate; + + # Convert the string to a [DateTime] object + $dateTime = [DateTime]::Parse($dateTimeString) + + # Return the DateTime object + $dateTime.Date + + } | Sort-Object | Select-Object -Unique | foreach { + + # After sorting and removing duplicates, format the date as MM/dd/yyyy + $_.ToString('MM/dd/yyyy') + + } + + # Join the dates into a comma-separated string and format it as labels + $labelsString = $UniqueDates -join "', '" + $formattedLabels = "labels: ['$labelsString']," + + # Pre-process all CreationDates from final inventory to avoid repeated parsing and formatting + $AllAcesWithFormattedDates = $ExcessiveSharePrivsFinal | ForEach-Object { + # Create a new property 'FormattedCreationDate' with the date formatted as 'MM/dd/yyyy' + $_ | Add-Member -MemberType NoteProperty -Name 'FormattedCreationDate' -Value ([DateTime]::Parse($_.CreationDate).ToString('MM/dd/yyyy')) -PassThru + } + + # Get start and end dates for all + $AcesFirstDate = $UniqueDates | select -First 1 + $AcesLastDate = $UniqueDates | select -Last 1 + + # Get start and end dates for all high + $ACEHighCountBlah = $AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | measure | select count -ExpandProperty count + If($ACEHighCountBlah -gt 0) + { + [datetime]$HighFirstDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'High' } | 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 + $HighLastDateS = $HighLastDateD.ToString('MM/dd/yyyy') + + #$ACEHighTime = "Shares configured with high risk ACEs were created between $HighFirstDateS and $HighLastDateS." + $ACEHighTime = "" + }else{ + $HighFirstDateS = "NA" + $HighLastDateS = "NA" + $ACEHighTime = "" + } + + + + # Get start and end dates for all critical + $ACECriticalCountBlah = $AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | measure | select count -ExpandProperty count + If($ACECriticalCountBlah -gt 0) + { + [datetime]$CriticalFirstDateD = [datetime]($AllAcesWithFormattedDates | Where-Object { $_.RiskLevel -eq 'Critical' } | 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 + $CriticalLastDateS = $CriticalLastDateD.ToString('MM/dd/yyyy') + + #$ACECriticalTime = "Shares configured with critical risk ACEs were created between $CriticalFirstDateS and $CriticalLastDateS." + $ACECriticalTime = "" + }else{ + $CriticalFirstDateS = "NA" + $CriticalLastDateS = "NA" + $ACECriticalTime = "" + } + + + + # Iterate through unique dates and count ACEs efficiently + $UniqueDates | ForEach-Object { + + # Get target date + $TargetDate = $_ + + # Filter ACES with pre-formatted dates + $TargetAces = $AllAcesWithFormattedDates | Where-Object { + $_.FormattedCreationDate -eq $TargetDate + } + + # Count the number of matching ACEs + $TargetAcesCount = $TargetAces | measure | select count -ExpandProperty count + if($TargetAcesCount -gt 0){ + $DataSeriesAces = $DataSeriesAces + ", $TargetAcesCount" + } + + # Get computer count + $TargetAcesComputerCount = $TargetAces | select ComputerName -unique | measure | select count -expandproperty count + + # Add computer count to series + $DataSeriesComputers = $DataSeriesComputers + ", $TargetAcesComputerCount" + + # Get share 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 + } + $DataSeriesLow = $DataSeriesLow + ", $LowAcesCounter" + + # Check for mediums and increase counter + $MediumAceCount = $TargetAces | where RiskLevel -eq 'Medium' | measure | select count -expandproperty count + if($MediumAceCount -gt 0){ + $MediumAcesCounter = $MediumAcesCounter + $MediumAceCount + } + $DataSeriesMedium = $DataSeriesMedium + ", $MediumAcesCounter" + + # Check for highs and increase counter + $HighAceCount = $TargetAces | where RiskLevel -eq 'High' | measure | select count -expandproperty count + if($HighAceCount -gt 0){ + $HighAcesCounter = $HighAcesCounter + $HighAceCount + } + $DataSeriesHigh = $DataSeriesHigh + ", $HighAcesCounter" + + # Check for critical and increase counter + $CriticalAceCount = $TargetAces | where RiskLevel -eq 'Critical' | measure | select count -expandproperty count + if($CriticalAceCount -gt 0){ + $CriticalAcesCounter = $CriticalAcesCounter + $CriticalAceCount + } + $DataSeriesCritical = $DataSeriesCritical + ", $CriticalAcesCounter" + } + + # Final data series formatting + $DataSeriesComputers = $DataSeriesComputers.Substring(2) + $DataSeriesComputers = '[' + $DataSeriesComputers + ']' + $DataSeriesShares = $DataSeriesShares.Substring(2) + $DataSeriesShares = '[' + $DataSeriesShares + ']' + $DataSeriesAces = $DataSeriesAces.Substring(2) + $DataSeriesAces = '[' + $DataSeriesAces + ']' + $DataSeriesLow = $DataSeriesLow.Substring(2) + $DataSeriesLow = '[' + $DataSeriesLow + ']' + $DataSeriesMedium = $DataSeriesMedium.Substring(2) + $DataSeriesMedium = '[' + $DataSeriesMedium + ']' + $DataSeriesHigh = $DataSeriesHigh.Substring(2) + $DataSeriesHigh = '[' + $DataSeriesHigh + ']' + $DataSeriesCritical = $DataSeriesCritical.Substring(2) + $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) + + # 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 + + # Get number of records/days past the + $DataSeriesAceAnomalyCount = ($DataSeriesAcesNum| Where-Object { $_ -ge $DataSeriesAceSDtwo }) | Measure-Object | select count -ExpandProperty count # ---------------------------------------------------------------------- # Create ShareGraph Nodes and Edges @@ -5576,9 +5756,7 @@ input[type="checkbox"]:checked::before {
- - - +