Query Details

HUNT 06 AD ADCS Vulnerable Template Audit 30d

Query

// =========================================================
// HUNT-06 | AD-ADCS-Vulnerable-Template-Audit-30d
// Description : All certificate issuances (4886/4887) over
//               30 days grouped by template, with SAN
//               presence, requester vs. subject mismatch
//               detection, enrollment agent use flags,
//               and bulk enrollment rate indicators.
//               Maps to ESC1 (SAN mismatch), ESC3
//               (enrollment agent), ESC8 (DC cert relay).
// Period      : 30 days
// Use Case    : ADCS attack surface review, PKI audit
// Tables      : SecurityEvent
// =========================================================

let Period = 30d;

// Event 4887 — Certificate Issued with detailed fields
SecurityEvent
| where TimeGenerated > ago(Period)
| where EventID in (4886, 4887)
| extend
    EventDesc         = case(EventID == 4886, "Certificate Requested",
                             EventID == 4887, "Certificate Issued", "Other"),
    RequesterUPN      = SubjectUserName,
    RequesterDomain   = SubjectDomainName,
    // Parse template from EventData
    TemplateName      = extract(@"(?i)<Data Name=.CertificateTemplate.>(.*?)</Data>", 1, EventData),
    RequestAttr       = extract(@"(?i)<Data Name=.RequestAttributes.>(.*?)</Data>", 1, EventData),
    SubjectField      = extract(@"(?i)<Data Name=.Subject.>(.*?)</Data>", 1, EventData)
| extend
    // SAN present in request attributes (locally computed from RequestAttr)
    SANValue          = extract(@"(?i)san=([^;,\n]+)", 1, RequestAttr),
    EnrollmentAgent   = extract(@"(?i)enrollmentagent=([^;,\n]+)", 1, RequestAttr),
    RequesterNorm     = tolower(RequesterUPN),
    IsDCTemplate      = TemplateName has_any ("DomainController", "KerberosAuthentication",
                                               "DirectoryEmailReplication")
| extend
    HasSAN            = isnotempty(SANValue),
    HasEnrollAgent    = isnotempty(EnrollmentAgent),
    SANNorm           = tolower(SANValue),
    SANMismatch       = isnotempty(SANValue) and not(tolower(SANValue) contains tolower(RequesterUPN))
| extend
    SensitiveSAN      = SANNorm has_any ("administrator", "domain admins", "enterprise admins",
                                         "krbtgt", "dc$", "dc01", "dc02")
| summarize
    TotalIssuances      = count(),
    SANMismatches       = countif(SANMismatch),
    SensitiveSANIssuances = countif(SensitiveSAN),
    EnrollAgentUses     = countif(HasEnrollAgent),
    DCTemplateCerts     = countif(IsDCTemplate),
    UniqueRequesters    = dcount(RequesterUPN),
    Requesters          = make_set(RequesterUPN, 20),
    SANValues           = make_set(SANValue, 20),
    IssuanceDays        = dcount(startofday(TimeGenerated)),
    LastIssuance        = max(TimeGenerated),
    FirstIssuance       = min(TimeGenerated)
    by TemplateName
| extend
    DailyRateAvg        = round(todouble(TotalIssuances) / todouble(IssuanceDays), 1),
    RiskScore           = (SANMismatches * 30)
                        + (SensitiveSANIssuances * 50)
                        + (EnrollAgentUses * 20)
                        + (DCTemplateCerts * 15),
    ESCFlags = strcat(
        iff(SANMismatches > 0,         "ESC1_SAN_Mismatch; ", ""),
        iff(EnrollAgentUses > 0,       "ESC3_EnrollAgent; ", ""),
        iff(DCTemplateCerts > 0,       "ESC8_DCTemplate; ", ""),
        iff(SensitiveSANIssuances > 0, "Critical_SensitiveSAN; ", "")
    ),
    RiskLevel = case(
        SensitiveSANIssuances > 0, "Critical",
        SANMismatches > 0,         "High",
        EnrollAgentUses > 0,       "High",
        DCTemplateCerts > 5,       "Medium",
        "Low"
    )
| project
    TemplateName,
    RiskLevel,
    RiskScore,
    ESCFlags,
    TotalIssuances,
    DailyRateAvg,
    SANMismatches,
    SensitiveSANIssuances,
    EnrollAgentUses,
    DCTemplateCerts,
    UniqueRequesters,
    FirstIssuance,
    LastIssuance,
    SANValues,
    Requesters
| order by RiskScore desc

Explanation

This KQL query is designed to audit and analyze certificate issuances in an Active Directory Certificate Services (ADCS) environment over the past 30 days. Here's a simple breakdown of what the query does:

  1. Data Source: It looks at security events related to certificate requests and issuances (Event IDs 4886 and 4887) from the SecurityEvent table.

  2. Time Frame: The analysis covers a period of the last 30 days.

  3. Data Extraction: For each event, it extracts and processes several pieces of information:

    • The type of event (certificate requested or issued).
    • The template used for the certificate.
    • The requester's user principal name (UPN) and domain.
    • Subject Alternative Name (SAN) details.
    • Whether an enrollment agent was used.
    • Whether the certificate template is for a domain controller.
  4. Analysis:

    • It checks for SAN presence and mismatches between the SAN and the requester.
    • It identifies sensitive SAN values that could indicate potential security risks.
    • It counts the use of enrollment agents and domain controller templates.
  5. Summarization: The query summarizes the data by certificate template, calculating:

    • Total number of issuances.
    • Number of SAN mismatches and sensitive SAN issuances.
    • Use of enrollment agents and domain controller templates.
    • Unique requesters and their details.
    • Issuance frequency and time range.
  6. Risk Assessment:

    • It calculates a risk score based on the presence of SAN mismatches, sensitive SANs, enrollment agent usage, and domain controller templates.
    • It assigns a risk level (Critical, High, Medium, Low) based on specific criteria.
  7. Output: The results are projected to show key details like template name, risk level, risk score, and other relevant metrics, sorted by risk score in descending order to prioritize higher-risk templates.

This query is useful for identifying potential vulnerabilities and risks in the certificate issuance process, helping to enhance the security posture of the ADCS environment.