From 61ae16bef6adaa31667245105b25d92e7999eb16 Mon Sep 17 00:00:00 2001 From: Scott Sutherland Date: Tue, 29 Oct 2024 10:24:34 -0500 Subject: [PATCH] Update PowerHuntShares.psm1 Updated dashboard charts. Fixed bugs. Added menu icons. --- PowerHuntShares.psm1 | 1153 ++++++++++++++++++++++++++---------------- 1 file changed, 722 insertions(+), 431 deletions(-) diff --git a/PowerHuntShares.psm1 b/PowerHuntShares.psm1 index ffb7316..0332405 100644 --- a/PowerHuntShares.psm1 +++ b/PowerHuntShares.psm1 @@ -4,7 +4,7 @@ #-------------------------------------- # Author: Scott Sutherland, 2024 NetSPI # License: 3-clause BSD -# Version: v1.180 +# Version: v1.182 # 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 { @@ -1869,7 +1869,7 @@ function Invoke-HuntSMBShares } # Generate counts for dashabord summary and for "Recovered Secrets" Page - $SecretsRecoveredCount = $MySecretsTbl | Select-Object ComputerName, ShareName, UncFilePath, FileName, Section, ObjectName, TargetURL, TargetServer, TargetPort, Database, Domain, Username, Password, PasswordEnc, KeyFilePath -Unique | measure | select count -ExpandProperty count + $SecretsRecoveredCount = $MySecretsTbl | Where ComputerName -NotLike "" | Select-Object ComputerName, ShareName, UncFilePath, FileName, Section, ObjectName, TargetURL, TargetServer, TargetPort, Database, Domain, Username, Password, PasswordEnc, KeyFilePath -Unique | measure | select count -ExpandProperty count # Generate count of file that secrests were recovered from (instead of total recovered secrets) $SecretsRecoveredFileCount = $MySecretsTbl | Select-Object UncFilePath -Unique | measure | select count -ExpandProperty count @@ -1977,7 +1977,6 @@ function Invoke-HuntSMBShares $MySecretsTbl } - # ---------------------------------------------------------------------- # Create Share Name Application Fingerprint Library # ---------------------------------------------------------------------- @@ -2505,41 +2504,61 @@ function Invoke-HuntSMBShares # Return it $SubnetSummaryHTML = "$HTMLSTART $HTMLTableColumn $HTMLTableRow $HTMLEND" - # Create network risk table data + # Create network risk table data - each network is placed in one severity - the highest $SubnetTotalLow = 0 $SubnetTotalMedium = 0 $SubnetTotalHigh = 0 $SubnetTotalCritical = 0 + + # Create totals affected for each severity + $AllNetworksWithCriticalCount = 0 + $AllNetworksWithHighCount = 0 + $AllNetworksWithMediumCount = 0 + $AllNetworksWithLowCount = 0 + $SubnetSummary | foreach{ + + $CumulativeSevScore = 0 # Get subnet without trailing .0 $SubnetIp = $_.Subnet $SubnetIpBase = ($SubnetIp -split '\.')[0..2] -join '.' # Get Low count for subnet - $SubnetCountLow = $ExcessiveSharePrivsFinal | where IpAddress -like "$SubnetIpBase*" | where RiskLevel -eq 'Low' | measure | select count -ExpandProperty count + $SubnetCountLow = $ExcessiveSharePrivsFinal | where IpAddress -like "$SubnetIpBase*" | where RiskLevel -eq 'Low' | measure | select count -ExpandProperty count if($SubnetCountLow -gt 0){ - $SubnetTotalLow = $SubnetTotalLow + 1 + $AllNetworksWithLowCount = $AllNetworksWithLowCount + 1 + $CumulativeSevScore = $CumulativeSevScore + 1 } # Get Medium count for subnet - $SubnetCountMedium = $ExcessiveSharePrivsFinal | where IpAddress -like "$SubnetIpBase*" | where RiskLevel -eq 'Medium' | measure | select count -ExpandProperty count + $SubnetCountMedium = $ExcessiveSharePrivsFinal | where IpAddress -like "$SubnetIpBase*" | where RiskLevel -eq 'Medium' | measure | select count -ExpandProperty count if( $SubnetCountMedium -gt 0){ - $SubnetTotalMedium = $SubnetTotalMedium + 1 + $AllNetworksWithMediumCount = $AllNetworksWithMediumCount + 1 + $CumulativeSevScore = $CumulativeSevScore + 1 } # Get High count for subnet $SubnetCountHigh = $ExcessiveSharePrivsFinal | where IpAddress -like "$SubnetIpBase*" | where RiskLevel -eq 'High' | measure | select count -ExpandProperty count if($SubnetCountHigh -gt 0){ - $SubnetTotalHigh = $SubnetTotalHigh + 1 + $AllNetworksWithHighCount = $AllNetworksWithHighCount + 1 + $CumulativeSevScore = $CumulativeSevScore + 1 } # Get Critical count for subnet - $SubnetCountCritical = $ExcessiveSharePrivsFinal | where IpAddress -like "$SubnetIpBase*" | where RiskLevel -eq 'Critical' | measure | select count -ExpandProperty count + $SubnetCountCritical = $ExcessiveSharePrivsFinal | where IpAddress -like "$SubnetIpBase*" | where RiskLevel -eq 'Critical' | measure | select count -ExpandProperty count if($SubnetCountCritical -gt 0){ - $SubnetTotalCritical = $SubnetTotalCritical + 1 + $AllNetworksWithCriticalCount = $AllNetworksWithCriticalCount + 1 + $CumulativeSevScore = $CumulativeSevScore + 1 } + + # Check count to determine the highest severity for each network + if ($CumulativeSevScore -eq 1){$SubnetTotalLow = $SubnetTotalLow + 1} + if ($CumulativeSevScore -eq 2){$SubnetTotalMedium = $SubnetTotalMedium + 1} + if ($CumulativeSevScore -eq 3){$SubnetTotalHigh = $SubnetTotalHigh + 1} + if ($CumulativeSevScore -eq 4){$SubnetTotalCritical = $SubnetTotalCritical + 1} + } # Construct the array with the desired pattern @@ -2629,12 +2648,18 @@ function Invoke-HuntSMBShares # Create Computer Insights Summary Information # ---------------------------------------------------------------------- - # Reset global computer risk levels + # Reset global computer risk levels - one severity per computer, the highest one. $RiskLevelComputersCountCritical = 0 $RiskLevelComputersCountHigh = 0 $RiskLevelComputersCountMedium = 0 $RiskLevelComputersCountLow = 0 + # Total Computers Affected by Severity - one computer may have many + $AllComputersWithCriticalCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'Critical' | Select ComputerName -Unique | Measure | Select Count -ExpandProperty Count + $AllComputersWithHighCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'High' | Select ComputerName -Unique | Measure | Select Count -ExpandProperty Count + $AllComputersWithMediumCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'Medium' | Select ComputerName -Unique | Measure | Select Count -ExpandProperty Count + $AllComputersWithLowCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'Low' | Select ComputerName -Unique | Measure | Select Count -ExpandProperty Count + # Rest row data $ComputerTableRows = "" $ComputerTableRow = "" @@ -2645,6 +2670,10 @@ function Invoke-HuntSMBShares # Get computer count $ComputersChartCount = $ComputerPageComputerList | measure | select count -ExpandProperty count # Unique folder group + + # Initialize an empty array to store os counts for vulnerabile computers + $OperatingSystemCounts = @() + # Process each computer & add data to final risk counts $ComputerPageComputerList | foreach { @@ -2655,6 +2684,16 @@ function Invoke-HuntSMBShares # Get os version $ComputerPageOS = $DomainComputers | Where ComputerName -eq $TargetComputers | Select OperatingSystem -ExpandProperty OperatingSystem + # Add or increment OS + $item = $OperatingSystemCounts | Where-Object { $_.Name -eq $ComputerPageOS } + if ($item) { + # If the item exists, increment its Value by 1 + $item.Value += 1 + } else { + # If the item does not exist, add it with the specified value + $OperatingSystemCounts += @{Name = $ComputerPageOS; Value = 1} + } + # Grab the risk level for the highest risk acl for the share name $ComputersTopACLRiskScore = $ExcessiveSharePrivsFinal | where ComputerName -eq $TargetComputers | select RiskScore | sort RiskScore -Descending | select -First 1 | select RiskScore -ExpandProperty RiskScore @@ -2766,7 +2805,7 @@ function Invoke-HuntSMBShares # Get count of unique operating systems $DomainComputerOSCount = $DomainComputerOSList | measure | select count -ExpandProperty count - # Get count of each operating system - the counts are off + # Get count of each operating system $DomainComputerOSSum = $DomainComputerOSList | Foreach { @@ -2792,10 +2831,10 @@ function Invoke-HuntSMBShares # Create java script chart objects - names $DomainComputerOSListJsNames = "" $DomainComputerOSListJsValues = "" - $DomainComputerOSSum | + $OperatingSystemCounts | foreach{ - $TargetOSName = $_.os - $TargetOSValue = $_.count + $TargetOSName = $_.Name + $TargetOSValue = $_.Value $DomainComputerOSListJsNames = $DomainComputerOSListJsNames + ",'" + $TargetOSName + "'" $DomainComputerOSListJsValues = $DomainComputerOSListJsValues + "," + $TargetOSValue } @@ -2813,6 +2852,12 @@ function Invoke-HuntSMBShares # Create Share Name Insights Data # ---------------------------------------------------------------------- + # Total Shares Affected by Severity - one computer may have many + $AllSharesWithCriticalCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'Critical' | Select SharePath -Unique | Measure | Select Count -ExpandProperty Count + $AllSharesWithHighCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'High' | Select SharePath -Unique | Measure | Select Count -ExpandProperty Count + $AllSharesWithMediumCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'Medium' | Select SharePath -Unique | Measure | Select Count -ExpandProperty Count + $AllSharesWithLowCount = $ExcessiveSharePrivsFinal | where RiskLevel -eq 'Low' | Select SharePath -Unique | Measure | Select Count -ExpandProperty Count + # Get unique share name count $ShareNameChartCount = $ExcessiveSharePrivsFinal | where ShareName -ne "" | select ShareName -Unique | foreach{ @@ -3001,6 +3046,100 @@ function Invoke-HuntSMBShares $SanKeyLow = "" } + <# HTML apexcharts.js sankey chart example + + // -------------------------- + // Dashboard Page: Sankey Chart + // -------------------------- + + + const SankeyData = { + nodes: [ + { + id: 'Networks ($SubnetsCount)', + title: 'Networks ($SubnetsCount)', + color: '#6f5420', + }, + { + id: 'Computers ($ComputerWithExcessive)', + title: 'Computers ($ComputerWithExcessive)', + color: '#7D825E', + }, + { + id: 'Shares ($ExcessiveSharesCount)', + title: 'Shares ($ExcessiveSharesCount)', + color: '#f29650', + }, + { + id: 'ACEs ($ExcessiveSharePrivsCount)', + title: 'ACEs ($ExcessiveSharePrivsCount)', + color: '#345367', + }, + { + id: 'Critical ($RiskLevelCountCritical)', + title: 'Critical ($RiskLevelCountCritical)', + color: '#772400', + }, + { + id: 'High ($RiskLevelCountHigh)', + title: 'High ($RiskLevelCountHigh)', + color: '#f56a00', + }, + { + id: 'Medium ($RiskLevelCountMedium)', + title: 'Medium ($RiskLevelCountMedium)', + color: '#6f5420', + }, + { + id: 'Low ($RiskLevelCountLow)', + title: 'Low ($RiskLevelCountLow)', + color: '#f3f1e6', + }, + ], + edges: [ + { + source: 'Networks ($SubnetsCount)', + target: 'Computers ($ComputerWithExcessive)', + value: $ComputerWithExcessive, + color: '#000', // Custom color for this edge + }, + { + source: 'Computers ($ComputerWithExcessive)', + target: 'Shares ($ExcessiveSharesCount)', + value: $ExcessiveSharesCount, + color: '#000', // Custom color for this edge + }, + { + source: 'Shares ($ExcessiveSharesCount)', + target: 'ACEs ($ExcessiveSharePrivsCount)', + value: $ExcessiveSharePrivsCount, + color: '#000', // Custom color for this edge + }, + $SanKeyCritical + $SanKeyHigh + $SanKeyMedium + $SanKeyLow + ], + }; + + const graphOptions = { + nodeWidth: 10, + fontFamily: 'Quicksand, sans-serif', + fontSize: '14px', + fontWeight: 400, + fontColor: '#345367', + height: 200, + width: 1200, + spacing: 10, // margin + enableTooltip: true, + canvasStyle: 'border: 0px solid #caced0;', + }; + const s = new ApexSankey(document.getElementById('svg-sankey'), graphOptions); + s.render(SankeyData); + + + #> + # ---------------------------------------------------------------------- # Generate Share Creation Timeline Data Series Objects # ---------------------------------------------------------------------- @@ -3096,7 +3235,7 @@ function Invoke-HuntSMBShares } 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." + $ShareCriticalHighLine = "The red and purple trend lines reflect the cumulative number of critical and high risk shares in the environment so you can easily observe when/if they were introduced." } @@ -5425,10 +5564,6 @@ $NewHtmlReport = @" text-decoration:underline } - li{ - list-style-type:none - } - .mobile{ display:none; height:0; @@ -6225,24 +6360,24 @@ input[type="checkbox"]:checked::before {
- - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +
@@ -6331,144 +6466,367 @@ input[type="checkbox"]:checked::before {

Summary Report

-
- This page provides a summary of the share scan results, observations, risks, and prioritized recommendations. -

-
-
+
+ + +
+ Testing was conducted between $StartTime and $EndTime to identify network shares configured with excessive privileges hosted on computers joined to the $TargetDomain domain. + In total, $RiskLevelCountCritical critical, $RiskLevelCountHigh high, $RiskLevelCountMedium medium, and $RiskLevelCountLow low risk ACE (Access Control Entry) configurations were discovered across $ExcessiveSharesCount shares, hosted by $ComputerWithExcessive computers in the $TargetDomain Active Directory domain. + Overall, $InterestingFilesAllFilesCount interesting files were found accessible to all domain users that could potentially lead to unauthorized data access or remote code execution. The affected shares were found hosting $InterestingFilesAllObjectsSecretCount files that may contain passwords and $InterestingFilesAllObjectsSensitiveCount files that may contain sensitive data. $SecretsRecoveredCount credentials were recovered from $SecretsRecoveredFileCount of the discovered $InterestingFilesAllObjectsSecretCount secrets files. +

+ The summary report below includes an overview of the affected assets, data & finding exposure, share creation timelines, and general recommendations. +
-
- Risk & Data Exposure
- In total, $RiskLevelCountCritical critical, $RiskLevelCountHigh high, $RiskLevelCountMedium medium, and $RiskLevelCountLow low risk ACE (Access Control Entry) configurations were discovered across $ExcessiveSharesCount shares, hosted by $ComputerWithExcessive computers in the $TargetDomain Active Directory domain. The affected shares were found hosting $InterestingFilesAllObjectsSecretCount files that may contain passwords and $InterestingFilesAllObjectsSensitiveCount files that may contain sensitive data. $SecretsRecoveredCount credentials were recovered from $SecretsRecoveredFileCount of the discovered $InterestingFilesAllObjectsSecretCount secrets files. Overall, $InterestingFilesAllFilesCount interesting files were found accessible to all domain users that could potentially lead to unauthorized data access or remote code execution. -

View the - Insecure ACEs, - Extracted Secrets, and - Interesting Files sections for more details.
-
- - - -
-
-
-
- -
+
+ + +
+ +
+
Finding Exposure Summary
+ + +
+ + +
+
+
+ Critical +
+
+ + $RiskLevelCountCritical
+
+ findings +
+
+
+ + +
+
+
+ High +
+
+ + $RiskLevelCountHigh
+
+ findings +
+
+
+ + +
+
+
+ Medium +
+
+ + $RiskLevelCountMedium
+
+ findings +
+
+
+ + +
+
+
+ Low +
+
+ + $RiskLevelCountLow
+
+ findings +
+
+
+ +
-
- - - -
-
-
-
- -
- -
- 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. -
+
-
- - -
-
+
+
+ +
+ +
+ More details available in the  NetworksComputersShares, and   ACEs  sections. +
+
+
+ +
+ +
+
Data Exposure Summary
+ + +
+ + +
+
+
+ Interesting +
+
+ + $InterestingFilesAllFilesCount
+
+ files found +
+
+
+ + +
+
+
+ Sensitive +
+
+ + $InterestingFilesAllObjectsSensitiveCount
+
+ files found +
+
+
+ + +
+
+
+ Secrets +
+
+ + $InterestingFilesAllObjectsSecretCount
+
+ files found +
+
+
+ + +
+
+
+ Extracted +
+
+ + $SecretsRecoveredCount
+
+ secrets ($SecretsRecoveredFileCount files) +
+
+
+ +
+ +
+
+
+
+ + +
+ More details are available in the  Extracted Secrets, and   Interesting Files  sections. +
+
+
+ +
+ -
- Peer Comparison
- Below is a comaprison between the percent of affected assets in this environment and the average percent of affected assets observed in other environments. - The percentage is calculated based on the total number of assets discovered for each asset type. -
-
- - - -
-
-
-
- -
+
+ + +
+
+
+
Asset Exposure Summary
+
+ $ExcessiveSharePrivsCount ACL entries, on $ExcessiveSharesCount shares, hosted by $ComputerWithExcessive computers were found configured with excessive privileges on the $TargetDomain domain. +
+ +
+ + +
+
+
+ Networks +
+
+ + $SubnetsCount
+
+ affected +
+
+
+ + +
+
+
+ Computers +
+
+ + $ComputerWithExcessive
+
+ affected +
+
+
+ +
+ + +
+ + +
+
+
+ Shares +
+
+ + $ExcessiveSharesCount
+
+ affected +
+
+
+ + +
+
+
+ ACEs +
+
+ + $ExcessiveSharePrivsCount
+
+ affected +
+
+
+
+
+
+
+ + + +
+
+
+
Affected Asset Peer Comparison
+
+ Below is a comaprison between the percent of affected assets in this environment and the average percent of + affected assets observed in other environments. The percentage is calculated based on the total number of + live assets discovered for each asset type. +
+
+
+
+
+
+
+
+ +
-
- Share Creation Timeline
-
- 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 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. -
-
-
- - -
-
-
-
-
+
+
+ +
+ + +
+
+
+
+
+
-
- Remediation & Prioritization Recommendations
- - 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. -

View the - Folder Group or - Share Names sections for more details. +
+
+
Remediation & Prioritization Recommendations
+
+ Remediate share ACEs by risk level, starting with critical and high risks. Review the share creation timeline and share name details from other sections for additional context. + Consider remediating mutliple ACEs at one time based on natural share groupings to reduce the number of remediation tasks.

+ Group Examples: +
    +
  • Group ACE remediation tasks by folder groups, which contain exactly the same file listing.
  • +
  • Group ACE remediation tasks by share names with a high similarity scores.
  • +
+ + Remediating ACEs by group may reduce remediation tasks by as much as $RemediationSavings% for this environment. The chart below shows the task savings.
+
-
+
-
-
+
+
+
+ More details are available in the  Folder Group, and   Share Names  sections. +
+
+ + - - - - -
@@ -10500,95 +10858,6 @@ var TimelineCreationChartVar = new ApexCharts(document.querySelector("#TimelinCr TimelineCreationChartVar.render(); -// -------------------------- -// Dashboard Page: Sankey Chart -// -------------------------- - - - const SankeyData = { - nodes: [ - { - id: 'Networks ($SubnetsCount)', - title: 'Networks ($SubnetsCount)', - color: '#6f5420', - }, - { - id: 'Computers ($ComputerWithExcessive)', - title: 'Computers ($ComputerWithExcessive)', - color: '#7D825E', - }, - { - id: 'Shares ($ExcessiveSharesCount)', - title: 'Shares ($ExcessiveSharesCount)', - color: '#f29650', - }, - { - id: 'ACEs ($ExcessiveSharePrivsCount)', - title: 'ACEs ($ExcessiveSharePrivsCount)', - color: '#345367', - }, - { - id: 'Critical ($RiskLevelCountCritical)', - title: 'Critical ($RiskLevelCountCritical)', - color: '#772400', - }, - { - id: 'High ($RiskLevelCountHigh)', - title: 'High ($RiskLevelCountHigh)', - color: '#f56a00', - }, - { - id: 'Medium ($RiskLevelCountMedium)', - title: 'Medium ($RiskLevelCountMedium)', - color: '#6f5420', - }, - { - id: 'Low ($RiskLevelCountLow)', - title: 'Low ($RiskLevelCountLow)', - color: '#f3f1e6', - }, - ], - edges: [ - { - source: 'Networks ($SubnetsCount)', - target: 'Computers ($ComputerWithExcessive)', - value: $ComputerWithExcessive, - color: '#000', // Custom color for this edge - }, - { - source: 'Computers ($ComputerWithExcessive)', - target: 'Shares ($ExcessiveSharesCount)', - value: $ExcessiveSharesCount, - color: '#000', // Custom color for this edge - }, - { - source: 'Shares ($ExcessiveSharesCount)', - target: 'ACEs ($ExcessiveSharePrivsCount)', - value: $ExcessiveSharePrivsCount, - color: '#000', // Custom color for this edge - }, - $SanKeyCritical - $SanKeyHigh - $SanKeyMedium - $SanKeyLow - ], -}; - -const graphOptions = { - nodeWidth: 10, - fontFamily: 'Quicksand, sans-serif', - fontSize: '14px', - fontWeight: 400, - fontColor: '#345367', - height: 200, - width: 1200, - spacing: 10, // margin - enableTooltip: true, - canvasStyle: 'border: 0px solid #caced0;', -}; -const s = new ApexSankey(document.getElementById('svg-sankey'), graphOptions); -s.render(SankeyData); - // -------------------------- // side menu collapse function @@ -11116,6 +11385,10 @@ ChartFGRiska.render(); const datanetwork = $subnetChartString; const categoriesnetwork = ['Low','Medium','High','Critical']; +// Reverse the order of the array +datanetwork.reverse(); +categoriesnetwork.reverse(); + const ChartNetworkRiskOptions = { series: [{ data: datanetwork @@ -11323,6 +11596,12 @@ const ChartDashboardIFOptions = { }, xaxis: { categories: categories, + axisTicks: { + show: false + }, + labels: { + show: false // Hide the x-axis labels + } }, colors: ['#f29650','#345367'], // Orange for discovered, Blue for verified title: { @@ -11344,40 +11623,44 @@ const ChartDashboardIFOptions = { const ChartDashboardIF = new ApexCharts(document.querySelector("#ChartDashboardIF"), ChartDashboardIFOptions); ChartDashboardIF.render(); + // -------------------------- // Dashboard Page: Risk Level chart // -------------------------- // Set data series -var DataSeriesComputers = [$RiskLevelComputersCountLow, $RiskLevelComputersCountMedium, $RiskLevelComputersCountHigh, $RiskLevelComputersCountCritical]; -var DataSeriesShares = [$RiskLevelSharePathCountLow, $RiskLevelSharePathCountMedium, $RiskLevelSharePathCountHigh, $RiskLevelSharePathCountCritical]; +var DataSeriesNetwork = [$AllNetworksWithLowCount, $AllNetworksWithMediumCount, $AllNetworksWithHighCount, $AllNetworksWithCriticalCount]; +var DataSeriesComputers = [$AllComputersWithLowCount, $AllComputersWithMediumCount, $AllComputersWithHighCount, $AllComputersWithCriticalCount]; +var DataSeriesShares = [$AllSharesWithLowCount, $AllSharesWithMediumCount, $AllSharesWithHighCount, $AllSharesWithCriticalCount]; var DataSeriesACEs = [$RiskLevelCountLow, $RiskLevelCountMedium, $RiskLevelCountHigh,$RiskLevelCountCritical]; // Reverse each array +DataSeriesNetwork.reverse(); DataSeriesComputers.reverse(); DataSeriesShares.reverse(); DataSeriesACEs.reverse(); // Find max values -var maxComputer = Math.max(...DataSeriesComputers); -var maxShares = Math.max(...DataSeriesShares); -var maxACEs = Math.max(...DataSeriesACEs); -var maxValueOverall = Math.max(maxComputer, maxShares, maxACEs); +var maxNetwork = Math.max(...DataSeriesNetwork); +var maxComputer = Math.max(...DataSeriesComputers); +var maxShares = Math.max(...DataSeriesShares); +var maxACEs = Math.max(...DataSeriesACEs); +var maxValueOverall = Math.max(maxNetwork, maxComputer, maxShares, maxACEs); // Initialize ApexCharts const ChartDashboardRiskOptions = { series: [{ + name: 'Network', + data: DataSeriesNetwork + }, { name: 'Computers', data: DataSeriesComputers - //color: 'blue' // Set color for Computers series - },{ + }, { name: 'Shares', data: DataSeriesShares - //color: 'green' // Set color for Shares series - },{ + }, { name: 'ACEs', data: DataSeriesACEs - //color: 'red' // Set color for ACEs series }], chart: { type: 'bar', @@ -11385,40 +11668,48 @@ const ChartDashboardRiskOptions = { }, plotOptions: { bar: { - borderRadius: 0, - borderRadiusApplication: 'end', horizontal: true, - barHeight: '90%', // Reduce bar height for more space - barGap: '0%', // Adds gap between bars in the same group - // barSpacing: 0.0 // Adds space between the groups (risk levels) + barHeight: '90%', // Reduce bar height for more space + borderWidth: 0 // Remove borders around bars } }, - colors: ['#7D825E', '#f29650', '#345367'], // Colors for the bars + colors: ['#71808D', '#7D825E', '#f29650', '#345367'], // Added a new color for the Network series dataLabels: { enabled: true, + formatter: function (val) { + return val === 0 ? '' : val; // Hide the label if the value is 0 + }, + offsetX: 4, // Move the labels 4px to the right of the bar + textAnchor: 'start', // Ensure the label starts at the end of the bar style: { fontSize: '12px', - colors: ['#345367', '#345367', '#f29650'] // colors for the lables #FF9965 - }, - offsetX: 0 + colors: ['#345367','#345367', '#345367', '#f29650'] // Updated colors for the labels + } }, grid: { - show: false, - opacity: 0.5 + show: false }, xaxis: { - categories: ['Critical','High','Medium','Low'], - max: maxValueOverall, - min: 0 + categories: ['Critical', 'High', 'Medium', 'Low'], + max: maxValueOverall, + labels: { + show: false // Hide the x-axis labels + }, + axisBorder: { + show: true + }, + axisTicks: { + show: false + } }, title: { - text: 'Asset Count by Risk Level', + text: 'Affected Asset Count by Risk Level', align: 'center', margin: 10, style: { - fontSize: '14px', - fontWeight: 'bold', - color: '#71808d' + fontSize: '14px', + fontWeight: 'bold', + color: '#71808d' } } }; @@ -11430,106 +11721,106 @@ ChartDashboardRisk.render(); // Dashboard Page: Chart - Remediation Prioritization // -------------------------- - // Set data series - var DataSeriesAverage = $RemediationBase; - var DataSeriesActual = $RemediationSave; + // Set data series + var DataSeriesAverage = $RemediationBase; + var DataSeriesActual = $RemediationSave; - - // Find max values - var maxValueAverage = Math.max(...DataSeriesAverage); - var maxValueActual = Math.max(...DataSeriesActual); - var maxValueOverall = Math.max(maxValueAverage, maxValueActual); + // Find max values + var maxValueAverage = Math.max(...DataSeriesAverage); + var maxValueActual = Math.max(...DataSeriesActual); + var maxValueOverall = Math.max(maxValueAverage, maxValueActual); - var RemCompareOptions = { - series: [{ - name: 'Affected Shares', - data: DataSeriesAverage - }, { - name: 'Grouping', - data: DataSeriesActual - }], - chart: { - type: 'bar', - height: 250 + var RemCompareOptions = { + series: [{ + name: 'Affected ACEs', + data: DataSeriesAverage + }, { + name: 'Remediation Tasks', + data: DataSeriesActual + }], + chart: { + type: 'bar', + height: 250 + }, + plotOptions: { + bar: { + horizontal: false, + columnWidth: '55%', + endingShape: 'rounded', + dataLabels: { + position: 'top' // Moves the label to the top of the bar + } }, - plotOptions: { - bar: { - horizontal: false, - columnWidth: '55%', - endingShape: 'rounded' - }, + }, + colors: ['#345367', '#f29650'], // Reversed colors for Average and Actual bars + dataLabels: { + enabled: true, // Enable data labels + offsetY: -20, // Move the label 20px above the bar + style: { + fontSize: '12px', + colors: ['#345367', '#345367'], // Colors for labels }, - colors: ['#345367', '#f29650'], // Reversed colors for Average and Actual bars - dataLabels: { - enabled: true, // Enable data labels + formatter: function (val) { + return val; // Append percentage sign to data labels + } + }, + stroke: { + show: true, + width: 2, + colors: ['transparent'] + }, + grid: { + show: false, + opacity: 0.5 + }, + xaxis: { + categories: ['By ACE (Default)', 'By Folder Group (Perfect Match)', 'By Share Name (High Similarity)'], // X-axis categories + labels: { style: { - fontSize: '12px', - colors: ['#f29650', '#345367'], // Colors for labels - }, - formatter: function (val, opts) { - return val; // Display values with percentage sign - }, - offsetY: -6 // Adjust position of the label - }, - stroke: { - show: true, - width: 2, - colors: ['transparent'] - }, - grid: { - show: false, - opacity: 0.5 - }, - xaxis: { - categories: ['Individul ACEs (No Grouping)','Folder Grouping', 'Share Name Grouping (High Similarity)'], // X-axis categories - labels: { - style: { - colors: '#71808d', // Set x-axis labels to gray - } - } - }, - yaxis: { - title: { - text: 'Remediation Tasks', - style: { - fontWeight: 'normal', - color: '#71808d' // Set "Percentage" text to gray - } - }, - labels: { - style: { - colors: '#71808d', // Set y-axis labels to gray - }, - formatter: function (val) { - return val; // Format y-axis labels with percentage sign - } - }, - max: Math.ceil(maxValueOverall * 1.1), - min: 0 - }, - fill: { - opacity: 1 - }, - tooltip: { - y: { - formatter: function (val) { - return val; // Show percentage in tooltip - } + colors: '#71808d' // Set x-axis labels to gray } }, + axisTicks: { + show: false // Hide x-axis ticks + } + }, + yaxis: { title: { - text: 'Remediation Effort by Task Grouping Approach', // Updated chart title - align: 'center', + text: '', // Remediation Tasks style: { - fontSize: '14px', - fontWeight: 'bold', - color: '#71808d' + fontWeight: 'normal', + color: '#71808d' // Set text color to gray + } + }, + labels: { + show: false // Hide y-axis labels + }, + max: Math.ceil(maxValueOverall * 1.1), + min: 0 + }, + fill: { + opacity: 1 + }, + tooltip: { + y: { + formatter: function (val) { + return val + "%"; // Show percentage in tooltip } } - }; + }, + title: { + text: 'Number of Remediation Tasks by Grouping Approach', // Updated chart title + align: 'center', + style: { + fontSize: '14px', + fontWeight: 'bold', + color: '#71808d' + } + } + }; - var RemCompareOptionschart = new ApexCharts(document.querySelector("#ChartDashboardRemediate"), RemCompareOptions); - RemCompareOptionschart.render(); +var RemCompareOptionschart = new ApexCharts(document.querySelector("#ChartDashboardRemediate"), RemCompareOptions); +RemCompareOptionschart.render(); // -------------------------- // Dashboard Page: Chart - Peer Comparison @@ -11537,101 +11828,101 @@ ChartDashboardRisk.render(); // Set data series var DataSeriesAverage = $PeerCompareAverageP; - var DataSeriesActual = $PeerCompareActuaP; + var DataSeriesActual = $PeerCompareActuaP; - - // Find max values - var maxValueAverage = Math.max(...DataSeriesAverage); - var maxValueActual = Math.max(...DataSeriesActual); - var maxValueOverall = Math.max(maxValueAverage, maxValueActual); + // Find max values + var maxValueAverage = Math.max(...DataSeriesAverage); + var maxValueActual = Math.max(...DataSeriesActual); + var maxValueOverall = Math.max(maxValueAverage, maxValueActual); var PeerCompareOptions = { series: [{ - name: 'Peer Average', - data: DataSeriesAverage - }, { - name: 'This Environment', - data: DataSeriesActual - }], + name: 'Peer Average', + data: DataSeriesAverage + }, { + name: 'This Environment', + data: DataSeriesActual + }], chart: { - type: 'bar', - height: 250 - }, - plotOptions: { - bar: { - horizontal: false, - columnWidth: '55%', - endingShape: 'rounded' + type: 'bar', + height: 250 }, - }, - colors: ['#345367', '#f29650'], // Reversed colors for Average and Actual bars - dataLabels: { - enabled: true, // Enable data labels - style: { - fontSize: '12px', - colors: ['#f29650', '#345367'], // Colors for labels + plotOptions: { + bar: { + horizontal: false, + columnWidth: '55%', + endingShape: 'rounded', + dataLabels: { + position: 'top' // Moves the label to the top of the bar + } + }, }, - formatter: function (val, opts) { - return val + '%'; // Display values with percentage sign - }, - offsetY: -6 // Adjust position of the label - }, - grid: { - show: false, - opacity: 0.5 - }, - stroke: { - show: true, - width: 2, - colors: ['transparent'] - }, - xaxis: { - categories: ['Computers', 'Shares', 'ACEs'], // X-axis categories - labels: { - style: { - colors: '#71808d', // Set x-axis labels to gray - } - } - }, - yaxis: { - title: { - text: 'Percentage (%)', + colors: ['#345367', '#f29650'], // Reversed colors for Average and Actual bars + dataLabels: { + enabled: true, + offsetY: -20, // Move the label 10px above the bar style: { fontSize: '12px', - fontWeight: 'normal', - color: '#71808d' // Set "Percentage" text to gray - } - }, - labels: { - style: { - colors: '#71808d', // Set y-axis labels to gray + colors: ['#345367', '#345367'] // Custom colors for labels }, formatter: function (val) { - return val + '%'; // Format y-axis labels with percentage sign + return val + '%'; // Append '%' to the data label } }, - max: Math.ceil(maxValueOverall * 1.1), - min: 0 - }, - fill: { - opacity: 1 - }, - tooltip: { - y: { - formatter: function (val) { - return val + "%"; // Show percentage in tooltip + grid: { + show: false, + opacity: 0.5 + }, + stroke: { + show: true, + width: 2, + colors: ['transparent'] + }, + xaxis: { + categories: ['Computers', 'Shares', 'ACEs'], // X-axis categories + labels: { + style: { + colors: '#71808d' // Set x-axis labels to gray + } + }, + axisTicks: { + show: false // Hide x-axis ticks + } + }, + yaxis: { + title: { + text: '', // Percentage (%) + style: { + fontSize: '12px', + fontWeight: 'normal', + color: '#71808d' // Set "Percentage" text to gray + } + }, + labels: { + show: false // Hide y-axis labels + }, + max: Math.ceil(maxValueOverall * 1.1), + min: 0 + }, + fill: { + opacity: 1 + }, + tooltip: { + y: { + formatter: function (val) { + return val + "%"; // Show percentage in tooltip + } + } + }, + title: { + text: 'Percent of Assets with Excessive Privileges', // Updated chart title - Percent of Assets with Excessive Privileges + align: 'center', + style: { + fontSize: '14px', + fontWeight: 'bold', + color: '#71808d' } } - }, - title: { - text: 'Percent of Assets with Excessive Privileges', // Updated chart title - align: 'center', - style: { - fontSize: '14px', - fontWeight: 'bold', - color: '#71808d' - } - } }; var PeerCompareOptionschart = new ApexCharts(document.querySelector("#ChartDashboardPeerCompare"), PeerCompareOptions);