Skip to content

Commit

Permalink
Tooltips, don't expand AU / EO option, iterator for Graph edges, back…
Browse files Browse the repository at this point in the history
…links fuzz implemented but not enabled in WebUI (causes chaos), graph edge can have data attached
  • Loading branch information
lkarlslund committed Nov 28, 2023
1 parent 12d1a63 commit 68846c0
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 53 deletions.
36 changes: 21 additions & 15 deletions modules/analyze/analyzeobjects.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/lkarlslund/adalanche/modules/graph"
"github.com/lkarlslund/adalanche/modules/query"
"github.com/lkarlslund/adalanche/modules/ui"
"github.com/lkarlslund/adalanche/modules/windowssecurity"
)

var SortBy engine.Attribute = engine.NonExistingAttribute
Expand All @@ -24,6 +25,7 @@ func NewAnalyzeObjectsOptions() AnalyzeObjectsOptions {
MinEdgeProbability: 0,
MinAccumulatedProbability: 0,
PruneIslands: false,
DontExpandAUEO: true,
}
}

Expand All @@ -41,12 +43,12 @@ type AnalyzeObjectsOptions struct {
MaxDepth int
MaxOutgoingConnections int
Direction engine.EdgeDirection
Backlinks bool // Full backlinks
Fuzzlevel int // Backlink depth
Backlinks int // Backlink depth
MinEdgeProbability engine.Probability
MinAccumulatedProbability engine.Probability
PruneIslands bool
NodeLimit int
DontExpandAUEO bool
}

type GraphNode struct {
Expand Down Expand Up @@ -90,7 +92,7 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults {
// Convert to our working graph
processinground := 1
query.Execute(opts.StartFilter, opts.Objects).Iterate(func(o *engine.Object) bool {
pg.Set(o, "target", true)
pg.SetNodeData(o, "target", true)

for o := range pg.Nodes() {
if ei, found := extrainfo[o]; !found || ei.roundadded == 0 {
Expand Down Expand Up @@ -144,6 +146,11 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults {

newconnectionsmap := make(map[graph.NodePair[*engine.Object]]engine.EdgeBitmap) // Pwn Connection between objects

if opts.Direction == engine.In && opts.DontExpandAUEO && (currentobject.SID() == windowssecurity.EveryoneSID || currentobject.SID() == windowssecurity.AuthenticatedUsersSID) {
// Don't expand Authenticated Users or Everyone
continue
}

// Iterate over ever edges
currentobject.Edges(opts.Direction).Range(func(nextobject *engine.Object, eb engine.EdgeBitmap) bool {
// If this is not a chosen edge, skip it
Expand Down Expand Up @@ -189,13 +196,11 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults {
// SKIP THIS IF
if
// We're not including backlinks
!opts.Backlinks &&
// It's found
found &&
found &&
// This is not the first round
processinground > 1 &&
// It was found in an earlier round
extrainfo[nextobject] != nil && extrainfo[nextobject].roundadded+opts.Fuzzlevel <= processinground &&
extrainfo[nextobject] != nil && extrainfo[nextobject].roundadded+opts.Backlinks <= processinground &&
// If SIDs match between objects, it's a cross forest/domain link and we want to see it
(currentobject.SID().IsNull() || nextobject.SID().IsNull() || currentobject.SID().Component(2) != 21 || currentobject.SID() != nextobject.SID()) {
// skip it
Expand Down Expand Up @@ -339,12 +344,12 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults {
outernodemap[outernode] = struct{}{}
}

for pair, endedge := range pg.Edges() {
pg.IterateEdges(func(source, target *engine.Object, endedge engine.EdgeBitmap) bool {
var endnode *engine.Object
if opts.Direction == engine.In {
endnode = pair.Source
endnode = source
} else {
endnode = pair.Target
endnode = target
}
if _, found := outernodemap[endnode]; found {
// Outer node
Expand All @@ -353,26 +358,27 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults {
pg.DeleteNode(endnode)
pb.Add(1)
removed++
continue
return true
}
if detectobjecttypes != nil {
if _, found := detectobjecttypes[endnode.Type()]; !found {
// No matches on LastMethods
pg.DeleteNode(endnode)
pb.Add(1)
removed++
continue
return true
}
}
if opts.EndFilter != nil && !opts.EndFilter.Evaluate(endnode) {
// does it exist in the exclude last list
pg.DeleteNode(endnode)
pb.Add(1)
removed++
continue
return true
}
}
}
return true
})

if removed == 0 {
break
Expand Down Expand Up @@ -449,7 +455,7 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) AnalysisResults {
pg.Nodes() // Trigger cleanup, important otherwise they get readded below
for eo, ei := range extrainfo {
if pg.HasNode(eo) && ei.CanExpand > 0 {
pg.Set(eo, "canexpand", ei.CanExpand)
pg.SetNodeData(eo, "canexpand", ei.CanExpand)
}
}

Expand Down
21 changes: 12 additions & 9 deletions modules/analyze/export-graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ func ExportGraphViz(pg graph.Graph[*engine.Object, engine.EdgeBitmap], filename
fmt.Fprintf(df, " \"%v\" [label=\"%v\";%v];\n", object.ID(), object.OneAttr(activedirectory.Name), formatting)
}
fmt.Fprintln(df, "")
for connection, edge := range pg.Edges() {
fmt.Fprintf(df, " \"%v\" -> \"%v\" [label=\"%v\"];\n", connection.Source, connection.Target, edge.JoinedString())
}

pg.IterateEdges(func(source, target *engine.Object, edge engine.EdgeBitmap) bool {
fmt.Fprintf(df, " \"%v\" -> \"%v\" [label=\"%v\"];\n", source, target, edge.JoinedString())
return true
})
fmt.Fprintln(df, "}")

return nil
Expand Down Expand Up @@ -122,27 +124,28 @@ func GenerateCytoscapeJS(pg graph.Graph[*engine.Object, engine.EdgeBitmap], alld
i++
}

for connection, edge := range pg.Edges() {
pg.IterateEdges(func(source, target *engine.Object, edge engine.EdgeBitmap) bool {
cytoedge := CytoFlatElement{
Group: "edges",
Data: MapStringInterface{
"id": fmt.Sprintf("e%v-%v", connection.Source.ID(), connection.Target.ID()),
"source": fmt.Sprintf("n%v", connection.Source.ID()),
"target": fmt.Sprintf("n%v", connection.Target.ID()),
"id": fmt.Sprintf("e%v-%v", source.ID(), target.ID()),
"source": fmt.Sprintf("n%v", source.ID()),
"target": fmt.Sprintf("n%v", target.ID()),
},
}

// for key, value := range edge.DynamicFields {
// cytoedge.Data[key] = value
// }

cytoedge.Data["_maxprob"] = edge.MaxProbability(connection.Source, connection.Target)
cytoedge.Data["_maxprob"] = edge.MaxProbability(source, target)
cytoedge.Data["methods"] = edge.StringSlice()

g.Elements[i] = cytoedge

i++
}
return true
})

return g, nil
}
Expand Down
10 changes: 9 additions & 1 deletion modules/analyze/html/custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,11 @@ function analyze(e) {
for (var objecttype in data.resulttypes) {
info += '<tr><td class="text-right pr-5">'+ data.resulttypes[objecttype] + '</td><td>' + objecttype + '</td></tr>';
}
info += '<tr><td class="text-right pr-5">' + data.total + '</td><td>total nodes in analysis</td></tr></table>';
info += '<tr><td class="text-right pr-5">' + data.total + '</td><td>total nodes in analysis</td></tr>';
if (data.removed>0) {
info += '<tr><td class="text-right pr-5"><b>' + data.removed + '</b></td><td><b>nodes were removed by node limiter</b></td></tr>';
}
info += '</table>';

newwindow('results', 'Query results', info);

Expand Down Expand Up @@ -363,6 +367,10 @@ $(function () {
$('#optionspanel').animate({ width: 'toggle' }, 400);
});

$("[data-bs-toggle='tooltip']").each(function () {
new bootstrap.Tooltip($(this));
});

// autosize($('#querytext'));

$('#explore').on('click', function () {
Expand Down
37 changes: 25 additions & 12 deletions modules/analyze/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,12 @@
<div class="form-check">
<input class="form-check-input" id="prune" type="checkbox" name="prune" autocomplete="off"
preference="analysis.prune.islands" defaultpref=false>
<label class="form-check-label" for="prune">Prune Island Nodes</label>
</div>

<div class="form-check">
<input class="form-check-input" id="backlinks" type="checkbox" name="backlinks" autocomplete="off"
preference="analysis.include.backlinks" defaultpref=false>
<label class="form-check-label" for="backlinks">Include backlinks</label>
<label class="form-check-label" for="prune" data-bs-toggle='tooltip' data-bs-title='Remove nodes that are not connected to anything'>Prune Island Nodes</label>
</div>

<div class="row">
<div class="col">
<label for="nodelimit" class="col-form-label">Node limit</label>
<label for="nodelimit" class="col-form-label" data-bs-toggle='tooltip' data-bs-title='In order to prevent browser crashes, you should probably keep this under 2500'>Node limit</label>
</div>
<div class="col">
<input id="nodelimit" type="number" name="nodelimit" min="100" max="5000" value="2000"
Expand All @@ -146,7 +140,7 @@

<div class="row">
<div class="col">
<label for="maxdepth" class="col-form-label">Analysis depth</label>
<label for="maxdepth" class="col-form-label" data-bs-toggle='tooltip' data-bs-title='How many steps away from the targets should be searched'>Analysis depth</label>
</div>
<div class="col">
<input id="maxdepth" type="number" name="maxdepth" min="0" max="99" value="99"
Expand All @@ -156,7 +150,7 @@

<div class="row">
<div class="col">
<label for="maxoutgoing" class="col-form-label">Max outgoing</label>
<label for="maxoutgoing" class="col-form-label" data-bs-toggle='tooltip' data-bs-title='If a node has more than this amount of edges, drop some of them to keep output less cluttered (you will lose some insights)'>Max outgoing edges</label>
</div>
<div class="col">
<input id="maxoutgoing" type="number" name="maxoutgoing" min="0" max="5000" value="50"
Expand All @@ -166,7 +160,7 @@

<div class="row">
<div class="col">
<label for="minprobability" class="col-form-label">Min edge probability %</label>
<label for="minprobability" class="col-form-label" data-bs-toggle='tooltip' data-bs-title='The minimum probability for an edge to be included, 0 for all edges even just informative ones'>Min edge probability %</label>
</div>
<div class="col">
<input id="minprobability" type="number" length=3 name="minprobability" min="0" max="100" value="0"
Expand All @@ -176,13 +170,32 @@

<div class="row">
<div class="col">
<label for="minaccprobability" class="col-form-label">Min accumulated probability %</label>
<label for="minaccprobability" class="col-form-label" data-bs-toggle='tooltip' data-bs-title='The minimum accumulated probability for an edge to be included, eg. two steps with 50% and 50% will give an accumulated probability of 25%'>Min accumulated probability %</label>
</div>
<div class="col">
<input id="minaccprobability" type="number" size=3 name="minaccprobability" min="0" max="100" value="0"
preference="analysis.min.accumulated.probability" class="form-control text-right">
</div>
</div>

<!-- <div class="row">
<div class="col">
<label for="backlinks" class="col-form-label" data-bs-toggle='tooltip'
data-bs-title='The number of backlinks to include, recommended to keep this 0 to avoid unneccessary clutter'>Backlink steps</label>
</div>
<div class="col">
<input id="backlinks" type="number" size=3 name="backlinks" min="0" max="100" value="0"
preference="analysis.backlink.count" class="form-control text-right">
</div>
</div> -->

<div class="form-check">
<input class="form-check-input" id="dont-expand-au-eo" type="checkbox" name="dont-expand-au-eo" autocomplete="off"
preference="analysis.dontexpandaueo" defaultpref=true>
<label class="form-check-label" for="dont-expand-au-eo" data-bs-toggle='tooltip'
data-bs-title='Expanding these groups usually gives an unreasonable amount of data in the graph'>Don't expand "Domain Users" / "Everyone"</label>
</div>

</div>

</form>
Expand Down
9 changes: 7 additions & 2 deletions modules/analyze/webservicefuncs.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,13 @@ func analysisfuncs(ws *webservice) {

alldetails, _ := util.ParseBool(vars["alldetails"])
// force, _ := util.ParseBool(vars["force"])
backlinks, _ := util.ParseBool(vars["backlinks"])

backlinks, _ := strconv.Atoi(vars["backlinks"])

nodelimit, _ := strconv.Atoi(vars["nodelimit"])

dontexpandaueo, _ := util.ParseBool(vars["dont-expand-au-eo"])

opts := NewAnalyzeObjectsOptions()

// tricky tricky - if we get a call with the expanddn set, then we handle things .... differently :-)
Expand Down Expand Up @@ -332,6 +336,7 @@ func analysisfuncs(ws *webservice) {
opts.PruneIslands = prune
opts.Backlinks = backlinks
opts.NodeLimit = nodelimit
opts.DontExpandAUEO = dontexpandaueo
results := AnalyzeObjects(opts)

for _, postprocessor := range PostProcessors {
Expand All @@ -342,7 +347,7 @@ func analysisfuncs(ws *webservice) {
var objecttypes [256]int

for node := range results.Graph.Nodes() {
if results.Graph.Get(node, "target") == true {
if results.Graph.GetNodeData(node, "target") == true {
targets++
continue
}
Expand Down
Loading

0 comments on commit 68846c0

Please sign in to comment.