From bee73649403f0b8d04a991b4dd4d9e98cae49e04 Mon Sep 17 00:00:00 2001 From: Jayson Grace Date: Sat, 16 May 2026 10:40:45 -0600 Subject: [PATCH 1/2] feat: add universal ADCS and CVE techniques and expand ADCS ESC coverage **Added:** - Included "adcs_esc8" in vulnerable techniques for relevant lab entities in the config - Added new ADCS techniques ("adcs_esc5", "adcs_esc8", "adcs_esc14") to scoreboard labels - Introduced universal techniques (e.g., "nopac", "printnightmare", "zerologon", "cve_2019_1040", "certifried", "krbrelayup", "machine_account_quota", "mitm6") via a dedicated function to ensure they are always credited - Updated test expectations to cover the new and universal techniques **Changed:** - Refactored extraction of techniques to add universal techniques for every lab, replacing previous static addition of "child_to_parent" - Improved documentation in code comments for universal techniques logic --- ad/GOAD/data/config.json | 4 ++-- cli/internal/scoreboard/generate.go | 23 ++++++++++++++++++++++- cli/internal/scoreboard/verify_test.go | 4 +++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ad/GOAD/data/config.json b/ad/GOAD/data/config.json index 3f006a92..cb54a53a 100644 --- a/ad/GOAD/data/config.json +++ b/ad/GOAD/data/config.json @@ -19,7 +19,7 @@ ] }, "scripts" : ["sidhistory.ps1"], - "vulns" : ["disable_firewall", "adcs_esc10_case1", "adcs_esc10_case2"], + "vulns" : ["disable_firewall", "adcs_esc8", "adcs_esc10_case1", "adcs_esc10_case2"], "security": ["account_is_sensitive", "audit_policy"], "security_vars": { "account_is_sensitive" : { "renly": {"account" : "renly.baratheon"} } @@ -218,7 +218,7 @@ "essos\\Dothraki" ], "scripts" : [], - "vulns" : ["openshares","disable_firewall", "adcs_esc6", "adcs_esc11"], + "vulns" : ["openshares","disable_firewall", "adcs_esc6", "adcs_esc8", "adcs_esc11"], "security": ["enable_run_as_ppl"], "mssql":{ "sa_password": "sa_P@ssw0rd!Ess0s", diff --git a/cli/internal/scoreboard/generate.go b/cli/internal/scoreboard/generate.go index 9784da3e..607d9c40 100644 --- a/cli/internal/scoreboard/generate.go +++ b/cli/internal/scoreboard/generate.go @@ -315,13 +315,16 @@ var adcsLabels = map[string]string{ "adcs_esc2": "ADCS ESC2", "adcs_esc3": "ADCS ESC3", "adcs_esc4": "ADCS ESC4", + "adcs_esc5": "ADCS ESC5", "adcs_esc6": "ADCS ESC6", "adcs_esc7": "ADCS ESC7", + "adcs_esc8": "ADCS ESC8", "adcs_esc9": "ADCS ESC9", "adcs_esc10_case1": "ADCS ESC10 (Case 1)", "adcs_esc10_case2": "ADCS ESC10 (Case 2)", "adcs_esc11": "ADCS ESC11", "adcs_esc13": "ADCS ESC13", + "adcs_esc14": "ADCS ESC14", "adcs_esc15": "ADCS ESC15", } @@ -355,7 +358,7 @@ func extractTechniques(lab map[string]any, asrep map[string][]string) []Objectiv addKerberosTechniques(domains, asrep, add) addHostTechniques(hosts, add) addDomainTechniques(domains, add) - add("child_to_parent", "Child-to-Parent Domain Escalation", "domain_trust") + addUniversalTechniques(add) keys := make([]string, 0, len(techniques)) for k := range techniques { @@ -496,6 +499,24 @@ func addPrivescTechniques(h map[string]any, add techniqueAdd) { } } +// addUniversalTechniques credits techniques that are exploitable against any +// default-configured GOAD lab: cross-domain escalation, unpatched DC CVEs, +// ADCS-adjacent abuses (Certifried), IPv6 poisoning, and MAQ=10 chains. These +// don't have per-host markers — the lab's defaults (unpatched Server roles, +// MAQ=10, Print Spooler on, ca_web_enrollment=true) make them universally +// applicable. Documented in docs/GOAD-vulnerabilities-comprehensive.md. +func addUniversalTechniques(add techniqueAdd) { + add("child_to_parent", "Child-to-Parent Domain Escalation", "domain_trust") + add("nopac", "noPac (CVE-2021-42287/42278)", "cve") + add("printnightmare", "PrintNightmare (CVE-2021-1675)", "cve") + add("zerologon", "ZeroLogon (CVE-2020-1472)", "cve") + add("cve_2019_1040", "CVE-2019-1040 (Remove-MIC NTLM Bypass)", "cve") + add("certifried", "Certifried (CVE-2022-26923)", "adcs") + add("krbrelayup", "KrbRelayUp (RBCD self-relay)", "privilege_escalation") + add("machine_account_quota", "Machine Account Quota Abuse (MAQ=10)", "privilege_escalation") + add("mitm6", "MITM6 IPv6/DHCPv6 Poisoning", "network") +} + func addDomainTechniques(domains map[string]any, add techniqueAdd) { addIfAnyDomainHas(domains, "acls", add, "acl_abuse", "ACL Abuse Chain", "acl_abuse") addIfAnyDomainHas(domains, "trust", add, "cross_forest_trust", "Cross-Forest Trust Exploitation", "domain_trust") diff --git a/cli/internal/scoreboard/verify_test.go b/cli/internal/scoreboard/verify_test.go index dc4d2ab2..a137ea30 100644 --- a/cli/internal/scoreboard/verify_test.go +++ b/cli/internal/scoreboard/verify_test.go @@ -114,7 +114,7 @@ func TestAnswerKeyHasAllExpectedTechniques(t *testing.T) { want := []string{ "asrep_roast", "kerberoast", "adcs_esc1", "adcs_esc2", "adcs_esc3", "adcs_esc4", "adcs_esc6", - "adcs_esc7", "adcs_esc9", "adcs_esc11", "adcs_esc13", "adcs_esc15", + "adcs_esc7", "adcs_esc8", "adcs_esc9", "adcs_esc11", "adcs_esc13", "adcs_esc15", "adcs_esc10_case1", "adcs_esc10_case2", "golden_ticket-essos.local", "golden_ticket-north.sevenkingdoms.local", @@ -126,6 +126,8 @@ func TestAnswerKeyHasAllExpectedTechniques(t *testing.T) { "acl_abuse", "cross_forest_trust", "child_to_parent", "constrained_delegation", "unconstrained_delegation", "seimpersonate", + "nopac", "printnightmare", "zerologon", "cve_2019_1040", + "certifried", "krbrelayup", "machine_account_quota", "mitm6", } for _, w := range want { if !techIDs[w] { From 1bec8b9e7678143a0aba442938543c65d18fb956 Mon Sep 17 00:00:00 2001 From: Jayson Grace Date: Sat, 16 May 2026 10:49:57 -0600 Subject: [PATCH 2/2] feat: add domain-level detection for ADCS ESC8 technique **Added:** - Added logic to credit ESC8 technique when any domain has Web Enrollment enabled by introducing addADCSWebEnrollmentTechnique function in the scoreboard generator **Changed:** - Updated technique extraction flow to call addADCSWebEnrollmentTechnique, ensuring ESC8 is recognized at the domain level rather than per host **Removed:** - Removed "adcs_esc8" from per-host 'vulns' lists in config.json to prevent Ansible from dispatching non-existent vulns_adcs_esc8 role --- ad/GOAD/data/config.json | 4 ++-- cli/internal/scoreboard/generate.go | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ad/GOAD/data/config.json b/ad/GOAD/data/config.json index cb54a53a..3f006a92 100644 --- a/ad/GOAD/data/config.json +++ b/ad/GOAD/data/config.json @@ -19,7 +19,7 @@ ] }, "scripts" : ["sidhistory.ps1"], - "vulns" : ["disable_firewall", "adcs_esc8", "adcs_esc10_case1", "adcs_esc10_case2"], + "vulns" : ["disable_firewall", "adcs_esc10_case1", "adcs_esc10_case2"], "security": ["account_is_sensitive", "audit_policy"], "security_vars": { "account_is_sensitive" : { "renly": {"account" : "renly.baratheon"} } @@ -218,7 +218,7 @@ "essos\\Dothraki" ], "scripts" : [], - "vulns" : ["openshares","disable_firewall", "adcs_esc6", "adcs_esc8", "adcs_esc11"], + "vulns" : ["openshares","disable_firewall", "adcs_esc6", "adcs_esc11"], "security": ["enable_run_as_ppl"], "mssql":{ "sa_password": "sa_P@ssw0rd!Ess0s", diff --git a/cli/internal/scoreboard/generate.go b/cli/internal/scoreboard/generate.go index 607d9c40..bfe09ff8 100644 --- a/cli/internal/scoreboard/generate.go +++ b/cli/internal/scoreboard/generate.go @@ -358,6 +358,7 @@ func extractTechniques(lab map[string]any, asrep map[string][]string) []Objectiv addKerberosTechniques(domains, asrep, add) addHostTechniques(hosts, add) addDomainTechniques(domains, add) + addADCSWebEnrollmentTechnique(domains, add) addUniversalTechniques(add) keys := make([]string, 0, len(techniques)) @@ -499,6 +500,22 @@ func addPrivescTechniques(h map[string]any, add techniqueAdd) { } } +// addADCSWebEnrollmentTechnique credits ESC8 when any domain has Web Enrollment +// installed. ESC8 isn't a per-host vulns marker (Ansible would try to dispatch +// a non-existent vulns_adcs_esc8 role) — it's gated by the domain-level +// ca_web_enrollment flag, which defaults to true. Mirrors validate/checks.go's +// CAWebEnrollment() logic. +func addADCSWebEnrollmentTechnique(domains map[string]any, add techniqueAdd) { + for _, dRaw := range domains { + d, _ := dRaw.(map[string]any) + if v, ok := d["ca_web_enrollment"].(bool); ok && !v { + continue + } + add("adcs_esc8", "ADCS ESC8", "adcs") + return + } +} + // addUniversalTechniques credits techniques that are exploitable against any // default-configured GOAD lab: cross-domain escalation, unpatched DC CVEs, // ADCS-adjacent abuses (Certifried), IPv6 poisoning, and MAQ=10 chains. These