diff --git a/Scripts/Analyze-HuntSMBShares.ps1 b/Scripts/Analyze-HuntSMBShares.ps1 index 56f9314..3fa68a7 100644 --- a/Scripts/Analyze-HuntSMBShares.ps1 +++ b/Scripts/Analyze-HuntSMBShares.ps1 @@ -5,7 +5,7 @@ #-------------------------------------- # Author: Scott Sutherland, 2024 NetSPI # License: 3-clause BSD -# Version: v1.76 +# Version: v1.80 # References: This script includes custom code and code taken and modified from the open source projects PowerView, Invoke-Ping, and Invoke-Parrell. function Analyze-HuntSMBShares { @@ -1939,6 +1939,7 @@ function Analyze-HuntSMBShares # ---------------------------------------------------------------------- # Create Folder Group Summary Information # ---------------------------------------------------------------------- + $RiskLevelFolderGroupCountCritical = 0 $RiskLevelFolderGroupCountHigh = 0 $RiskLevelFolderGroupCountMedium = 0 @@ -1964,7 +1965,102 @@ function Analyze-HuntSMBShares if($RiskLevelFileListGroupResult -eq "Medium" ){$RiskLevelFolderGroupCountMedium = $RiskLevelFolderGroupCountMedium + 1} if($RiskLevelFileListGroupResult -eq "High" ){$RiskLevelFolderGroupCountHigh = $RiskLevelFolderGroupCountHigh + 1} if($RiskLevelFileListGroupResult -eq "Critical"){$RiskLevelFolderGroupCountCritical = $RiskLevelFolderGroupCountCritical + 1} - } + } + + # ---------------------------------------------------------------------- + # Create ShareGraph Nodes and Edges + # ---------------------------------------------------------------------- + $Time = Get-Date -UFormat "%m/%d/%Y %R" + Write-Output " [*][$Time] Creating ShareGraph nodes and edges..." + + # Create hashsets to track added nodes and edges + $addedNodes = @{} + $addedEdges = @{} + + # Iterate through each row in the CSV + foreach ($row in $ExcessiveSharePrivsFinal) { + + # Replace single backslashes with double backslashes for SharePath, ShareName, ShareOwner, and IdentityReference + $escapedSharePath = $row.SharePath -replace '\\', '\\' + $escapedShareName = $row.ShareName -replace '\\', '\\' + $escapedShareOwner = $row.ShareOwner -replace '\\', '\\' + $escapedIdentityReference = $row.IdentityReference -replace '\\', '\\' + + # Create and add nodes if they don't exist + $ownerNode = "{ data: { id: '$escapedShareOwner', label: '$escapedShareOwner', type: 'owner', IdentitySID: '$($row.IdentitySID)' } }," + if (-not $addedNodes.ContainsKey($escapedShareOwner)) { + $ShareGraphNodes += $ownerNode + $addedNodes[$escapedShareOwner] = $true + } + + $userNode = "{ data: { id: '$escapedIdentityReference', label: '$escapedIdentityReference', type: 'user', IdentitySID: '$($row.IdentitySID)' } }," + if (-not $addedNodes.ContainsKey($escapedIdentityReference)) { + $ShareGraphNodes += $userNode + $addedNodes[$escapedIdentityReference] = $true + } + + $computerNode = "{ data: { id: '$($row.ComputerName)', label: '$($row.ComputerName)', type: 'computer', ipaddress: '$($row.IpAddress)' } }," + if (-not $addedNodes.ContainsKey($row.ComputerName)) { + $ShareGraphNodes += $computerNode + $addedNodes[$row.ComputerName] = $true + } + + $folderGroupNode = "{ data: { id: '$($row.FileListGroup)', label: '$($row.FileListGroup)', type: 'Folder Group' } }," + if (-not $addedNodes.ContainsKey($row.FileListGroup)) { + $ShareGraphNodes += $folderGroupNode + $addedNodes[$row.FileListGroup] = $true + } + + # Check if the ShareName node already exists + if (-not $addedNodes.ContainsKey($escapedShareName)) { + $shareNameNode = "{ data: { id: '$escapedShareName', label: '$escapedShareName', type: 'sharename' } }," + $ShareGraphNodes += $shareNameNode + $addedNodes[$escapedShareName] = $true + } + + # Check if SharePath node already exists + if (-not $addedNodes.ContainsKey($escapedSharePath)) { + $sharePathNode = "{ data: { id: '$escapedSharePath', label: '$escapedSharePath', type: 'sharepath', RiskLevel: '$($row.RiskLevel)', RiskScore: '$($row.RiskScore)', creationDate: '$($row.CreationDate)', lastModifiedDate: '$($row.LastModifiedDate)', fileCount: $($row.FileCount), owner: '$escapedShareOwner', IsDefault: '$($row.IsDefault)', IsEmpty: '$($row.IsEmpty)', IsStale: '$($row.IsStale)', IsHR: '$($row.HasHR)', HasWrite: '$($row.HasWrite)', HasRead: '$($row.HasRead)', HasRCE: '$($row.HasRCE)', InterestingFiles: '$($row.HasIF)', ShareName: '$escapedShareName', ShareDescription: '$($row.ShareDescription)' } }," + $ShareGraphNodes += $sharePathNode + $addedNodes[$escapedSharePath] = $true + } + + # Ensure the edge between ShareName and SharePath exists + $shareNameEdge = "{ data: { source: '$escapedShareName', target: '$escapedSharePath', label: 'child_of' } }," + if (-not $addedEdges.ContainsKey("child_of_$escapedShareName_$escapedSharePath")) { + $ShareGraphEdges += $shareNameEdge + $addedEdges["child_of_$escapedShareName_$escapedSharePath"] = $true + } + + # Create and add other edges if they don't exist + $ownerEdge = "{ data: { source: '$escapedShareOwner', target: '$escapedSharePath', label: 'owner_of' } }," + if (-not $addedEdges.ContainsKey("owner_of_$escapedShareOwner_$escapedSharePath")) { + $ShareGraphEdges += $ownerEdge + $addedEdges["owner_of_$escapedShareOwner_$escapedSharePath"] = $true + } + + $privilegeEdge = "{ data: { source: '$escapedIdentityReference', target: '$escapedSharePath', label: 'has_privilege_on', filesystemrights: '$($row.FileSystemRights)' } }," + if (-not $addedEdges.ContainsKey("has_privilege_on_$escapedIdentityReference_$escapedSharePath")) { + $ShareGraphEdges += $privilegeEdge + $addedEdges["has_privilege_on_$escapedIdentityReference_$escapedSharePath"] = $true + } + + $folderGroupEdge = "{ data: { source: '$($row.FileListGroup)', target: '$escapedSharePath', label: 'hosted_on' } }," + if (-not $addedEdges.ContainsKey("hosted_on_$($row.FileListGroup)_$escapedSharePath")) { + $ShareGraphEdges += $folderGroupEdge + $addedEdges["hosted_on_$($row.FileListGroup)_$escapedSharePath"] = $true + } + + $computerEdge = "{ data: { source: '$escapedSharePath', target: '$($row.ComputerName)', label: 'hosted_on' } }," + if (-not $addedEdges.ContainsKey("hosted_on_$escapedSharePath_$($row.ComputerName)")) { + $ShareGraphEdges += $computerEdge + $addedEdges["hosted_on_$escapedSharePath_$($row.ComputerName)"] = $true + } + } + + # Reference $ShareGraphNodesFinal and $ShareGraphEdgesFinal in Cytoscape JavaScript + $ShareGraphNodesFinal = $ShareGraphNodes | select -Unique + $ShareGraphEdgesFinal = $ShareGraphEdges | select -Unique # ---------------------------------------------------------------------- # Create Timeline Reports @@ -3306,8 +3402,192 @@ $NewHtmlReport = @" + + + + + + + Report