T1201

Password Policy Discovery

Discovery Last updated:

Adversaries may attempt to access detailed information about the password policy used within an enterprise network or cloud environment. Password policies enforce complexity requirements that make passwords harder to guess or crack through brute force. By discovering lockout thresholds, minimum length, and complexity rules, adversaries can tailor dictionary and brute force attacks to comply with the policy — maximizing credential testing while avoiding account lockout. Discovery occurs via command-line utilities (net accounts, Get-ADDefaultDomainPasswordPolicy, chage, pwpolicy), cloud APIs (AWS GetAccountPasswordPolicy), and network device CLIs. This technique is commonly observed in the early reconnaissance phase of intrusions by groups including OilRig, Turla, and Chimera.

What is T1201 Password Policy Discovery?

Password Policy Discovery (T1201) maps to the Discovery tactic — the adversary is trying to figure out your environment in MITRE ATT&CK.

This page provides production-ready detection logic for Password Policy Discovery, covering the data sources and telemetry it touches: Process: Process Creation, Command: Command Execution, Microsoft Defender for Endpoint. The queries below are rated low severity at high confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.

MITRE ATT&CK

Tactic
Discovery
Technique
T1201 Password Policy Discovery
Canonical reference
https://attack.mitre.org/techniques/T1201/
Microsoft Sentinel / Defender
kusto
let PasswordPolicyCommands = dynamic([
  "net accounts",
  "net.exe accounts",
  "Get-ADDefaultDomainPasswordPolicy",
  "Get-ADFineGrainedPasswordPolicy",
  "Get-PassPol",
  "pwpolicy",
  "chage -l",
  "chage --list",
  "pam.d",
  "common-password",
  "pwquality",
  "show aaa",
  "NtdsAudit"
]);
let PasswordPolicyCmdlets = dynamic([
  "Get-ADDefaultDomainPasswordPolicy",
  "Get-ADFineGrainedPasswordPolicy",
  "Get-ADFineGrainedPasswordPolicySubject",
  "Get-PassPol"
]);
DeviceProcessEvents
| where Timestamp > ago(24h)
| where (
    // net accounts and net accounts /domain
    (FileName =~ "net.exe" or FileName =~ "net1.exe") and ProcessCommandLine has "accounts"
  ) or (
    // PowerShell AD password policy cmdlets
    (FileName =~ "powershell.exe" or FileName =~ "pwsh.exe") and
    ProcessCommandLine has_any (PasswordPolicyCmdlets)
  ) or (
    // CrackMapExec or other tools querying password policy via LDAP/WMI patterns
    ProcessCommandLine has_any ("NtdsAudit", "--pass-pol", "--password-policy")
  ) or (
    // Linux: chage command reading password aging info
    FileName =~ "chage" and (ProcessCommandLine has "-l" or ProcessCommandLine has "--list")
  ) or (
    // macOS: pwpolicy command
    FileName =~ "pwpolicy" and ProcessCommandLine has "getaccountpolicies"
  )
| extend DiscoveryMethod = case(
    ProcessCommandLine has "accounts /domain" or ProcessCommandLine has "accounts", "net accounts",
    ProcessCommandLine has_any ("Get-ADDefaultDomainPasswordPolicy", "Get-ADFineGrainedPasswordPolicy"), "PowerShell AD Cmdlet",
    ProcessCommandLine has "Get-PassPol", "PoshC2 Get-PassPol",
    ProcessCommandLine has "NtdsAudit", "NtdsAudit Utility",
    ProcessCommandLine has "chage", "Linux chage",
    ProcessCommandLine has "pwpolicy", "macOS pwpolicy",
    ProcessCommandLine has_any ("--pass-pol", "--password-policy"), "CrackMapExec-style",
    "Other"
  )
| extend IsDomainQuery = ProcessCommandLine has "/domain" or ProcessCommandLine has_any ("Get-ADDefaultDomainPasswordPolicy", "Get-ADFineGrainedPasswordPolicy")
| project Timestamp, DeviceName, AccountName, AccountDomain,
         FileName, ProcessCommandLine,
         InitiatingProcessFileName, InitiatingProcessCommandLine,
         DiscoveryMethod, IsDomainQuery
| sort by Timestamp desc

Detects password policy discovery activity using Microsoft Defender for Endpoint DeviceProcessEvents. Monitors for net.exe/net1.exe with 'accounts' arguments (local and domain), PowerShell AD password policy cmdlets (Get-ADDefaultDomainPasswordPolicy, Get-ADFineGrainedPasswordPolicy), PoshC2's Get-PassPol, NtdsAudit utility usage, Linux chage -l enumeration, macOS pwpolicy getaccountpolicies, and CrackMapExec-style --pass-pol flags. Enriches events with the discovery method and whether the query targets the domain policy.

low severity high confidence

Data Sources

Process: Process Creation Command: Command Execution Microsoft Defender for Endpoint

Required Tables

DeviceProcessEvents

False Positives

  • IT administrators running 'net accounts /domain' for routine password policy audits or compliance checks
  • Security tools and vulnerability scanners (Nessus, Qualys, CIS-CAT) that enumerate password policy as part of baseline hardening assessments
  • Active Directory management scripts and monitoring agents (e.g., Azure AD Connect health, SIEM onboarding scripts) that periodically query domain password policy
  • Help desk staff using net accounts to verify lockout policy before resetting a locked account
  • Automated identity governance platforms (SailPoint, Saviynt) querying fine-grained password policies during access reviews

Sigma rule & cross-platform mapping

The detection logic for Password Policy Discovery (T1201) above is provided in a vendor-neutral form so you can deploy it on any SIEM. The same logic is shipped here as native KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the following logsource:

logsource:
  category: process_creation
  product: windows

Browse the community-maintained Sigma rules for this technique:


Testing Methodology

Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Local Password Policy Discovery via net accounts

    Expected signal: Sysmon Event ID 1: Process Create with Image ending in net.exe or net1.exe, CommandLine='net accounts'. Security Event ID 4688 (if command line auditing is enabled) with same details. Parent process will be cmd.exe or the calling shell.

  2. Test 2Domain Password Policy Discovery via net accounts /domain

    Expected signal: Sysmon Event ID 1: Process Create with Image=net.exe, CommandLine='net accounts /domain'. Net.exe internally calls net1.exe which also generates a process creation event. The query contacts the PDC emulator — Sysmon Event ID 3 (Network Connect) may show a connection to the DC on port 445 or 135.

  3. Test 3Domain Password Policy via PowerShell Get-ADDefaultDomainPasswordPolicy

    Expected signal: Sysmon Event ID 1: Process Create with Image=powershell.exe, CommandLine containing 'Get-ADDefaultDomainPasswordPolicy'. PowerShell ScriptBlock Log Event ID 4104 capturing the full command. Sysmon Event ID 7 (Image Load) may show Microsoft.ActiveDirectory.Management.dll being loaded.

  4. Test 4Linux Password Policy Discovery via PAM configuration

    Expected signal: On systems with auditd: syscall audit records for openat()/read() on /etc/security/pwquality.conf and /etc/pam.d/common-password (auditd rule: -w /etc/pam.d/ -p r -k pam_policy_read). Process creation event for chage with -l argument. On MDE Linux agent: DeviceProcessEvents event for chage with ProcessCommandLine containing '-l'.


Response Playbook

Triage

  1. Identify the user account that executed the command — is this a standard end user, IT admin, service account, or domain admin? Standard users running 'net accounts /domain' warrant closer scrutiny than IT staff
  2. Examine the parent process — was the password policy query launched interactively from cmd.exe or PowerShell, or was it spawned by an unexpected parent (Office application, browser, script engine like wscript.exe or mshta.exe)?
  3. Check the timeline for surrounding activity — did this command occur in isolation, or is it part of a cluster of discovery commands (net user, net group, whoami /priv, nltest, systeminfo)? Clustered discovery is a strong indicator of post-exploitation reconnaissance
  4. Determine if the query targeted the domain policy (/domain flag or Get-ADDefaultDomainPasswordPolicy) versus local policy only — domain queries have broader impact for subsequent brute force planning
  5. Review recent authentication events for the same account — look for failed login attempts (Event ID 4625), Kerberoasting indicators (Event ID 4769 with RC4 encryption), or unusual access to sensitive systems preceding this query
  6. Check for tool artifacts: NtdsAudit writes output files; CrackMapExec logs to disk. Look for unusual output files in the working directory of the process
  7. Correlate with network connections from the same host around the same time — outbound connections to non-corporate IPs alongside discovery activity strongly suggests an active intrusion

Containment

  1. If discovered alongside other post-exploitation indicators (credential dumping, lateral movement, C2 beaconing): immediately isolate the endpoint via EDR network isolation or VLAN quarantine
  2. If a compromised account is suspected: disable the account in Active Directory immediately, revoke all active sessions and Kerberos tickets (run 'klist purge' or use the AD console to reset the account), and notify the account owner
  3. If CrackMapExec or NtdsAudit was executed: search for the tool binary and any output files, collect as forensic evidence before removal, then delete from the system
  4. Review and temporarily tighten authentication policies if brute force activity is anticipated: lower lockout thresholds if safe to do so, enable MFA for all privileged accounts, and alert the SOC to monitor for sudden spikes in 4625 events
  5. If the query was domain-scoped: escalate to the identity team immediately — the adversary now knows the domain lockout threshold and can conduct targeted account spraying across the entire domain

Evidence Collection

  1. Process creation events: Sysmon Event ID 1 or Security Event ID 4688 (requires 'Audit Process Creation' and 'Include command line in process creation events' GPO) from the affected host
  2. Parent process chain: capture the full ancestry of the discovery process (grandparent, parent, child) to identify the initial execution vector
  3. PowerShell ScriptBlock Logs (Event ID 4104): if a PowerShell AD cmdlet was used, ScriptBlock logging captures the full script content including any piped output handling
  4. Security Event ID 4625 (failed logons) and 4771 (Kerberos pre-auth failures): collect from all DCs for the 24 hours before and after the discovery event to detect attempted follow-on brute force
  5. Net session data: run 'net session' and 'netstat -an' on the affected host to capture active connections at time of investigation
  6. File system artifacts: check for NtdsAudit output files (typically CSV dumps of account and password info), CrackMapExec log files (~/.cme/logs/), or any text files containing password policy output in the user's home directory and temp directories
  7. Prefetch files: C:\Windows\Prefetch\NET.EXE-*.pf and POWERSHELL.EXE-*.pf contain execution timestamps confirming when these tools were run
  8. Windows Security Event ID 4661 (handle requested for object) from Domain Controllers: SAM database handle requests may accompany programmatic password policy retrieval

Escalation Criteria

  • ! Password policy discovery occurs alongside credential dumping indicators (LSASS access, ntds.dit copy, comsvcs.dll MiniDump), indicating the adversary is preparing a targeted offline crack based on known policy parameters
  • ! Discovery command was executed by a service account, domain admin, or SYSTEM context with no corresponding change management ticket or scheduled task justification
  • ! NtdsAudit or CrackMapExec binary detected on the endpoint — these are purpose-built offensive tools with no legitimate administrative use in most environments
  • ! Domain-scoped password policy query (net accounts /domain or Get-ADDefaultDomainPasswordPolicy) followed within minutes by Kerberoasting activity (Event ID 4769 with etype=0x17/RC4) or password spray attempts (multiple 4625s against different accounts)
  • ! Same discovery pattern observed on multiple endpoints within a short time window, suggesting scripted or automated post-exploitation framework activity (Cobalt Strike, PoshC2, Metasploit)
  • ! Password policy discovery preceded by a phishing email open, suspicious document execution, or unusual remote logon — confirms the discovery is part of an active attack chain rather than isolated administrative activity

Investigation Guide

Forensic Artifacts

  • > Prefetch: C:\Windows\Prefetch\NET.EXE-*.pf — confirms net.exe execution with timestamps and loaded DLLs
  • > Prefetch: C:\Windows\Prefetch\NET1.EXE-*.pf — net1.exe is the internal binary called by net.exe
  • > Registry: HKLM\SAM\SAM\Domains\Account — contains local password policy settings readable by SYSTEM
  • > Event Log: Security Event ID 4688 with CommandLine — requires 'Include command line in process creation events' audit policy enabled
  • > Event Log: Microsoft-Windows-PowerShell/Operational Event ID 4104 — ScriptBlock logging captures Get-ADDefaultDomainPasswordPolicy invocations with full parameter context
  • > File System: NtdsAudit output CSVs (account-hashes.csv, password-hashes.csv) if NtdsAudit was run — typically written to the working directory or a path specified with --output
  • > File System: ~/.cme/logs/ — CrackMapExec logs including smb/<target>/<timestamp>.log which record --pass-pol results
  • > Active Directory: 'net accounts /domain' retrieves policy from the PDC emulator — check PDC emulator DC Security event logs for the corresponding authentication and LDAP query
  • > Command history: $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt — interactive PowerShell sessions log commands here

Tuning Guidance

Password policy discovery via net accounts is extremely common in Windows environments and most hits will be benign IT activity. Begin by profiling legitimate users: IT help desk staff, AD admins, and automated compliance scanners (Nessus, CIS-CAT) will generate the bulk of noise. Build an allowlist of known-good (account, parent process, hostname) tuples — for example, SCCM agents querying policy as part of software inventory, or dedicated admin hosts where net accounts is expected. Consider elevating severity only when domain-scoped queries (/domain flag) are executed by non-privileged accounts or from workstations rather than admin jump hosts. The highest-fidelity signals are NtdsAudit and PoshC2 Get-PassPol — these should always alert without suppression. For cloud environments, supplement this detection with AWS CloudTrail monitoring for GetAccountPasswordPolicy API calls from IAM principals that are not dedicated audit/compliance roles. The combination of password policy discovery followed within minutes by authentication failures (Event ID 4625) is a near-certain indicator of active password spraying and should be a high-priority compound rule.


Hunting Queries

Hunt for accounts or parent processes repeatedly querying password policy via net accounts. Multiple executions across different devices from the same account, or repeated execution from an unusual parent, may indicate a scripted post-exploitation reconnaissance sweep — as seen with OilRig and Turla tooling.

Hunting — KQL
kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where (FileName =~ "net.exe" or FileName =~ "net1.exe") and ProcessCommandLine has "accounts"
| summarize
    Count = count(),
    UniqueDevices = dcount(DeviceName),
    UniqueAccounts = dcount(AccountName),
    FirstSeen = min(Timestamp),
    LastSeen = max(Timestamp),
    SampleCommands = make_set(ProcessCommandLine, 5)
  by InitiatingProcessFileName, AccountName
| where Count > 2 or UniqueDevices > 1
| sort by Count desc
Hunting — SPL
spl
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
  (Image="*\\net.exe" OR Image="*\\net1.exe") CommandLine="*accounts*"
| stats count as Count, dc(host) as UniqueDevices, dc(User) as UniqueAccounts,
        earliest(_time) as FirstSeen, latest(_time) as LastSeen,
        values(CommandLine) as SampleCommands
  by ParentImage, User
| where Count > 2 OR UniqueDevices > 1
| sort - Count

Hunt for password policy discovery co-occurring with other Active Directory or system discovery commands within a 10-minute window on the same host and account. Co-occurrence of multiple discovery techniques is a strong behavioral indicator of automated post-exploitation frameworks (Cobalt Strike, PoshC2, Metasploit) running a reconnaissance phase.

Hunting — KQL
kql
let DiscoveryWindow = 10m;
DeviceProcessEvents
| where Timestamp > ago(7d)
| where (
    ((FileName =~ "net.exe" or FileName =~ "net1.exe") and ProcessCommandLine has "accounts") or
    ((FileName =~ "powershell.exe" or FileName =~ "pwsh.exe") and
     ProcessCommandLine has_any ("Get-ADDefaultDomainPasswordPolicy", "Get-ADFineGrainedPasswordPolicy"))
  )
| project DiscoveryTime=Timestamp, DeviceName, AccountName, DiscoveryCmd=ProcessCommandLine
| join kind=inner (
    DeviceProcessEvents
    | where Timestamp > ago(7d)
    | where ProcessCommandLine has_any ("net user", "net group", "whoami", "nltest", "dsquery", "ldifde", "csvde", "net localgroup")
    | project CompanionTime=Timestamp, DeviceName, AccountName, CompanionCmd=ProcessCommandLine
  ) on DeviceName, AccountName
| where abs(datetime_diff('minute', DiscoveryTime, CompanionTime)) <= 10
| project DeviceName, AccountName, DiscoveryTime, DiscoveryCmd, CompanionTime, CompanionCmd
| sort by DeviceName, DiscoveryTime asc
Hunting — SPL
spl
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
| eval CommandLineLower=lower(CommandLine)
| eval IsPasswdPol=if(
    (match(lower(Image), "(net\.exe|net1\.exe)") AND match(CommandLineLower, "accounts")) OR
    (match(lower(Image), "(powershell|pwsh)") AND match(CommandLineLower, "get-addefaultdomainpasswordpolicy")),
    1, 0)
| eval IsOtherDiscovery=if(
    match(CommandLineLower, "(net user|net group|whoami|nltest|dsquery|net localgroup|ldifde|csvde)"),
    1, 0)
| eval DiscoveryFlag=IsPasswdPol + IsOtherDiscovery
| where DiscoveryFlag > 0
| bucket _time span=10m
| stats sum(IsPasswdPol) as PasswdPolCount, sum(IsOtherDiscovery) as OtherDiscoveryCount,
        values(CommandLine) as Commands
  by _time, host, User
| where PasswdPolCount > 0 AND OtherDiscoveryCount > 0
| sort - _time

Hunt for execution of purpose-built offensive tools that explicitly target password policy: NtdsAudit (used by Chimera), CrackMapExec (--pass-pol flag), and PoshC2's Get-PassPol module. Any hit from these tools in a production environment is high-fidelity and warrants immediate investigation — these have no legitimate administrative use.

Hunting — KQL
kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has_any ("NtdsAudit", "--pass-pol", "--password-policy", "Get-PassPol")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
         InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by Timestamp desc
Hunting — SPL
spl
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
  (CommandLine="*NtdsAudit*" OR CommandLine="*--pass-pol*" OR CommandLine="*--password-policy*" OR CommandLine="*Get-PassPol*")
| table _time, host, User, Image, CommandLine, ParentImage, ParentCommandLine
| sort - _time

Atomic Red Team Tests

Test 1 Local Password Policy Discovery via net accounts
windows

Executes 'net accounts' to retrieve the local machine's password policy including minimum/maximum password age, minimum password length, lockout threshold, and lockout duration. This is the simplest form of T1201 and is used by malware families like Kwampirs and frameworks like Cobalt Strike during reconnaissance.

Command

powershell
net accounts

Expected Telemetry

Sysmon Event ID 1: Process Create with Image ending in net.exe or net1.exe, CommandLine='net accounts'. Security Event ID 4688 (if command line auditing is enabled) with same details. Parent process will be cmd.exe or the calling shell.

Expected Detection

KQL: FileName =~ 'net.exe' AND ProcessCommandLine has 'accounts', DiscoveryMethod='net accounts (local)'. SPL: IsNetAccounts=1, IsDomainQuery=0, SuspicionScore=1.

Test 2 Domain Password Policy Discovery via net accounts /domain
windows

Executes 'net accounts /domain' to query the domain password policy from Active Directory, retrieving lockout threshold, observation window, and complexity requirements. This is the specific command documented as used by OilRig (G0049) in scripts against Middle East financial sector targets, and by Turla (G0010).

Command

powershell
net accounts /domain

Expected Telemetry

Sysmon Event ID 1: Process Create with Image=net.exe, CommandLine='net accounts /domain'. Net.exe internally calls net1.exe which also generates a process creation event. The query contacts the PDC emulator — Sysmon Event ID 3 (Network Connect) may show a connection to the DC on port 445 or 135.

Expected Detection

KQL: FileName =~ 'net.exe' AND ProcessCommandLine has 'accounts' AND IsDomainQuery=true, DiscoveryMethod='net accounts /domain'. SPL: IsNetAccounts=1, IsDomainQuery=1, SuspicionScore=1. Higher severity than local query due to domain-wide scope.

Test 3 Domain Password Policy via PowerShell Get-ADDefaultDomainPasswordPolicy
windows

Uses the ActiveDirectory PowerShell module to query the default domain password policy, returning ComplexityEnabled, MinPasswordLength, LockoutThreshold, LockoutObservationWindow, and LockoutDuration. This method is used by PoshC2 (via Get-PassPol) and is common in living-off-the-land attacks where the AD module is already available on the target.

Command

powershell
powershell.exe -NoProfile -Command "Import-Module ActiveDirectory; Get-ADDefaultDomainPasswordPolicy"

Expected Telemetry

Sysmon Event ID 1: Process Create with Image=powershell.exe, CommandLine containing 'Get-ADDefaultDomainPasswordPolicy'. PowerShell ScriptBlock Log Event ID 4104 capturing the full command. Sysmon Event ID 7 (Image Load) may show Microsoft.ActiveDirectory.Management.dll being loaded.

Expected Detection

KQL: FileName =~ 'powershell.exe' AND ProcessCommandLine has 'Get-ADDefaultDomainPasswordPolicy', DiscoveryMethod='PowerShell AD Password Policy Cmdlet'. SPL: IsPSADPolicy=1, SuspicionScore=1.

Test 4 Linux Password Policy Discovery via PAM configuration
linux

On Linux systems, reads the PAM password quality configuration to discover minimum password length, complexity requirements, and history settings. This technique is used post-compromise on Linux servers to understand enforcement before attempting password changes or understanding existing account policies. The chage command is additionally used to read per-account password aging policies.

Command

bash
cat /etc/security/pwquality.conf && cat /etc/pam.d/common-password && chage -l $(whoami)

Expected Telemetry

On systems with auditd: syscall audit records for openat()/read() on /etc/security/pwquality.conf and /etc/pam.d/common-password (auditd rule: -w /etc/pam.d/ -p r -k pam_policy_read). Process creation event for chage with -l argument. On MDE Linux agent: DeviceProcessEvents event for chage with ProcessCommandLine containing '-l'.

Expected Detection

KQL (MDE Linux): FileName =~ 'chage' AND ProcessCommandLine has '-l', DiscoveryMethod='Linux chage'. Auditd-based SIEM: file read events on /etc/security/pwquality.conf tagged with pam_policy_read key. SPL (auditd): sourcetype=linux_audit key=pam_policy_read.

Related Detections

Tactic Hub