Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: filter out ESC3 false positives #351

Merged
merged 11 commits into from
Jan 30, 2024
41 changes: 39 additions & 2 deletions packages/go/analysis/ad/adcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,13 @@ func PostADCSESC3(ctx context.Context, tx graph.Transaction, outC chan<- analysi
cache.EnterpriseCAEnrollers[eca1.ID],
cache.EnterpriseCAEnrollers[eca2.ID],
delegatedAgents.Slice())
results.Or(tempResults)

// Add principals to result set unless it's a user and DNS is required
if filteredResults, err := filterUserDNSResults(tx, tempResults, certTemplateOne); err != nil {
log.Errorf("Error filtering user dns results: %v", err)
} else {
results.Or(filteredResults)
}
}
}
} else {
Expand All @@ -151,7 +157,12 @@ func PostADCSESC3(ctx context.Context, tx graph.Transaction, outC chan<- analysi
cache.CertTemplateControllers[certTemplateTwo.ID],
cache.EnterpriseCAEnrollers[eca1.ID],
cache.EnterpriseCAEnrollers[eca2.ID])
results.Or(tempResults)

if filteredResults, err := filterUserDNSResults(tx, tempResults, certTemplateOne); err != nil {
log.Errorf("Error filtering user dns results: %v", err)
} else {
results.Or(filteredResults)
}
}
}
}
Expand All @@ -174,6 +185,32 @@ func PostADCSESC3(ctx context.Context, tx graph.Transaction, outC chan<- analysi
return nil
}

func filterUserDNSResults(tx graph.Transaction, tempResults cardinality.Duplex[uint32], certTemplate *graph.Node) (cardinality.Duplex[uint32], error) {
if userNodes, err := ops.FetchNodeSet(tx.Nodes().Filterf(func() graph.Criteria {
return query.And(
query.KindIn(query.Node(), ad.User),
query.InIDs(query.NodeID(), cardinality.DuplexToGraphIDs(tempResults)...),
)
})); err != nil {
if !graph.IsErrNotFound(err) {
return nil, err
}
} else if len(userNodes) > 0 {
if subjRequireDns, err := certTemplate.Properties.Get(ad.SubjectAltRequireDNS.String()).Bool(); err != nil {
log.Debugf("Failed to retrieve subjectAltRequireDNS for template %d: %v", certTemplate.ID, err)
tempResults.Xor(cardinality.NodeSetToDuplex(userNodes))
} else if subjRequireDomainDns, err := certTemplate.Properties.Get(ad.SubjectAltRequireDomainDNS.String()).Bool(); err != nil {
log.Debugf("Failed to retrieve subjectAltRequireDomainDNS for template %d: %v", certTemplate.ID, err)
tempResults.Xor(cardinality.NodeSetToDuplex(userNodes))
} else if subjRequireDns || subjRequireDomainDns {
//If either of these properties is true, we need to remove all these users from our victims list
tempResults.Xor(cardinality.NodeSetToDuplex(userNodes))
}
}

return tempResults, nil
}

func principalControlsCertTemplate(principal, certTemplate *graph.Node, groupExpansions impact.PathAggregator, cache ADCSCache) bool {
var (
expandedTemplateControllers = cache.ExpandedCertTemplateControllers[certTemplate.ID]
Expand Down
Loading