Detect Valid Accounts in IBM QRadar
Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop. Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. In some cases, adversaries may abuse inactive accounts belonging to individuals who are no longer part of an organization.
MITRE ATT&CK
- Technique
- T1078 Valid Accounts
- Canonical reference
- https://attack.mitre.org/techniques/T1078/
QRadar Detection Query
SELECT
username AS target_user,
DATEFORMAT(starttime, 'yyyy-MM-dd HH:00:00') AS event_hour,
COUNT(*) AS total_events,
COUNT(DISTINCT sourceip) AS unique_source_ips,
SUM(CASE WHEN eventid = 4625 THEN eventcount ELSE 0 END) AS failed_logons,
SUM(CASE WHEN eventid = 4672 THEN eventcount ELSE 0 END) AS privileged_logons,
SUM(CASE WHEN eventid = 4648 THEN eventcount ELSE 0 END) AS new_credential_use,
SUM(CASE WHEN eventid = 4624 THEN eventcount ELSE 0 END) AS successful_logons,
MIN(sourceip) AS sample_source_ip
FROM events
WHERE
LOGSOURCETYPENAME(devicetype) = 'Microsoft Windows Security Event Log'
AND eventid IN (4624, 4625, 4648, 4672)
AND username NOT IN ('SYSTEM', 'ANONYMOUS LOGON', '-', 'LOCAL SERVICE', 'NETWORK SERVICE')
AND username NOT LIKE '%$'
AND starttime > NOW() - 3600000
GROUP BY
username,
DATEFORMAT(starttime, 'yyyy-MM-dd HH:00:00')
HAVING
failed_logons > 5
OR (unique_source_ips > 3 AND successful_logons > 0)
OR (new_credential_use > 0 AND privileged_logons > 0)
ORDER BY total_events DESC
LAST 1 HOURS AQL query that aggregates Windows Security authentication events (4624 successful logon, 4625 failed logon, 4648 logon with explicit credentials, 4672 special privilege assignment) per user per hour across all Windows Security Event Log sources. Flags accounts meeting any of three risk conditions: more than 5 failed logons, successful logons arriving from more than 3 distinct source IPs within the hour, or the co-occurrence of explicit credential use and privileged session creation. Machine accounts and known system identities are excluded. Mirrors the risk-scoring logic of the SPL detection adapted to QRadar's AQL aggregation model.
Data Sources
Required Tables
False Positives & Tuning
- System administrators who authenticate to many managed workstations from a single jump host generate multiple 4624 events with the same sourceip, but automated inventory or patch management tools may pull credentials from several IPs, inflating unique_source_ips past the threshold during maintenance windows
- Ansible, SCCM, or similar configuration management platforms that authenticate as a service account across dozens of endpoints in parallel within a single hour will reliably exceed the unique_source_ips threshold without any malicious activity
- Helpdesk workflows where staff use RunAs (generating 4648) to launch an elevated tool and then perform privileged operations (generating 4672) during a support ticket are a common and entirely legitimate co-occurrence of new_credential_use and privileged_logons
Other platforms for T1078
Testing Methodology
Validate this detection against 5 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 1 Simulate Compromised Account Remote Logon (Windows)
Expected signal: Security Event ID 4648 on source host (explicit credential logon with alternate credentials). Security Event ID 4624 LogonType=3 (network) on target host. Sysmon Event ID 3 (network connection) from cmd.exe to TARGET_HOST:445. Security Event ID 4672 if USERNAME has special privileges.
- Test 2 Simulate Service Account Lateral Movement via WMI
Expected signal: Security Event ID 4648 on initiating host. Security Event ID 4624 LogonType=3 on TARGET_HOST. Security Event ID 4688 (or Sysmon Event ID 1) showing WmiPrvSE.exe spawning cmd.exe on TARGET_HOST. Sysmon Event ID 3 showing DCOM/WMI network traffic to TARGET_HOST:135.
- Test 3 Simulate Dormant Account Reactivation (Local)
Expected signal: Security Event ID 4720 (account created). Security Event ID 4725 (account disabled). Security Event ID 4722 (account enabled — key indicator of reactivation). Security Event ID 4624 LogonType=2 (interactive) for df00tech_dormant. Audit event for account enabling action.
- Test 4 Simulate Cloud Account Compromise via Azure CLI
Expected signal: Azure AD SigninLogs entry with UserPrincipalName=compromised_user, AppDisplayName='Microsoft Azure CLI', ClientAppUsed='Other clients', AuthenticationRequirement='singleFactorAuthentication' (if no MFA). Azure Audit Log entries for resource enumeration. Entra ID Protection may generate a risk detection if login is from an unexpected location.
- Test 5 Test Impossible Travel Detection Trigger
Expected signal: Two SigninLogs entries for [email protected]: first from US IP, second from EU IP approximately 2 minutes later. Entra ID Protection should generate an 'Impossible Travel' risk detection. Both entries appear in the 24h window, different Location fields.
References (8)
- https://attack.mitre.org/techniques/T1078/
- https://www.cisa.gov/uscert/ncas/alerts/aa22-074a
- https://learn.microsoft.com/en-us/azure/active-directory/reports-monitoring/concept-sign-ins
- https://learn.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection
- https://docs.splunk.com/Documentation/SplunkCloud/latest/SearchReference/CommonStatsFunctions
- https://www.mandiant.com/resources/blog/unc3944-scattered-spider
- https://www.cisa.gov/sites/default/files/2024-02/aa24-038a-prc-state-sponsored-actors-compromise-us-critical-infrastructure_0.pdf
- https://technet.microsoft.com/en-us/library/dn535501.aspx
Response Playbook
Triage
- Retrieve the full sign-in history for the account over the past 30 days — look for the first anomalous logon timestamp and what changed (new IP, new ASN, new country, new device fingerprint)
- Check whether the account is a human user or service account — service accounts should have fixed source IPs and hosts; any deviation is high-confidence malicious
- Identify the authentication method used — password-only auth on an MFA-enrolled account without an MFA event suggests MFA bypass (SIM swap, OTP phishing, adversary-in-the-middle)
- Cross-reference the source IP against threat intel feeds — check VirusTotal, Shodan, or AbuseIPDB for the IP/ASN; residential proxy infrastructure and VPN exit nodes are common for credential abuse
- Determine geographic plausibility — if the user logged in from New York 30 minutes before logging in from Singapore, the second login is impossible travel and high-confidence compromise
- Review what the account accessed after the anomalous logon — did it access sensitive SharePoint/OneDrive, email, admin portals, or begin lateral movement via RDP/SMB?
- Check if the account has recent MFA registration changes, password resets, or new app authorizations — adversaries often register new MFA devices or OAuth apps to maintain persistence after initial access
Containment
- Immediately revoke all active sessions and refresh tokens for the compromised account: in Entra ID use 'Revoke Sign-In Sessions' from the user blade, or run: Revoke-AzureADUserAllRefreshToken -ObjectId <user-object-id>
- Force password reset and require re-enrollment of MFA factors — specifically remove any MFA devices registered during or after the suspicious logon window
- If on-premises AD: reset the Kerberos ticket-granting ticket by resetting the account password twice and running 'klist purge' on affected endpoints
- Disable the account temporarily if immediate password reset is not operationally feasible, then coordinate with the user out-of-band (phone/in-person) for credential restoration
- Block the identified threat actor IP(s)/ASN at the perimeter firewall, Conditional Access named locations, and email gateway
- If lateral movement is detected: isolate affected endpoints using EDR network containment, and rotate credentials for any service accounts the compromised user could access
- Audit and revoke any OAuth application consents granted during the suspicious session window
Evidence Collection
- Azure AD / Entra ID Sign-In Logs (retention: 30 days default) — export to Log Analytics or Storage Account immediately if within window; include non-interactive sign-ins which are often missed
- Azure AD Audit Logs — capture any MFA registration changes, password resets, role assignments, or OAuth consent grants made during the suspicious window
- Windows Security Event ID 4624/4625/4648/4672 from domain controllers and affected endpoints — extract with wevtutil: wevtutil qe Security /q:"*[System[(EventID=4624 or EventID=4625) and TimeCreated[@SystemTime>='2026-03-14T00:00:00']]]"
- VPN/remote access gateway logs — source IPs, connection duration, and transferred data volume during the suspicious period
- Email access logs (Exchange/M365) — MailItemsAccessed audit record shows which emails were read; run: Search-UnifiedAuditLog -Operations MailItemsAccessed -UserIds <upn> -StartDate <date> -EndDate <date>
- SharePoint/OneDrive access logs — FileAccessed, FileDownloaded events in the Unified Audit Log for any mass download during the suspicious window
- Endpoint process creation and network events from the workstation(s) involved in the suspicious logon (Sysmon Event ID 1 and 3)
- UEBA/Identity Protection risk detections export from Entra ID Protection — these may contain pre-existing risk signals that predated the alert
Escalation Criteria
- !Confirmed impossible travel — two geographically separated successful logons within a timeframe that is physically impossible
- !MFA bypass evidence — successful authentication without a corresponding MFA event for an MFA-enrolled account
- !Privileged account compromise — any Domain Admin, Global Admin, or high-privilege service account showing anomalous access patterns
- !Evidence of email exfiltration — MailItemsAccessed events for large volumes of sensitive email, or inbox rules forwarding to external addresses created post-compromise
- !Lateral movement detected — the compromised account authenticating to additional hosts, using WMI, PsExec, RDP, or SMB after the initial anomalous logon
- !Persistence mechanism established — new MFA device registered, OAuth app authorized, scheduled task or service created using the compromised account
- !Multiple accounts compromised simultaneously — same source IP/ASN with anomalous logons across several accounts suggests bulk credential stuffing or a broader breach
Investigation Guide
Related Techniques
Forensic Artifacts
- >
Windows Event Log: Security — Event 4624 (successful logon) with LogonType, Source IP, AuthPackage; Event 4625 (failed logon); Event 4648 (explicit credential use); Event 4672 (special privilege assigned) - >
Windows Event Log: Security — Event 4768/4769 (Kerberos TGT/TGS requests) at domain controllers — reveals ticket-granting activity for the compromised account - >
Windows Event Log: Security — Event 4776 (NTLM authentication) at domain controllers — source workstation and account for NTLM-based access - >
Registry: HKLM\SYSTEM\CurrentControlSet\Control\Lsa — CachedLogonsCount, LmCompatibilityLevel affect authentication artifacts - >
Registry: HKCU\Software\Microsoft\Terminal Server Client\Servers — cached RDP server entries indicating lateral movement destinations - >
File System: C:\Users\<username>\AppData\Local\Microsoft\Credentials\ — DPAPI-protected credential blobs - >
File System: C:\Windows\System32\winevt\Logs\Security.evtx — primary authentication event log (export before rotation) - >
Azure AD: Sign-In Logs, Audit Logs, Risk Detections in Entra ID Protection (accessible via Azure Portal or Microsoft Graph API) - >
Memory: LSASS process memory contains active Kerberos tickets and NTLM hashes for logged-on users — volatile, capture immediately if endpoint is live - >
Network: NetFlow/firewall logs showing source IP, destination, protocol, and data volume for the suspicious session window
Tuning Guidance
Valid account detections require careful baseline establishment to avoid alert fatigue. Begin with a 30-day baseline of normal user behavior before enabling automated alerting. Key tuning steps: (1) Build an allowlist of known VPN exit node IP ranges and corporate proxy infrastructure — these create legitimate IP diversity. (2) Exclude service accounts from human-behavior anomaly rules and instead create dedicated rules for service account deviation (service accounts should have fixed source IPs, logon types, and target systems). (3) For MFA-enrolled accounts, add MFA success/failure as a required field — password-only auth on MFA accounts is almost always suspicious. (4) Use Entra ID Identity Protection risk scores as a pre-filter — risk scores of 'medium' or 'high' significantly reduce false positives. (5) Tune the dormancy threshold to match your organization's offboarding processes — if accounts are routinely disabled within 14 days of termination, a 30-day dormancy threshold may be appropriate. (6) For on-premises environments, create separate rules for interactive (Type 2, 10) vs. network (Type 3) logons — bulk Type 3 logons from service accounts are normal; bulk Type 10 (RDP) from non-admin accounts is suspicious. (7) Integrate with HR/ITSM systems to automatically exclude accounts with active travel requests or contractor engagements in new geographies.
Hunting Queries
Hunt for accounts authenticating from 3 or more distinct countries within a 24-hour window. This pattern indicates either account sharing (policy violation), credential compromise with active threat actor access, or legitimate global travel that warrants verification. APT groups like Scattered Spider are known to use residential proxies that appear as different country origins.
// Hunt for accounts logging in from multiple countries within 24h (impossible travel)
let TimeWindow = 24h;
SigninLogs
| where TimeGenerated > ago(7d)
| where ResultType == 0
| summarize Countries=make_set(Location), IPs=make_set(IPAddress), LogonCount=count(),
FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated)
by UserPrincipalName, bin(TimeGenerated, TimeWindow)
| extend CountryCount=array_length(Countries)
| where CountryCount >= 3
| project-away TimeGenerated
| sort by CountryCount desc index=o365 sourcetype="o365:management:activity" Operation="UserLoggedIn" ResultStatus="Succeeded"
| iplocation ClientIP
| stats dc(Country) as CountryCount, values(Country) as Countries, values(ClientIP) as IPs,
count as LogonCount, earliest(_time) as FirstSeen, latest(_time) as LastSeen
by UserId, span=24h
| where CountryCount >= 3
| sort - CountryCount Hunt for accounts dormant for 90+ days that have suddenly become active. Adversaries frequently target inactive accounts of former employees or service accounts as they are less likely to have password changes, active MFA, or monitoring. This pattern is consistent with CISA-documented techniques used by groups targeting critical infrastructure.
// Hunt for dormant accounts suddenly becoming active after 90+ days of inactivity
let DormancyThreshold = 90d;
let RecentWindow = 7d;
let DormantAccounts = SigninLogs
| where TimeGenerated between (ago(365d) .. ago(DormancyThreshold))
| where ResultType == 0
| summarize LastActiveDate=max(TimeGenerated) by UserPrincipalName;
let RecentLogons = SigninLogs
| where TimeGenerated > ago(RecentWindow)
| where ResultType == 0
| summarize RecentLogonCount=count(), RecentIPs=make_set(IPAddress), RecentApps=make_set(AppDisplayName)
by UserPrincipalName, RecentLogonDate=bin(TimeGenerated, 1d);
DormantAccounts
| join kind=inner RecentLogons on UserPrincipalName
| extend DaysDormant = datetime_diff('day', RecentLogonDate, LastActiveDate)
| where DaysDormant >= DormancyThreshold
| project UserPrincipalName, LastActiveDate, RecentLogonDate, DaysDormant,
RecentLogonCount, RecentIPs, RecentApps
| sort by DaysDormant desc index=wineventlog sourcetype="WinEventLog:Security" EventCode=4624
| bucket span=1d _time
| stats latest(_time) as LastLogon by TargetUserName
| eval DaysSinceLastLogon=round((now()-LastLogon)/86400, 0)
| where DaysSinceLastLogon < 7
| join type=left TargetUserName
[search index=wineventlog sourcetype="WinEventLog:Security" EventCode=4624 earliest=-365d latest=-90d
| stats latest(_time) as PreviousLogon by TargetUserName
| eval DaysDormant=round((now()-PreviousLogon)/86400, 0)
| where DaysDormant >= 90]
| where isnotnull(PreviousLogon)
| table TargetUserName, LastLogon, PreviousLogon, DaysDormant
| sort - DaysDormant Hunt for accounts with concurrent or near-concurrent sessions from multiple distinct IP addresses within a 30-minute window. Legitimate users rarely authenticate from 3+ different IPs within 30 minutes. This pattern may indicate active credential sharing by a threat actor across multiple infrastructure nodes, or a credential-sharing botnet performing simultaneous actions with stolen credentials.
// Hunt for accounts used simultaneously from multiple distinct IP address ranges (concurrent sessions)
let ConcurrentWindow = 30m;
SigninLogs
| where TimeGenerated > ago(7d)
| where ResultType == 0
| summarize Sessions=make_list(pack('time', TimeGenerated, 'ip', IPAddress, 'app', AppDisplayName, 'location', Location))
by UserPrincipalName
| mv-expand Session=Sessions
| extend SessionTime=todatetime(Session.time), SessionIP=tostring(Session.ip)
| order by UserPrincipalName, SessionTime asc
| serialize
| extend PrevTime=prev(SessionTime), PrevIP=prev(IPAddress), PrevUser=prev(UserPrincipalName)
| where UserPrincipalName == PrevUser
| extend TimeDiff=datetime_diff('minute', SessionTime, PrevTime)
| where TimeDiff <= toint(ConcurrentWindow / 1m) and SessionIP != PrevIP
| project UserPrincipalName, SessionTime, SessionIP, PrevTime, PrevIP, TimeDiff
| sort by TimeDiff asc index=wineventlog sourcetype="WinEventLog:Security" EventCode=4624 LogonType IN ("3", "10")
| stats list(_time) as LogonTimes, list(IpAddress) as IpAddresses, dc(IpAddress) as UniqueIPs
by TargetUserName span=30m
| where UniqueIPs >= 3
| mvexpand LogonTimes
| mvexpand IpAddresses
| stats values(IpAddresses) as IPs, count as Sessions by TargetUserName, UniqueIPs
| sort - UniqueIPs Atomic Red Team Tests
Uses stored credentials to perform a network logon to a remote system, simulating an adversary using compromised credentials to access internal resources. This generates Event ID 4648 (explicit credential use) on the source and 4624 LogonType 3 on the target. Replace TARGET_HOST, USERNAME, and DOMAIN with test environment values.
Command
cmdkey /add:TARGET_HOST /user:DOMAIN\USERNAME /pass:Password123!
net use \\TARGET_HOST\IPC$ /user:DOMAIN\USERNAME Password123!
net use \\TARGET_HOST\IPC$ /delete Cleanup
cmdkey /delete:TARGET_HOST Expected Telemetry
Security Event ID 4648 on source host (explicit credential logon with alternate credentials). Security Event ID 4624 LogonType=3 (network) on target host. Sysmon Event ID 3 (network connection) from cmd.exe to TARGET_HOST:445. Security Event ID 4672 if USERNAME has special privileges.
Expected Detection
SPL rule triggers on 4648 + 4624 combination with UniqueSourceIPs > 1 within the hour window. KQL anomaly rule flags new IP/workstation combination for USERNAME if not seen in 14-day baseline.
Uses WMI with explicit credentials to execute a command on a remote host, mimicking APT41 and FIN8 lateral movement techniques where compromised service account credentials are used for remote code execution. Generates Event 4648 and 4624 LogonType 3, plus WMI activity.
Command
wmic /node:TARGET_HOST /user:DOMAIN\svc_account /password:ServicePass1! process call create "cmd.exe /c whoami > C:\Windows\Temp\wmi_test.txt" Cleanup
wmic /node:TARGET_HOST /user:DOMAIN\svc_account /password:ServicePass1! process call create "cmd.exe /c del C:\Windows\Temp\wmi_test.txt" Expected Telemetry
Security Event ID 4648 on initiating host. Security Event ID 4624 LogonType=3 on TARGET_HOST. Security Event ID 4688 (or Sysmon Event ID 1) showing WmiPrvSE.exe spawning cmd.exe on TARGET_HOST. Sysmon Event ID 3 showing DCOM/WMI network traffic to TARGET_HOST:135.
Expected Detection
SPL risk score elevates due to NewCredentialUse (4648) + PrivilegedLogons if svc_account has admin rights. Lateral movement hunting query flags WmiPrvSE parent-child process chain on target host.
Creates a disabled local account, enables it, and performs a local interactive logon to simulate adversary reactivation of a dormant/inactive account — a technique used by groups like Scattered Spider to abuse former employee accounts. Requires local admin.
Command
net user df00tech_dormant TempPass123! /add /comment:"Test dormant account"
net user df00tech_dormant /active:no
ping -n 3 127.0.0.1 > nul
net user df00tech_dormant /active:yes
runas /user:df00tech_dormant cmd.exe Cleanup
net user df00tech_dormant /delete Expected Telemetry
Security Event ID 4720 (account created). Security Event ID 4725 (account disabled). Security Event ID 4722 (account enabled — key indicator of reactivation). Security Event ID 4624 LogonType=2 (interactive) for df00tech_dormant. Audit event for account enabling action.
Expected Detection
Dormant account hunting query matches df00tech_dormant (disabled then re-enabled). Event ID 4722 followed quickly by 4624 for an account with no prior logon history triggers escalation criteria.
Authenticates to Azure using compromised credentials and enumerates resources, simulating Initial Access via cloud console access as performed by groups like Scattered Spider and Volt Typhoon. Uses the Azure CLI — install with: curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
Command
az login --username [email protected] --password 'CompromisedPassword1!'
az account list --output table
az ad signed-in-user show
az role assignment list --assignee [email protected] Cleanup
az logout Expected Telemetry
Azure AD SigninLogs entry with UserPrincipalName=compromised_user, AppDisplayName='Microsoft Azure CLI', ClientAppUsed='Other clients', AuthenticationRequirement='singleFactorAuthentication' (if no MFA). Azure Audit Log entries for resource enumeration. Entra ID Protection may generate a risk detection if login is from an unexpected location.
Expected Detection
KQL anomaly detection fires if location or IP is new relative to 14-day baseline. AnomalyScore includes NewLocation + NewApp (CLI vs. browser) = 2, meeting threshold. Missing MFA event adds to escalation criteria.
Performs sequential authentications using VPN endpoints in geographically separated regions within a short time window to test impossible travel detection logic. Requires access to two VPN exit nodes in different countries/regions. This validates that your SIEM correctly identifies the impossible travel pattern.
Command
# Connect to VPN exit node 1 (e.g., US)
echo '[+] Authenticating from VPN endpoint 1 (US)'
curl -s -X POST 'https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token' \
-d 'grant_type=password&client_id=CLIENT_ID&[email protected]&password=TestPass1!&scope=openid'
sleep 120
# Connect to VPN exit node 2 (e.g., EU) and repeat authentication
echo '[+] Authenticating from VPN endpoint 2 (EU) - switch VPN now'
curl -s -X POST 'https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token' \
-d 'grant_type=password&client_id=CLIENT_ID&[email protected]&password=TestPass1!&scope=openid' Cleanup
# Revoke test sessions in Entra ID admin portal or via: az ad user revoke-sign-in-sessions --id [email protected] Expected Telemetry
Two SigninLogs entries for [email protected]: first from US IP, second from EU IP approximately 2 minutes later. Entra ID Protection should generate an 'Impossible Travel' risk detection. Both entries appear in the 24h window, different Location fields.
Expected Detection
KQL hunting query for 3+ countries in 24h may not fire for only 2 countries — adjust to 2+ for testing. Entra ID Protection impossible travel detection fires independently. AnomalyScore on second login = 2 (NewLocation + NewIP), meeting KQL alert threshold.