Skip to content

Commit 7d6e452

Browse files
martanneTw1sm
andauthored
AD CS improvements (#45)
* Fix AD CS certificate chain creation Extend the certificate chain of enterprise CAs to also include the corresponding root CA. * Resolve enterprise CA to hosting computer object This allows BloodHound to create the HostsCAService edge which since v7.4.0 is a pre-requisite for the other post-processed AD CS edges. * bump version & changelog --------- Co-authored-by: Tw1sm <mcreel31@gmail.com>
1 parent f94df10 commit 7d6e452

File tree

3 files changed

+21
-2
lines changed

3 files changed

+21
-2
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Changelog
2+
## [0.4.18] - 11/22/2025
3+
### Fixes
4+
- Fix ADCSESC1 edge creation
5+
- Fix [#44](https://github.com/coffeegist/bofhound/issues/44)
6+
27
## [0.4.17] - 10/30/2025
38
### Performance
49
- Optimized group membership resolution algorithm from polynomial to linear complexity using reverse index lookups

bofhound/ad/adds.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,10 @@ def process(self):
379379
self.resolve_published_templates(ca)
380380
logger.info("Resolved enabled templates per CA")
381381

382+
with console.status(" [bold] Resolving hosting computers of CAs", spinner="aesthetic"):
383+
for ca in self.enterprisecas:
384+
self.resolve_hosting_computer(ca)
385+
logger.info("Resolved hosting computers of CAs")
382386

383387
def get_sid_from_name(self, name):
384388
for entry in self.SID_MAP:
@@ -754,6 +758,16 @@ def resolve_published_templates(self, entry:BloodHoundEnterpriseCA):
754758
and template.Properties['domain'] == entry.Properties['domain']:
755759
entry.EnabledCertTemplates.append({"ObjectIdentifier": template.ObjectIdentifier.upper(), "ObjectType": "CertTemplate"})
756760

761+
def resolve_hosting_computer(self, ca:BloodHoundEnterpriseCA):
762+
if 'dnshostname' in ca.Properties:
763+
hostname = ca.Properties['dnshostname']
764+
for comp in self.computers:
765+
if comp.matches_dnshostname(hostname):
766+
ca.HostingComputer = comp.ObjectIdentifier
767+
logger.debug(f"Resolved CA hosting computer: {hostname} to {ca.HostingComputer}")
768+
return
769+
logger.warning(f"Could not resolve CA hosting computer: {hostname}")
770+
757771
def parse_acl(self, entry:BloodHoundObject):
758772
"""
759773
Parse the nTSecurityDescriptor attribute of an AD object and extract BloodHound
@@ -1306,7 +1320,7 @@ def build_certificate_chain(start_ca_obj, all_ca_obj):
13061320

13071321
def build_certificate_chains(self):
13081322
for enterpriseca in self.enterprisecas:
1309-
enterpriseca.Properties['certchain'] = ADDS.build_certificate_chain(enterpriseca, self.enterprisecas)
1323+
enterpriseca.Properties['certchain'] = ADDS.build_certificate_chain(enterpriseca, self.enterprisecas+self.rootcas)
13101324

13111325
for aiaca in self.aiacas:
13121326
aiaca.Properties['certchain'] = ADDS.build_certificate_chain(aiaca, self.aiacas)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "bofhound"
3-
version = "0.4.17"
3+
version = "0.4.18"
44
description = "Parse output from common sources and transform it into BloodHound-ingestible data"
55
authors = [
66
"Adam Brown",

0 commit comments

Comments
 (0)