From 5fa7d4f17dfbe799ba9c1459bc8af886287ec0e4 Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Tue, 22 Oct 2024 10:36:53 -0400 Subject: [PATCH] feat: add conversion logic to EIN to fix badly typed properties https://specterops.atlassian.net/browse/BED-4928 --- packages/go/ein/ad.go | 66 +++++++++++++++++++++++++++++- packages/go/ein/incoming_models.go | 2 +- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/packages/go/ein/ad.go b/packages/go/ein/ad.go index 48a0205d30..b1d9dd7c67 100644 --- a/packages/go/ein/ad.go +++ b/packages/go/ein/ad.go @@ -17,6 +17,7 @@ package ein import ( + "strconv" "strings" "github.com/specterops/bloodhound/analysis" @@ -40,6 +41,10 @@ func ConvertObjectToNode(item IngestBase, itemType graph.Kind) IngestibleNode { itemProps = make(map[string]any) } + if itemType == ad.Domain { + convertInvalidDomainProperties(itemProps) + } + return IngestibleNode{ ObjectID: item.ObjectIdentifier, PropertyMap: itemProps, @@ -47,6 +52,48 @@ func ConvertObjectToNode(item IngestBase, itemType graph.Kind) IngestibleNode { } } +func convertInvalidDomainProperties(itemProps map[string]any) { + convertStringPropertyToInt(itemProps, "machineaccountquota") + convertStringPropertyToInt(itemProps, "minpwdlength") + convertStringPropertyToInt(itemProps, "pwdproperties") + convertStringPropertyToInt(itemProps, "pwdhistorylength") + convertStringPropertyToInt(itemProps, "lockoutthreshold") + + if rawProperty, ok := itemProps["expirepasswordsonsmartcardonlyaccounts"]; ok { + switch converted := rawProperty.(type) { + case string: + if final, err := strconv.ParseBool(converted); err != nil { + delete(itemProps, "expirepasswordsonsmartcardonlyaccounts") + } else { + itemProps["expirepasswordsonsmartcardonlyaccounts"] = final + } + case bool: + //pass + default: + log.Debugf("Removing %s with type %T", converted) + delete(itemProps, "expirepasswordsonsmartcardonlyaccounts") + } + } +} + +func convertStringPropertyToInt(itemProps map[string]any, keyName string) { + if rawProperty, ok := itemProps[keyName]; ok { + switch converted := rawProperty.(type) { + case string: + if final, err := strconv.Atoi(converted); err != nil { + delete(itemProps, keyName) + } else { + itemProps[keyName] = final + } + case int: + //pass + default: + log.Debugf("Removing %s with type %T", keyName, converted) + delete(itemProps, keyName) + } + } +} + func ParseObjectContainer(item IngestBase, itemType graph.Kind) IngestibleRelationship { containingPrincipal := item.ContainedBy if containingPrincipal.ObjectIdentifier != "" { @@ -284,6 +331,21 @@ func ParseGpLinks(links []GPLink, itemIdentifier string, itemType graph.Kind) [] func ParseDomainTrusts(domain Domain) ParsedDomainTrustData { parsedData := ParsedDomainTrustData{} for _, trust := range domain.Trusts { + var finalTrustAttributes int + switch converted := trust.TrustAttributes.(type) { + case string: + if i, err := strconv.Atoi(converted); err != nil { + log.Errorf("Error converting trust attributes %s to int", converted) + } else { + finalTrustAttributes = i + } + case int: + finalTrustAttributes = converted + default: + log.Errorf("Error converting trust attributes %s to int", converted) + finalTrustAttributes = 0 + } + parsedData.ExtraNodeProps = append(parsedData.ExtraNodeProps, IngestibleNode{ PropertyMap: map[string]any{"name": trust.TargetDomainName}, ObjectID: trust.TargetDomainSid, @@ -306,7 +368,7 @@ func ParseDomainTrusts(domain Domain) ParsedDomainTrustData { "isacl": false, "sidfiltering": trust.SidFilteringEnabled, "tgtdelegationenabled": trust.TGTDelegationEnabled, - "trustattributes": trust.TrustAttributes, + "trustattributes": finalTrustAttributes, "trusttype": trust.TrustType, "transitive": trust.IsTransitive}, RelType: ad.TrustedBy, @@ -329,7 +391,7 @@ func ParseDomainTrusts(domain Domain) ParsedDomainTrustData { "isacl": false, "sidfiltering": trust.SidFilteringEnabled, "tgtdelegationenabled": trust.TGTDelegationEnabled, - "trustattributes": trust.TrustAttributes, + "trustattributes": finalTrustAttributes, "trusttype": trust.TrustType, "transitive": trust.IsTransitive}, RelType: ad.TrustedBy, diff --git a/packages/go/ein/incoming_models.go b/packages/go/ein/incoming_models.go index b4564a6d3f..4d5fd580c9 100644 --- a/packages/go/ein/incoming_models.go +++ b/packages/go/ein/incoming_models.go @@ -208,7 +208,7 @@ type Trust struct { SidFilteringEnabled bool TargetDomainName string TGTDelegationEnabled bool - TrustAttributes string + TrustAttributes any } type GPLink struct {