Query Details

HUNT 19 AD Pre Win2000 Machine Account Risk Audit 90d

Query

// =========================================================
// HUNT-19 | AD-PreWin2000-MachineAccount-Risk-Audit-90d
// Description : Pre-Windows-2000 compatible access machine
//               accounts have their password hash set to
//               the machine name in lower-case (predictable)
//               and are often left enabled for decades.
//               This query identifies: (1) machine accounts
//               whose TGT was requested with RC4 using a
//               predictable password pattern, (2) machine
//               accounts in the Pre-Windows 2000 Compatible
//               Access group, (3) machine accounts with
//               PasswordLastSet matching creation date.
// Period      : 90 days
// Use Case    : Pre-Win2000 password exploitation,
//               legacy auth risk assessment
// Tables      : SecurityEvent
// =========================================================

let Period = 90d;

// Machine account TGT requests with RC4 (pre-win2000 uses RC4 by default)
let MachineRC4TGT = SecurityEvent
    | where TimeGenerated > ago(Period)
    | where EventID == 4768
    | where TargetUserName endswith "$"       // machine accounts
    | where tostring(column_ifexists("TicketEncryptionType", "")) == "0x17"    // RC4
    | extend
        MachineNorm   = tolower(TargetUserName),
        MachineName   = trim_end("$", TargetUserName),
        ClientIP      = ClientAddress,
        Domain        = TargetDomainName;

// Pre-Windows 2000 Compatible Access group membership events
let PreWin2000Members = SecurityEvent
    | where TimeGenerated > ago(Period)
    | where EventID in (4728, 4732)   // member added to security group
    | where TargetUserName =~ "Pre-Windows 2000 Compatible Access"
    | extend
        MemberAdded = tostring(column_ifexists("MemberName", "")),
        AddedBy     = strcat(SubjectDomainName, "\\", SubjectUserName),
        AddedAt     = TimeGenerated;

// Machine account password-related events (4723/4724 on machine accounts)
let MachinePasswordEvents = SecurityEvent
    | where TimeGenerated > ago(Period)
    | where EventID in (4723, 4724)
    | where TargetUserName endswith "$"
    | extend MachineNorm = tolower(TargetUserName);

// New machine account creation (to compare with password set timing)
let MachineCreations = SecurityEvent
    | where TimeGenerated > ago(Period)
    | where EventID == 5137
    | where tostring(column_ifexists("ObjectClass", "")) =~ "computer"
    | extend
        CreatedMachineNorm = tolower(extract(@"CN=([^,]+)\$", 0, ObjectName)),
        CreationTime       = TimeGenerated,
        Creator            = strcat(SubjectDomainName, "\\", SubjectUserName);

// RC4 machine TGT summary
let RC4Summary = MachineRC4TGT
    | summarize
        RC4TGTCount     = count(),
        FirstRC4        = min(TimeGenerated),
        LastRC4         = max(TimeGenerated),
        ClientIPs       = make_set(ClientIP, 10),
        Domains         = make_set(Domain, 5)
      by MachineNorm, MachineName;

// Join machine creations to RC4 requests
RC4Summary
| join kind=leftouter (MachineCreations) on $left.MachineNorm == $right.CreatedMachineNorm
| extend
    DaysSinceCreation   = datetime_diff("day", LastRC4, CreationTime),
    IsFreshlyCreated    = CreationTime > ago(14d),
    IsLikelyPreWin2000  = MachineName =~ tolower(MachineName),   // password == lowercase machinename
    IsSuspiciousRC4 = RC4TGTCount >= 1
| extend
    RiskScore = (RC4TGTCount * 10)
              + iff(IsFreshlyCreated, 30, 0)
              + iff(IsLikelyPreWin2000, 20, 0),
    RiskLevel = case(
        IsFreshlyCreated and RC4TGTCount >= 3,
            "Critical - Fresh_Machine_Account_Repeated_RC4_Auth",
        IsFreshlyCreated,
            "High - New_Machine_Account_RC4_TGT",
        RC4TGTCount >= 10,
            "High - High_Volume_RC4_Machine_Auth",
        RC4TGTCount >= 3,
            "Medium - Repeated_RC4_Machine_Auth",
        "Low - Single_RC4_Machine_Auth"
    )
| union (
    PreWin2000Members
    | summarize
        MembersAdded  = make_set(MemberAdded, 20),
        AddedByActors = make_set(AddedBy, 10),
        LastChange    = max(AddedAt)
      by GroupName = TargetUserName
    | extend
        MachineNorm        = "",
        MachineName        = GroupName,
        RC4TGTCount        = 0,
        IsFreshlyCreated   = false,
        IsLikelyPreWin2000 = true,
        RiskScore          = array_length(MembersAdded) * 40,
        RiskLevel          = "High - PreWin2000CompatGroup_Membership_Changed",
        ClientIPs          = pack_array(""),
        DaysSinceCreation  = 0
    | project-away GroupName
)
| project
    MachineName,
    RiskLevel,
    RiskScore,
    IsFreshlyCreated,
    RC4TGTCount,
    ClientIPs,
    DaysSinceCreation,
    CreationTime,
    Creator,
    FirstRC4,
    LastRC4
| order by RiskScore desc

Explanation

This query is designed to identify potential security risks associated with machine accounts in an Active Directory environment, specifically focusing on those using outdated or predictable authentication methods. Here's a simplified breakdown of what the query does:

  1. Time Frame: It examines security events from the past 90 days.

  2. RC4 TGT Requests: It looks for machine accounts (accounts ending with "$") that have requested a Ticket Granting Ticket (TGT) using the RC4 encryption method. This is significant because pre-Windows 2000 systems use RC4 by default, and these accounts might have predictable passwords.

  3. Pre-Windows 2000 Group Membership: It checks for any changes in membership to the "Pre-Windows 2000 Compatible Access" group, which could indicate potential security risks.

  4. Password Events: It identifies password-related events for machine accounts, such as password changes.

  5. New Machine Accounts: It tracks the creation of new machine accounts to see if their password settings align with their creation date, which could indicate a security risk if they are using predictable passwords.

  6. Risk Assessment: The query calculates a risk score for each machine account based on several factors, such as the number of RC4 TGT requests, whether the account is newly created, and if it follows a predictable password pattern. It categorizes the risk level as Critical, High, Medium, or Low.

  7. Output: The results are ordered by risk score, highlighting the most potentially vulnerable machine accounts first.

In essence, this query helps identify machine accounts that might be vulnerable due to outdated authentication methods or predictable password patterns, allowing for a focused security assessment and remediation.

Details

David Alonso profile picture

David Alonso

Released: March 24, 2026

Tables

SecurityEvent

Keywords

SecurityEvent

Operators

letwhereagoendswithtostringcolumn_ifexistsextendtolowertrim_endinstrcatsummarizecountminmaxmake_setjoindatetime_diffcaseiffunionarray_lengthpack_arrayproject-awayprojectorder by

Actions