Zscaler ZPA/ZIA - Perfect Impostor: Account Takeover Hiding Within Normal Traffic
36 CSL ZPA Perfect Impostor Account Takeover
Query
let baselineWindow = 14d;
let recentWindow = 4h;
let ZPA_Baseline =
CommonSecurityLog
| where TimeGenerated between (ago(baselineWindow) .. ago(recentWindow))
| where DeviceVendor == "Zscaler" and DeviceProduct has "ZPA"
| where DeviceAction !in ("block", "BLOCK", "Failed")
| where isnotempty(SourceUserName)
| extend BaselineCountry = tostring(geo_info_from_ip_address(SourceIP).country)
| summarize
BaselineCountries = make_set(BaselineCountry, 20),
BaselineAppCount = dcount(DestinationHostName)
by UserName = tolower(SourceUserName);
let ZPA_Recent =
CommonSecurityLog
| where TimeGenerated > ago(recentWindow)
| where DeviceVendor == "Zscaler" and DeviceProduct has "ZPA"
| where isnotempty(SourceUserName)
| extend RecentCountry = tostring(geo_info_from_ip_address(SourceIP).country)
| summarize
RecentCountries = make_set(RecentCountry, 5),
RecentApps = make_set(DestinationHostName, 10),
RecentIPs = make_set(SourceIP, 5),
RecentConnCount = count(),
ZPA_FirstSeen = min(TimeGenerated)
by UserName = tolower(SourceUserName);
let ZIA_Suspicious =
CommonSecurityLog
| where TimeGenerated > ago(recentWindow)
| where DeviceVendor == "Zscaler"
| where isnotempty(SourceUserName)
| where DeviceCustomString2 has_any (
"REMOTE_ACCESS_TOOLS", "REMOTE_ADMINISTRATION", "WEB_BASED_ADMIN",
"ACCOUNT_CREATION", "TUNNEL_SOCKS_PROXY", "ANONYMOUS_PROXY",
"ONLINE_STORAGE", "FILE_SHARE", "TOR", "VPN_SERVICES",
"NEWLY_REGISTERED_DOMAINS", "PHISHING")
| summarize
ZIA_Categories = make_set(DeviceCustomString2, 10),
ZIA_Destinations = make_set(DestinationHostName, 10),
ZIA_RequestCount = count(),
ZIA_FirstSeen = min(TimeGenerated)
by UserName = tolower(SourceUserName);
let IdP_Changes =
OfficeActivity
| where TimeGenerated > ago(recentWindow)
| where isnotempty(UserId)
| where Operation in (
"New-InboxRule",
"Set-Mailbox",
"Add-MailboxPermission",
"Add OAuth2PermissionGrant",
"Consent to application",
"Add service principal credentials",
"Update user",
"Disable Strong Authentication",
"Update StsRefreshTokenValidFrom",
"Add member to role")
| summarize
IdP_EventCount = count(),
IdP_Operations = make_set(Operation, 10),
IdP_FirstSeen = min(TimeGenerated)
by UserName = tolower(UserId);
ZPA_Recent
| join kind=inner ZPA_Baseline on UserName
| extend NewCountries = set_difference(RecentCountries, BaselineCountries)
| join kind=leftouter ZIA_Suspicious on UserName
| join kind=leftouter IdP_Changes on UserName
| extend
ZIA_RequestCount = coalesce(ZIA_RequestCount, 0),
IdP_EventCount = coalesce(IdP_EventCount, 0)
| extend ImpostorScore =
iff(array_length(NewCountries) > 0, 40, 0)
+ (ZIA_RequestCount * 5)
+ (IdP_EventCount * 30)
| where ImpostorScore >= 40
or (IdP_EventCount >= 1 and ZIA_RequestCount >= 1)
or array_length(NewCountries) > 0
| project
UserName,
NewCountries, RecentCountries, BaselineCountries,
RecentApps, RecentIPs, RecentConnCount,
ZIA_Categories, ZIA_Destinations, ZIA_RequestCount,
IdP_Operations, IdP_EventCount,
ImpostorScore,
ZPA_FirstSeen
| order by ImpostorScore descExplanation
This query is designed to detect potential account takeovers by identifying unusual behavior across different layers of user activity. Here's a simplified breakdown:
-
Purpose: The query aims to identify "perfect impostor" scenarios where an attacker uses stolen credentials and mimics a legitimate user's behavior but introduces subtle anomalies.
-
Layers Analyzed:
- ZPA Layer: Checks for user sessions from countries not seen in the past 14 days, indicating possible use of a new device, VPN, or compromised session.
- ZIA Layer: Looks for browsing activity to suspicious sites like remote admin tools, proxies, or newly registered domains, which are not typical for the user.
- IdP/SaaS Layer: Monitors critical account changes such as MFA removal or privilege escalation.
-
Scoring: Each layer is scored individually. A high score or a combination of suspicious activities across layers flags the account as potentially compromised.
-
Outcome: The query generates a prioritized list of high-risk accounts for further review and action, such as session termination or MFA re-enforcement, to prevent attackers from gaining persistence or escalating privileges.
-
Frequency and Duration: The query runs every 4 hours and analyzes data from the past 14 days.
-
Alerting: If suspicious activity is detected, an alert is created with details about the anomalies and a calculated "ImpostorScore" to prioritize investigation.
Overall, this query helps security teams quickly identify and respond to potential account takeovers by correlating anomalies across multiple layers of user activity.