Skip to content

Commit

Permalink
Split include and exclude queries up in seperate input fields, and al…
Browse files Browse the repository at this point in the history
…so add an option to exclude last objects by query
  • Loading branch information
lkarlslund committed Nov 15, 2023
1 parent 07ea98c commit de79909
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 40 deletions.
6 changes: 3 additions & 3 deletions modules/analyze/html/custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ function analyze(e) {

$.ajax({
type: 'POST',
url: 'cytograph.json',
url: 'analyzegraph',
contentType: 'charset=utf-8',
data: JSON.stringify(
$('#queryform, #analysisoptionsform, #analysispwnform, #analysistypeform')
Expand Down Expand Up @@ -423,15 +423,15 @@ $(function () {
// $('[data-toggle="tooltip"]').tooltip()

var changetimer;
$('#querytext').on('input', function () {
$('#querytext, #queryexclude, #queryexcludelast').on('input', function (e) {
clearTimeout(changetimer);
changetimer = setTimeout(function () {
// check query for errors when user has been idle for 200ms
$.ajax({
type: 'GET',
url: '/validatequery',
data: {
query: $('#querytext').val(),
query: e.target.value,
},
success: function (data) {
console.log(data);
Expand Down
28 changes: 23 additions & 5 deletions modules/analyze/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,30 @@

<div id="outerquery" class="card border mb-0 mt-0 p-0 pe-auto z-10">
<div id="querypop" class="text-center ps-4 pe-4">LDAP Query</div>
<div id="querydiv" class="p-1">
<div id="querydiv" class="p-1" style="width: 40vw;">
<form id="queryform" class="m-0">
<textarea id="querytext" class="form-control mb-1" style="width: 300px" name="query" rows=4></textarea>
<!-- <textarea id="queryinclude" class="form-control w-300 mb-1" name="queryinclude" rows=4></textarea> -->
<!-- <textarea id="queryexclude" class="form-control w-300 mb-1" name="queryexclude" rows=4></textarea> -->
<!-- <textarea id="queryexcludelast" class="form-control w-300 mb-1" name="queryexcludelast" rows=4></textarea> -->
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button id="querybutton" class="nav-link active" data-bs-toggle="tab" data-bs-target="#query-pane" type="button">Query</button>
</li>
<li class="nav-item" role="presentation">
<button id="queryexcludebutton" class="nav-link" data-bs-toggle="tab" data-bs-target="#queryexclude-pane" type="button">Exclude</button>
</li>
<li class="nav-item" role="presentation">
<button id="queryexcludelastbutton" class="nav-link" data-bs-toggle="tab" data-bs-target="#queryexcludelast-pane" type="button">Exclude Last</button>
</li>
</ul>
<div class="tab-content" id="query-tabs-content">
<div class="tab-pane active" id="query-pane">
<textarea id="querytext" class="form-control mb-1" name="query" rows=4></textarea>
</div>
<div class="tab-pane" id="queryexclude-pane">
<textarea id="queryexclude" class="form-control mb-1" name="queryexclude" rows=4></textarea>
</div>
<div class="tab-pane" id="queryexcludelast-pane">
<textarea id="queryexcludelast" class="form-control mb-1" name="queryexcludelast" rows=4></textarea>
</div>
</div>
<div id="queryerror"></div>
<div id="querybuttons" class="mt-2">
<div id="queriesdropdown" class="dropup float-start">
Expand Down
65 changes: 35 additions & 30 deletions modules/analyze/webservicefuncs.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,26 +68,18 @@ func analysisfuncs(ws *webservice) {
// Checks a LDAP style query for input errors, and returns a hint to the user
// It supports the include,exclude syntax specific to this program
ws.Router.HandleFunc("/validatequery", func(w http.ResponseWriter, r *http.Request) {
rest, _, err := query.ParseLDAPQuery(r.URL.Query().Get("query"), ws.Objs)
if err != nil {
w.WriteHeader(400) // bad request
w.Write([]byte(err.Error()))
return
}
if rest != "" {
if rest[0] != ',' {
w.WriteHeader(400) // bad request
w.Write([]byte("Expecting comma as a seperator before exclude query"))
return
}
if _, err := query.ParseLDAPQueryStrict(rest[1:], ws.Objs); err != nil {
querytext := strings.Trim(r.URL.Query().Get("query"), " \n\r")
if querytext != "" {
_, err := query.ParseLDAPQueryStrict(querytext, ws.Objs)
if err != nil {
w.WriteHeader(400) // bad request
w.Write([]byte(err.Error()))
return
}
}
w.Write([]byte("ok"))
})

// Returns JSON descruibing an object located by distinguishedName, sid or guid
ws.Router.HandleFunc("/details/{locateby}/{id}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
Expand Down Expand Up @@ -173,8 +165,9 @@ func analysisfuncs(ws *webservice) {
}
// w.WriteHeader(200)
})

// Graph based query analysis - core functionality
ws.Router.HandleFunc("/cytograph.json", func(w http.ResponseWriter, r *http.Request) {
ws.Router.HandleFunc("/analyzegraph", func(w http.ResponseWriter, r *http.Request) {
vars := make(map[string]string)
err := json.NewDecoder(r.Body).Decode(&vars)
if err != nil {
Expand All @@ -194,11 +187,14 @@ func analysisfuncs(ws *webservice) {

prune, _ := util.ParseBool(vars["prune"])

querystr := vars["query"]
if querystr == "" {
querystr = "(&(objectClass=group)(|(name=Domain Admins)(name=Enterprise Admins)))"
queryinclude := vars["query"]
if queryinclude == "" {
queryinclude = "(&(objectClass=group)(|(name=Domain Admins)(name=Enterprise Admins)))"
}

queryexclude := vars["queryexclude"]
queryexcludelast := vars["queryexcludelast"]

maxdepth := 99
if maxdepthval, err := strconv.Atoi(vars["maxdepth"]); err == nil {
maxdepth = maxdepthval
Expand All @@ -220,14 +216,12 @@ func analysisfuncs(ws *webservice) {
force, _ := util.ParseBool(vars["force"])
backlinks, _ := util.ParseBool(vars["backlinks"])

var includeobjects *engine.Objects
var excludeobjects *engine.Objects

var excludequery query.NodeFilter
var includequery, excludequery, excludelastquery query.NodeFilter
var includeobjects, excludeobjects, excludelastobjects *engine.Objects

// tricky tricky - if we get a call with the expanddn set, then we handle things .... differently :-)
if expanddn := vars["expanddn"]; expanddn != "" {
querystr = `(distinguishedName=` + expanddn + `)`
queryinclude = `(distinguishedName=` + expanddn + `)`
maxoutgoing = 0
maxdepth = 1
force = true
Expand All @@ -240,21 +234,27 @@ func analysisfuncs(ws *webservice) {
}*/
}

rest, includequery, err := query.ParseLDAPQuery(querystr, ws.Objs)
includequery, err = query.ParseLDAPQueryStrict(queryinclude, ws.Objs)
if err != nil {
w.WriteHeader(400) // bad request
w.Write([]byte(err.Error()))
w.Write([]byte("Error parsing include query: " + err.Error()))
return
}
if rest != "" {
if rest[0] != ',' {

if queryexclude != "" {
excludequery, err = query.ParseLDAPQueryStrict(queryexclude, ws.Objs)
if err != nil {
w.WriteHeader(400) // bad request
encoder.Encode(fmt.Sprintf("Error parsing ldap query: %v", err))
w.Write([]byte("Error parsing exclude query: " + err.Error()))
return
}
if excludequery, err = query.ParseLDAPQueryStrict(rest[1:], ws.Objs); err != nil {
}

if queryexcludelast != "" {
excludelastquery, err = query.ParseLDAPQueryStrict(queryexcludelast, ws.Objs)
if err != nil {
w.WriteHeader(400) // bad request
encoder.Encode(fmt.Sprintf("Error parsing ldap query: %v", err))
w.Write([]byte("Error parsing exclude last query: " + err.Error()))
return
}
}
Expand All @@ -265,6 +265,10 @@ func analysisfuncs(ws *webservice) {
excludeobjects = query.Execute(excludequery, ws.Objs)
}

if excludelastquery != nil {
excludelastobjects = query.Execute(excludelastquery, ws.Objs)
}

// var methods engine.EdgeBitmap
var edges_f, egdes_m, edges_l engine.EdgeBitmap
var objecttypes_f, objecttypes_m, objecttypes_l []engine.ObjectType
Expand Down Expand Up @@ -318,7 +322,7 @@ func analysisfuncs(ws *webservice) {
var pg engine.Graph
if mode == "sourcetarget" {
if includeobjects.Len() == 0 || excludeobjects == nil || excludeobjects.Len() == 0 {
fmt.Fprintf(w, "You must use two queries (source and target), seperated by commas. Each must return at least one object.")
fmt.Fprintf(w, "You must use two queries (source = include and target = exclude). Each must return at least one object.")
}

// We dont support this yet, so merge all of them
Expand All @@ -337,6 +341,7 @@ func analysisfuncs(ws *webservice) {
opts := engine.NewAnalyzeObjectsOptions()
opts.IncludeObjects = includeobjects
opts.ExcludeObjects = excludeobjects
opts.ExcludeLastObjects = excludelastobjects
opts.MethodsF = edges_f
opts.MethodsM = egdes_m
opts.MethodsL = edges_l
Expand Down
17 changes: 15 additions & 2 deletions modules/engine/analyzeobjects.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func NewAnalyzeObjectsOptions() AnalyzeObjectsOptions {
type AnalyzeObjectsOptions struct {
IncludeObjects *Objects
ExcludeObjects *Objects
ExcludeLastObjects *Objects
ObjectTypesF []ObjectType
ObjectTypesM []ObjectType
ObjectTypesL []ObjectType
Expand Down Expand Up @@ -309,12 +310,24 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) (pg Graph) {
delete(connectionsmap, pair)
pb.Add(1)
removed++
} else if detectobjecttypes != nil {
continue
}
if detectobjecttypes != nil {
if _, found := detectobjecttypes[pair.Target.Type()]; !found {
// No matches on LastMethods
delete(connectionsmap, pair)
pb.Add(1)
removed++
continue
}
}
if opts.ExcludeLastObjects != nil {
// does it exist in the exclude last list
if _, found := opts.ExcludeLastObjects.FindID(pair.Target.ID()); found {
delete(connectionsmap, pair)
pb.Add(1)
removed++
continue
}
}
}
Expand All @@ -324,7 +337,7 @@ func AnalyzeObjects(opts AnalyzeObjectsOptions) (pg Graph) {
break
}

ui.Debug().Msgf("Post graph object filtering remove %v nodes", removed)
ui.Debug().Msgf("Post graph object filtering removed %v nodes", removed)

weremovedsomething = true
}
Expand Down

0 comments on commit de79909

Please sign in to comment.