diff --git a/cli/internal/scoreboard/generate.go b/cli/internal/scoreboard/generate.go index 9784da3e..bfe09ff8 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,8 @@ 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") + addADCSWebEnrollmentTechnique(domains, add) + addUniversalTechniques(add) keys := make([]string, 0, len(techniques)) for k := range techniques { @@ -496,6 +500,40 @@ 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 +// 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] {