Update Note
Due to the recent events at MGM, which included the compromise of MGM’s Okta tenant, and the surge in attacks of Okta Admins, we have updated the threat-hunting article, adding a few relevant queries to increase visibility surrounding compromised administrators, and detection of ransom groups that tend to perform aggressive steps to cause maximum disruption to their target and prevent recovery attempts.
To read our first Blog Post – Okta Logs Decoded: Unveiling Identity Threats Through Threat Hunting, click here
Let the Hunt Continue
Scenario 1 – User Account Hijack
Social engineering for initial access is on the rise. These techniques are usually simple and do not require much technical knowledge. Attacks such as phishing, MFA relay, or even buying credentials online may help attackers compromise user accounts.
Usually, when an adversary compromises a user, gaining persistent access to that account is essential. To do so, the adversary may change the user’s password and enroll a new MFA device, and in some cases even delete the original user’s factors.
The following query identifies user accounts that performed a series of actions from an IP address that is not being used often by the organization, during a short period of time – which might suggest that these accounts are compromised. The actions that this query searches for are:
- Self-password reset
- MFA enrollment
- MFA deletion
Relevant Okta Events:
- user.mfa.factor.activate
- user.mfa.factor.deactivate
- user.account.reset_password
- user.session.start
- device.user.add
Okta Log Query
-- User Account Hijack
-- You can use the "actorAlternateId" filter to focus on administrators
select "clientIpAddress", "clientCountry", "actorAlternateId", min(time) as first_event, max(time) as last_event, count(distinct "eventType") as unique_events,
count(id) as event_count, array_agg(distinct "eventType") as events, extract(EPOCH FROM max("time")) - extract(epoch from min("time")) as duration_epoch
from audit_log_okta_idp_entity aloie
where "eventType" in ('user.mfa.factor.activate', 'user.mfa.factor.deactivate', 'user.account.reset_password', 'user.session.start', 'device.user.add')
and "actionResult" = 'SUCCESS'
and time > now() -interval '1 week'
--and "actorAlternateId" in ('admin1', 'admin2', ...)
group by "clientIpAddress", "clientCountry", "actorAlternateId"
having count(distinct "eventType") >= 3
MITRE Technique: Initial Access | Social Engineering and Phishing | ATT&CK T1566
Scenario 2 – Rogue Administrator Tenant Takeover
When an adversary successfully compromises an administrator they might try to block access to the rest of the administrators in the organization to strengthen their hold on the tenant and ensure that no one can reverse their actions.
In such a scenario, the rogue admin might try to revoke administrative privileges or disable multiple user accounts.
Use the following queries to detect the described scenario.
Relevant Okta Events:
- user.lifecycle.deactivate
- user.lifecycle.suspend
- user.account.privilege.revoke
- group.account.privilege.revoke
Okta Log Query 1
-- Multiple users disabled or deactivated by a single user
select "clientIpAddress", "clientCountry", "actorAlternateId", min(time) as first_event, max(time) as last_event,
count(distinct "targetAlternateId") filter (where "eventType"='user.lifecycle.suspend') as unique_suspended_users,
count(distinct "targetAlternateId") filter (where "eventType"='user.lifecycle.deactivate') as unique_deactivated_users
from (select aloie.time ,aloie."clientIpAddress", aloie."clientCountry", aloie."actorAlternateId",aloie."eventType", altoie."targetAlternateId"
from audit_log_okta_idp_entity aloie, audit_log_target_okta_idp_entity altoie
where "eventType" in ('user.lifecycle.deactivate', 'user.lifecycle.suspend')
and aloie."actionResult" = 'SUCCESS'
and aloie.id = altoie."auditLogId") base
group by "clientIpAddress", "clientCountry", "actorAlternateId"
having (count(distinct "targetAlternateId") filter (where "eventType"='user.lifecycle.suspend') > 1 or count(distinct "targetAlternateId") filter (where "eventType"='user.lifecycle.deactivate') > 1)
Okta Log Query 2
-- Multiple admin privileges revoked
select "clientIpAddress", "clientCountry", "actorAlternateId", min(time) as first_event, max(time) as last_event,
count(distinct "targetAlternateId") filter (where "eventType"='user.account.privilege.revoke') as revoked_users,
count(distinct "targetAlternateId") filter (where "eventType"='group.account.privilege.revoke') as revoked_groups
from (select aloie.time ,aloie."clientIpAddress", aloie."clientCountry", aloie."actorAlternateId",aloie."eventType", altoie."targetAlternateId"
from audit_log_okta_idp_entity aloie, audit_log_target_okta_idp_entity altoie
where "eventType" in ('user.account.privilege.revoke', 'group.account.privilege.revoke')
and aloie."actionResult" = 'SUCCESS'
and aloie.id = altoie."auditLogId") base
group by "clientIpAddress", "clientCountry", "actorAlternateId"
having (count(distinct "targetAlternateId") filter (where "eventType"='user.account.privilege.revoke') > 1 or count(distinct "targetAlternateId") filter (where "eventType"='group.account.privilege.revoke') > 1)
MITRE Technique: Impact | Account Access Removal | ATT&CK T1531
Scenario 3 – Authentication Policy Downgrade
When an adevrary successfully compromises an administrator account, they may downgrade the tenant’s authentication requirement to ease their access to the tenant. Policy changes are not events that are triggered frequently since these are sensitive events that occur when the organization updates their authentication requirements. We can use these event to hunt for an adversary that made multiple changes to authentication policies and rules with the following query.
Relevant Okta Events:
- policy.lifecycle.update
- policy.rule.update
- policy.rule.add
Okta Log Query
-- Multiple authentication policy and rules changes
select "clientIpAddress", "clientCountry", "actorAlternateId", min(time) as first_event, max(time) as last_event,
count(distinct "targetAlternateId") filter (where "eventType"='policy.lifecycle.update') as unique_policies_updated,
count(distinct "targetAlternateId") filter (where "eventType"='policy.rule.update') as unique_policy_rules_updated,
count(distinct "targetAlternateId") filter (where "eventType"='policy.rule.add') as unique_policy_rules_created,
count(id) as event_count
from (select aloie.id, aloie.time ,aloie."clientIpAddress", aloie."clientCountry", aloie."actorAlternateId",aloie."eventType", altoie."targetAlternateId"
from audit_log_okta_idp_entity aloie, audit_log_target_okta_idp_entity altoie
where "eventType" in ('policy.lifecycle.update', 'policy.rule.update', 'policy.rule.add')
and aloie."actionResult" = 'SUCCESS'
and aloie.id = altoie."auditLogId") base
group by "clientIpAddress", "clientCountry", "actorAlternateId"
having count(id) >= 3
MITRE Technique: Persistence | Modify Authentication Process | ATT&CK T1556
Scenario 4 – Authentication Via Proxy
Adversaries will try to disguise their origin IP addresses using proxy solutions. When a user uses a proxy for authentication, Okta marks the sign-in as such. Monitor administrators that are logging in via proxy to detect suspicious administrator sign-ins.
Relevant Okta Events:
- user.session.start
Okta Log Query
-- Proxy Authentication
select "clientIpAddress", "clientCountry", "actorAlternateId", min(time) as first_event, max(time) as last_event, age(max(time), min(time)) as duration,
count(id) as event_count
from audit_log_okta_idp_entity aloie
where "eventType" ='user.session.start'
and "actorAlternateId" in ('admin1', 'admin2', ...)
and "isProxy" = true
and "actionResult" = 'SUCCESS'
group by "clientIpAddress", "clientCountry", "actorAlternateId"
MITRE Technique: Initial Access | Proxy Usage | ATT&CK T1090
2 Additional Queries For Administrative Okta Governance
Okta Log Query 1 – Access to Okta Admin App from Rare Locations
Monitor access to the Okta admin app from rare IP addresses and search for unauthorized access to the Okta Admin app.
Relevant Okta Events:
- user.session.access_admin_app
Okta Log Query
-- Admin app access from non-oranizational IP addresses
with org_ips as (SELECT count("timebucket"),"clientIpAddress", "clientCountry"
FROM (
SELECT DATE_TRUNC('day', "time") AS TimeBucket, COUNT(distinct "actorAlternateId") AS "userCount", "clientIpAddress", "clientCountry"
FROM audit_log_okta_idp_entity
WHERE "actionResult" = 'SUCCESS'
AND "time" > now() -interval '1 week'
GROUP BY TimeBucket, "clientIpAddress", "clientCountry"
HAVING COUNT(distinct "actorAlternateId") > 2
) subquery
GROUP BY "clientIpAddress", "clientCountry"
HAVING count("timebucket") > 1)
select time, "clientIpAddress", "clientCountry", "actorAlternateId", "eventType" from audit_log_okta_idp_entity aloie
where "eventType" ='user.session.access_admin_app'
and aloie."clientIpAddress" not in (select distinct "clientIpAddress" from org_ips)
order by time desc
MITRE Technique: https://attack.mitre.org/techniques/T1078/
Okta Log Query 2 – Admin Sign-In With Abnormal Client Characteristics
Note – The following query is relevant only for tenants who use Okta’s behavior detections in their session policies.
Use Okta’s sign-in behavior enrichments to detect suspicious sign-ins to Okta administrators.
Relevant Azure AD Event Source
- Azure AD Directory Audit Logs
Okta Log Query
-- Admin Sign-In With Abnormal Client Characteristics
select time, "clientIpAddress", "clientCountry", "actorAlternateId", "eventType" from audit_log_okta_idp_entity aloie
where "eventType" ='user.session.start' and "actionResult"='SUCCESS'
and "actorAlternateId" in ('admin1', 'admin2', ...)
and "clientBehaviorVelocity" = true
and "clientBehaviorNewIP" = true
and "clientBehaviorNewDevice" = true
and "clientBehaviorNewCountry" = true
and "clientBehaviorNewGeoLocation" = true
order by time desc
MITRE Technique: https://attack.mitre.org/techniques/T1078/
Learn More
Discover more Okta Security best practices to Implement Now with Rezonate.