Query Details

HUNT 07 AD Machine Account Creation Audit 90d

Query

// =========================================================
// HUNT-07 | AD-Machine-Account-Creation-Audit-90d
// Description : Full audit of all computer object creations
//               (5137) over 90 days. Identifies creator
//               role (admin vs. non-admin), creation rate,
//               timing patterns, and flags accounts likely
//               created for RBCD, noPac, or KrbRelayUp.
// Period      : 90 days
// Use Case    : RBCD/noPac exposure assessment,
//               MachineAccountQuota hygiene
// Tables      : SecurityEvent
// =========================================================

let Period = 90d;

// Admin accounts
let AdminMembers = SecurityEvent
    | where TimeGenerated > ago(90d)
    | where EventID in (4728, 4732, 4756)
    | where TargetUserName has_any ("Domain Admins", "Enterprise Admins",
                                    "Administrators", "Account Operators")
    | summarize by AdminMember = tolower(tostring(column_ifexists("MemberName", "")));

// Machine account creations
let Creations = SecurityEvent
    | where TimeGenerated > ago(Period)
    | where EventID == 5137
    | where tostring(column_ifexists("ObjectClass", "")) =~ "computer"
    | extend
        CreatorNorm     = tolower(SubjectUserName),
        CreatorAccount  = strcat(SubjectDomainName, "\\", SubjectUserName),
        OUPath          = ObjectName,
        NewMachineName  = extract(@"CN=([^,]+)", 1, ObjectName),
        IsOffHours      = hourofday(TimeGenerated) < 7 or hourofday(TimeGenerated) >= 20;

Creations
| join kind=leftouter (AdminMembers)
    on $left.CreatorNorm == $right.AdminMember
| extend IsAdminCreator = isnotempty(AdminMember)
// Flag suspicious patterns
| extend
    IsDefaultComputerOU = OUPath has "CN=Computers,DC=",      // Standard computer OU
    IsLikelyRBCD        = not(IsAdminCreator)
                           and not(NewMachineName endswith "$")
                           and NewMachineName matches regex @"^[a-zA-Z]{4,12}\$$",
    IsLikelyNoPac       = not(IsAdminCreator)
                           and NewMachineName !has "."
                           and NewMachineName !endswith "$"
| summarize
    TotalCreations      = count(),
    AdminCreations      = countif(IsAdminCreator),
    NonAdminCreations   = countif(not(IsAdminCreator)),
    OffHoursCreations   = countif(IsOffHours),
    DefaultOUCount      = countif(IsDefaultComputerOU),
    MachineNames        = make_set(NewMachineName, 30),
    OUPaths             = make_set(OUPath, 30),
    LastCreation        = max(TimeGenerated),
    FirstCreation       = min(TimeGenerated),
    UniqueCreators      = make_set(CreatorAccount, 20)
    by CreatorNorm
| extend
    OffHoursRatio    = round(todouble(OffHoursCreations) / todouble(TotalCreations), 2),
    NonAdminRatio    = round(todouble(NonAdminCreations) / todouble(TotalCreations), 2),
    RiskScore = (NonAdminCreations * 10)
              + (OffHoursCreations * 5)
              + iff(TotalCreations >= 5, 30, 0),
    RiskLevel = case(
        NonAdminCreations >= 5, "Critical",
        NonAdminCreations >= 3, "High",
        NonAdminCreations >= 1, "Medium",
        "Low"
    ),
    LikelyPurpose = case(
        NonAdminCreations >= 3, "Probable_RBCD_KrbRelayUp_noPac_Prep",
        NonAdminCreations >= 1, "Possible_Attack_Staging",
        AdminCreations > 0,     "Legitimate_Admin_Activity",
        "Unknown"
    )
| project
    CreatorNorm,
    RiskLevel,
    RiskScore,
    LikelyPurpose,
    TotalCreations,
    NonAdminCreations,
    OffHoursRatio,
    FirstCreation,
    LastCreation,
    MachineNames,
    UniqueCreators
| order by RiskScore desc

Explanation

This query is designed to audit the creation of computer accounts in an Active Directory environment over the past 90 days. It aims to identify patterns and potential security risks associated with these creations. Here's a simplified breakdown of what the query does:

  1. Time Period: It examines events from the last 90 days.

  2. Admin Accounts Identification: It identifies accounts belonging to administrative groups like "Domain Admins" and "Enterprise Admins" by looking at specific event IDs (4728, 4732, 4756).

  3. Machine Account Creations: It focuses on events where new computer objects are created (event ID 5137) and extracts relevant details such as the creator's username, the organizational unit (OU) path, and the new machine's name.

  4. Off-Hours Detection: It flags creations that occur outside of typical working hours (before 7 AM or after 8 PM).

  5. Suspicious Patterns: It identifies potentially suspicious creations, such as those not made by admins, those with unusual naming patterns, or those created in default computer OUs.

  6. Summary Statistics: It calculates various statistics, including the total number of creations, how many were made by admins vs. non-admins, and how many occurred during off-hours. It also compiles lists of unique machine names and creators.

  7. Risk Assessment: It assigns a risk score and level based on the number of non-admin creations and off-hours activities. It also suggests a likely purpose for the creations, such as legitimate admin activity or potential attack preparation.

  8. Output: The results are sorted by risk score, showing the creator's normalized name, risk level, risk score, likely purpose, and other relevant details.

Overall, this query helps identify and assess potential security risks related to the creation of computer accounts in an Active Directory environment.

Details

David Alonso profile picture

David Alonso

Released: March 24, 2026

Tables

SecurityEvent

Keywords

SecurityEvent

Operators

letinhas_anysummarizetolowertostringcolumn_ifexistswhereago===~extendstrcatextracthourofdayjoinkindleftouteronisnotemptyhasmatchesregexendswith!has!endswithcountcountifmake_setmaxminbyroundtodoubleiffcaseprojectorder bydesc

Actions