Skip to content

Commit

Permalink
Stage/v5.12.0 (#700)
Browse files Browse the repository at this point in the history
* BED-4435: Enforce AG name tag uniqueness (#665)

* fix: Prevent creation of duplicate asset group and tag names

* fix: Modified DB schema to enforce AG name tag uniqueness

* fix: abstracted agi error handling

* add changes to latest migration file

* Update cmd/api/src/api/error.go

Co-authored-by: mistahj67 <[email protected]>

* Update cmd/api/src/api/v2/agi_test.go

Co-authored-by: mistahj67 <[email protected]>

* add error body check in ag tests

* json body for empty ag tests, idempotence

---------

Co-authored-by: mistahj67 <[email protected]>

* BED-4525: Fix broken link (#682)

* BED-4439: Broken collected filter (#684)

* fix: Broken collected filter for available-domains endpoint

* reuse collected string variable

* additional fixes on style standards

* add TODO comment to clarify irregular logic

---------

Co-authored-by: Justin Wu <[email protected]>
Co-authored-by: mistahj67 <[email protected]>
Co-authored-by: Stephen Hinck <[email protected]>
  • Loading branch information
4 people committed Jul 17, 2024
1 parent bba5c08 commit 09e66d6
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 56 deletions.
74 changes: 49 additions & 25 deletions cmd/api/src/model/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/specterops/bloodhound/dawgs/graph"
"github.com/specterops/bloodhound/dawgs/query"
"github.com/specterops/bloodhound/errors"
"github.com/specterops/bloodhound/graphschema/common"
)

type FilterOperator string
Expand Down Expand Up @@ -96,8 +97,49 @@ type QueryParameterFilter struct {
}

type QueryParameterFilters []QueryParameterFilter


func (s QueryParameterFilter) BuildGDBNodeFilter() graph.Criteria {
var (
propertyRef = query.NodeProperty(s.Name)
value = guessFilterValueType(s.Value)
)

// TODO: Investigate whether we can set the collected property for domains that originate from trusts in ParseDomainTrusts
switch {
case s.Name == common.Collected.String() && s.Operator == Equals:
switch s.Value {
case FalseString:
return query.Or(
query.Equals(propertyRef, false),
query.Not(query.Exists(propertyRef)),
)
case TrueString:
return query.Equals(propertyRef, true)
}
}

switch s.Operator {
case GreaterThan:
return query.GreaterThan(propertyRef, value)
case GreaterThanOrEquals:
return query.GreaterThanOrEquals(propertyRef, value)
case LessThan:
return query.LessThan(propertyRef, value)
case LessThanOrEquals:
return query.LessThanOrEquals(propertyRef, value)
case Equals:
return query.Equals(propertyRef, value)
case NotEquals:
return query.Not(query.Equals(propertyRef, value))
default:
return nil
}
}

type QueryParameterFilterMap map[string]QueryParameterFilters


func (s QueryParameterFilterMap) BuildSQLFilter() (SQLFilter, error) {
var (
result strings.Builder
Expand Down Expand Up @@ -162,33 +204,15 @@ func guessFilterValueType(raw string) any {
}

func (s QueryParameterFilterMap) BuildGDBNodeFilter() graph.Criteria {
var criteria []graph.Criteria

for _, filters := range s {
for _, filter := range filters {
switch filter.Operator {
case GreaterThan:
criteria = append(criteria, query.GreaterThan(query.NodeProperty(filter.Name), guessFilterValueType(filter.Value)))

case GreaterThanOrEquals:
criteria = append(criteria, query.GreaterThanOrEquals(query.NodeProperty(filter.Name), guessFilterValueType(filter.Value)))

case LessThan:
criteria = append(criteria, query.LessThan(query.NodeProperty(filter.Name), guessFilterValueType(filter.Value)))
var criteria []graph.Criteria

case LessThanOrEquals:
criteria = append(criteria, query.LessThanOrEquals(query.NodeProperty(filter.Name), guessFilterValueType(filter.Value)))

case Equals:
criteria = append(criteria, query.Equals(query.NodeProperty(filter.Name), guessFilterValueType(filter.Value)))

case NotEquals:
criteria = append(criteria, query.Not(query.Equals(query.NodeProperty(filter.Name), guessFilterValueType(filter.Value))))
}
}
}
for _, filters := range s {
for _, filter := range filters {
criteria = append(criteria, filter.BuildGDBNodeFilter())
}
}

return query.And(criteria...)
return query.And(criteria...)
}

func (s QueryParameterFilterMap) BuildNeo4jFilter() (string, error) {
Expand Down
55 changes: 26 additions & 29 deletions cmd/api/src/model/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,34 +127,31 @@ func (s DomainSelectors) GetOrderCriteria(params url.Values) (OrderCriteria, err
}

func (s DomainSelectors) GetFilterCriteria(request *http.Request) (graph.Criteria, error) {
var (
queryParameterFilterParser = NewQueryParameterFilterParser()
criteria graph.Criteria
)

if queryFilters, err := queryParameterFilterParser.ParseQueryParameterFilters(request); err != nil {
return nil, fmt.Errorf(ErrorResponseDetailsBadQueryParameterFilters)
} else {
for name, filters := range queryFilters {
if valid := slices.Contains(s.GetFilterableColumns(), name); !valid {
return nil, fmt.Errorf(ErrorResponseDetailsColumnNotFilterable)
}

if validPredicates, err := s.GetValidFilterPredicatesAsStrings(name); err != nil {
return nil, fmt.Errorf(ErrorResponseDetailsColumnNotFilterable)
} else {
for i, filter := range filters {
if !slices.Contains(validPredicates, string(filter.Operator)) {
return nil, fmt.Errorf(ErrorResponseDetailsFilterPredicateNotSupported)
}

queryFilters[name][i].IsStringData = s.IsString(filter.Name)
}
}
}
var (
queryParameterFilterParser = NewQueryParameterFilterParser()
criteria graph.Criteria
)

if queryFilters, err := queryParameterFilterParser.ParseQueryParameterFilters(request); err != nil {
return nil, fmt.Errorf(ErrorResponseDetailsBadQueryParameterFilters)
} else {
for name, filters := range queryFilters {
if valid := slices.Contains(s.GetFilterableColumns(), name); !valid {
return nil, fmt.Errorf(ErrorResponseDetailsColumnNotFilterable)
}
if validPredicates, err := s.GetValidFilterPredicatesAsStrings(name); err != nil {
return nil, fmt.Errorf(ErrorResponseDetailsColumnNotFilterable)
} else {
for i, filter := range filters {
if !slices.Contains(validPredicates, string(filter.Operator)) {
return nil, fmt.Errorf(ErrorResponseDetailsFilterPredicateNotSupported)
}
queryFilters[name][i].IsStringData = s.IsString(filter.Name)
}
}
}
// ignoring the error here as this would've failed at ParseQueryParameterFilters before getting here
criteria = query.And(queryFilters.BuildGDBNodeFilter(), query.KindIn(query.Node(), ad.Domain, azure.Tenant))

return criteria, nil
}
criteria = query.And(queryFilters.BuildGDBNodeFilter(), query.KindIn(query.Node(), ad.Domain, azure.Tenant))
return criteria, nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const References: FC = () => {
https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/PowerView.ps1
</Link>
<br />
<Link target='_blank' rel='noopener' href='https://www.harmj0y.net/redteaming/kerberoasting-revisited/'>
https://www.harmj0y.net/redteaming/kerberoasting-revisited/
<Link target='_blank' rel='noopener' href='https://blog.harmj0y.net/redteaming/kerberoasting-revisited/'>
https://blog.harmj0y.net/redteaming/kerberoasting-revisited/
</Link>
<br />
<Link
Expand Down

0 comments on commit 09e66d6

Please sign in to comment.