diff --git a/modules/analyze/analyzeobjects.go b/modules/analyze/analyzeobjects.go index 9754ab9..807185b 100644 --- a/modules/analyze/analyzeobjects.go +++ b/modules/analyze/analyzeobjects.go @@ -15,41 +15,44 @@ var EdgeMemberOfGroup = engine.NewEdge("MemberOfGroup") // Get rid of this func NewAnalyzeObjectsOptions() AnalyzeObjectsOptions { return AnalyzeObjectsOptions{ - MethodsF: engine.AllEdgesBitmap, - MethodsM: engine.AllEdgesBitmap, - MethodsL: engine.AllEdgesBitmap, - Direction: engine.In, - MaxDepth: -1, - MaxOutgoingConnections: -1, - MinProbability: 0, - PruneIslands: false, + MethodsF: engine.AllEdgesBitmap, + MethodsM: engine.AllEdgesBitmap, + MethodsL: engine.AllEdgesBitmap, + Direction: engine.In, + MaxDepth: -1, + MaxOutgoingConnections: -1, + MinEdgeProbability: 0, + MinAccumulatedProbability: 0, + PruneIslands: false, } } type AnalyzeObjectsOptions struct { - Objects *engine.Objects - StartFilter query.NodeFilter - MiddleFilter query.NodeFilter - EndFilter query.NodeFilter - ObjectTypesF []engine.ObjectType - ObjectTypesM []engine.ObjectType - ObjectTypesL []engine.ObjectType - MethodsL engine.EdgeBitmap - MethodsM engine.EdgeBitmap - MethodsF engine.EdgeBitmap - MaxDepth int - MaxOutgoingConnections int - Direction engine.EdgeDirection - Backlinks bool // Full backlinks - Fuzzlevel int // Backlink depth - MinProbability engine.Probability - PruneIslands bool - NodeLimit int + Objects *engine.Objects + StartFilter query.NodeFilter + MiddleFilter query.NodeFilter + EndFilter query.NodeFilter + ObjectTypesF []engine.ObjectType + ObjectTypesM []engine.ObjectType + ObjectTypesL []engine.ObjectType + MethodsL engine.EdgeBitmap + MethodsM engine.EdgeBitmap + MethodsF engine.EdgeBitmap + MaxDepth int + MaxOutgoingConnections int + Direction engine.EdgeDirection + Backlinks bool // Full backlinks + Fuzzlevel int // Backlink depth + MinEdgeProbability engine.Probability + MinAccumulatedProbability engine.Probability + PruneIslands bool + NodeLimit int } type GraphNode struct { - CanExpand int - roundadded int + CanExpand int + roundadded int + accumulatedprobability float32 // 0-1 } type PostProcessorFunc func(pg graph.Graph[*engine.Object, engine.EdgeBitmap]) graph.Graph[*engine.Object, engine.EdgeBitmap] @@ -92,7 +95,8 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults { for o := range pg.Nodes() { if ei, found := extrainfo[o]; !found || ei.roundadded == 0 { extrainfo[o] = (&GraphNode{ - roundadded: processinground, + roundadded: processinground, + accumulatedprobability: 1, }) } } @@ -157,13 +161,21 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults { } } + // Edge probability var maxprobability engine.Probability if opts.Direction == engine.In { maxprobability = detectededges.MaxProbability(nextobject, currentobject) } else { maxprobability = detectededges.MaxProbability(currentobject, nextobject) } - if maxprobability < engine.Probability(opts.MinProbability) { + if maxprobability < engine.Probability(opts.MinEdgeProbability) { + // Too unlikeliy, so we skip it + return true // continue + } + + // Accumulated node probability + accumulatedprobability := ei.accumulatedprobability * float32(maxprobability) / 100 + if accumulatedprobability < float32(opts.MinAccumulatedProbability)/100 { // Too unlikeliy, so we skip it return true // continue } @@ -205,6 +217,11 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults { Target: nextobject}] = detectededges } + extrainfo[nextobject] = &GraphNode{ + roundadded: processinground + 1, + accumulatedprobability: ei.accumulatedprobability * float32(maxprobability) / 100, + } + return true }) @@ -285,13 +302,6 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults { } processinground++ - for o := range pg.Nodes() { - if ei, found := extrainfo[o]; !found || ei.roundadded == 0 { - extrainfo[o] = (&GraphNode{ - roundadded: processinground, - }) - } - } } pb.Finish() diff --git a/modules/analyze/html/custom.js b/modules/analyze/html/custom.js index 593d0d2..9c16514 100644 --- a/modules/analyze/html/custom.js +++ b/modules/analyze/html/custom.js @@ -335,6 +335,23 @@ function refreshStatus() { setTimeout(refreshStatus, 1000); } +function toast(title, contents) { + toastcontent = $(``); + $("#toasts").append(toastcontent); + const toast = bootstrap.Toast.getOrCreateInstance(toastcontent); + toast.show(); +} + // When we´re ready ... $(function () { // Initial GUI setup diff --git a/modules/analyze/html/graph.js b/modules/analyze/html/graph.js index eae725d..9ae9ebd 100644 --- a/modules/analyze/html/graph.js +++ b/modules/analyze/html/graph.js @@ -274,7 +274,7 @@ cytostyle = [{ "min-zoomed-font-size": 12, "font-family": "oswald", } -},{ +}, { selector: "node", style: { "label": function (ele) { return nodelabel(ele); }, @@ -326,13 +326,13 @@ cytostyle = [{ "background-color": "lightgreen" } }, - { - selector: 'node[type="GroupManagedServiceAccount"]', - style: { - "background-image": "icons/manage_accounts_black_24dp.svg", - "background-color": "lightgreen" - } - }, +{ + selector: 'node[type="GroupManagedServiceAccount"]', + style: { + "background-image": "icons/manage_accounts_black_24dp.svg", + "background-color": "lightgreen" + } +}, { selector: 'node[type="ForeignSecurityPrincipal"]', style: { @@ -364,14 +364,14 @@ cytostyle = [{ "background-color": "lightblue" } }, - { - selector: 'node[type="Executable"]', - style: { - shape: "rectangle", - "background-image": "icons/binary-code-binary-svgrepo-com.svg", - "background-color": "lightgreen" - } - }, +{ + selector: 'node[type="Executable"]', + style: { + shape: "rectangle", + "background-image": "icons/binary-code-binary-svgrepo-com.svg", + "background-color": "lightgreen" + } +}, { selector: 'node[type="GroupPolicyContainer"]', @@ -636,8 +636,163 @@ function rendermethods(ele) { } function rendernode(ele) { - var s = '
' + nodelabel(ele); - if (ele.data("engine.SAMAccountName")) s += ' (' + ele.data("engine.SAMAccountName") + ')'; + var s = '
'; + + switch (ele.data("type")) { + case "User": + // selector: 'node[type="User"][!_disabled]', + // style: { + // "background-image": "icons/person-fill.svg", + // "background-color": "green" + // } + // selector: 'node[type="User"][?_disabled]', + // style: { + // "background-image": "icons/no_accounts_black_48dp.svg", + // "background-color": "darkgreen" + // } + s += ''; + break; + case "Group": + // selector: 'node[type="Group"]', + // style: { + // shape: "cut-rectangle", + // "background-image": "icons/people-fill.svg", + // "background-color": "orange" + // } + s += ''; + break; + case "ManagedServiceAccount": + // selector: 'node[type="ManagedServiceAccount"]', + // style: { + // "background-image": "icons/manage_accounts_black_24dp.svg", + // "background-color": "lightgreen" + // } + s += ''; + break; + case "GroupManagedServiceAccount": + // selector: 'node[type="GroupManagedServiceAccount"]', + // style: { + // "background-image": "icons/manage_accounts_black_24dp.svg", + // "background-color": "lightgreen" + // } + s += ''; + break; + case "ForeignSecurityPrincipal": + // selector: 'node[type="ForeignSecurityPrincipal"]', + // style: { + // "background-image": "icons/badge_black_24dp.svg", + // "background-color": "lightgreen" + // } + s += ''; + break; + case "Service": + // selector: 'node[type="Service"]', + // style: { + // shape: "diamond", + // "background-image": "icons/service.svg", + // "background-color": "lightgreen" + // } + s += ''; + break; + case "Directory": + // selector: 'node[type="Directory"]', + // style: { + // shape: "diamond", + // "background-image": "icons/source_black_24dp.svg", + // "background-color": "lightblue" + // } + s += ''; + break; + case "File": + // selector: 'node[type="File"]', + // style: { + // shape: "diamond", + // "background-image": "icons/article_black_24dp.svg", + // "background-color": "lightblue" + // } + s += ''; + break; + case "Executable": + // selector: 'node[type="Executable"]', + // style: { + // shape: "rectangle", + // "background-image": "icons/binary-code-binary-svgrepo-com.svg", + // "background-color": "lightgreen" + // } + s += ''; + break; + case "GroupPolicyContainer": + // selector: 'node[type="GroupPolicyContainer"]', + // style: { + // shape: "rectangle", + // "background-image": "icons/gpo.svg", + // "background-color": "purple" + // } + s += ''; + break; + case "OrganizationalUnit": + // selector: 'node[type="OrganizationalUnit"]', + // style: { + // shape: "rectangle", + // "background-image": "icons/source_black_24dp.svg", + // "background-color": "lightgray" + // } + s += ''; + break; + case "Container": + // selector: 'node[type="Container"]', + // style: { + // shape: "rectangle", + // "background-image": "icons/folder_black_24dp.svg", + // "background-color": "lightgray" + // } + s += ''; + break; + + case "CertificateTemplate": + // selector: 'node[type="CertificateTemplate"]', + // style: { + // shape: "rectangle", + // "background-image": "icons/certificate.svg", + // "background-color": "pink" + // } + s += ''; + break; + case "DNSNode": + // selector: 'node[type="DNSNode"]', + // style: { + // shape: "rectangle", + // "background-image": "icons/dns.svg", + // } + s += ''; + break; + case "Computer": + // selector: 'node[type="Computer"]', + // style: { + // shape: "round-octagon", + // "background-image": "icons/tv-fill.svg", + // "background-color": "lightgreen" + // } + s += ''; + break; + case "Machine": + // selector: 'node[type="Machine"]', + // style: { + // shape: "round-octagon", + // "background-image": "icons/tv-fill.svg", + // "background-color": "teal" + // } + s += ''; + break; + } + + + s += nodelabel(ele); + if (ele.data("engine.downLevelLogonName")) { + s += ' (' + ele.data("engine.downLevelLogonName") + ')'; + } else if (ele.data("engine.SAMAccountName")) { + s += ' (' + ele.data("engine.SAMAccountName") + ')'; + } s += '
'; if (ele.data("distinguishedName")) s += '
' + ele.data("distinguishedName") + '
'; return s @@ -777,14 +932,7 @@ function initgraph(data) { analyze(); }, error: function (xhr, status, error) { - halfmoon.initStickyAlert({ - content: "There was a problem doing node lookup in the backend", - title: "Node not found in backend", - alertType: "alert-danger", - fillType: "filled", - hasDismissButton: true, - timeShown: 5000 - }); + toast("Node not found in backend", "There was a problem doing node lookup in the backend."); } }) } @@ -814,14 +962,7 @@ function initgraph(data) { analyze(); }, error: function (xhr, status, error) { - halfmoon.initStickyAlert({ - content: "There was a problem doing node lookup in the backend", - title: "Node not found in backend", - alertType: "alert-danger", - fillType: "filled", - hasDismissButton: true, - timeShown: 5000 - }); + toast("Node not found in backend", "There was a problem doing node lookup in the backend."); } }) }, @@ -887,7 +1028,7 @@ function initgraph(data) { // tip.show(); // this.tippy = tip; }); - + cy.on('mouseout', 'edge', function (event) { this.css({ content: '' @@ -898,7 +1039,7 @@ function initgraph(data) { // tip.destroy(); // } }); - + // cy.on('zoom', function () { // zoom = cy.zoom(); // console.log(zoom); @@ -965,7 +1106,7 @@ function applyNodeStyles(cy) { scale = cy.nodes().maxOutdegree(false) break; } - + // Apply node styles cy.nodes().each(function (ele) { var size @@ -1028,13 +1169,6 @@ function findroute(source) { `Route from ` + nodelabel(source) + ` to ` + nodelabel(target) + ` - ` + pathprobability.toFixed(2) + `% probability`, routecontents) } else { - halfmoon.initStickyAlert({ - content: "If your analysis was for multiple target nodes, there is no guarantee that all results can reach all targets.", - title: "No route found", - alertType: "alert-danger", - fillType: "filled", - hasDismissButton: true, - timeShown: 5000 - }); + toast("No route found", "If your analysis was for multiple target nodes, there is no guarantee that all results can reach all targets."); } } diff --git a/modules/analyze/html/index.html b/modules/analyze/html/index.html index 3f61ae7..5140f02 100644 --- a/modules/analyze/html/index.html +++ b/modules/analyze/html/index.html @@ -86,6 +86,9 @@
+ +
+