In an ideal world, every security function would have a Detection Engineering team.
Regrettably, even organizations that are stewards of highly sensitive data often can’t afford (or don’t prioritize) the capabilities required for effective security monitoring. There can be a misconception that cloud service providers are doing the monitoring for them.
It's a challenge that Okta Security wants to help address. Whenever we write a detection for our own purposes (we use Okta, too!), there’s an untapped opportunity to use those detections to help other Okta customers prevent or respond to security incidents that stem from common credential-based attacks.
So we’ve decided to publish our detection logic. Right here! (Scroll down!)
Publishing raw detection logic will suit many of our customers. But we recognize that publishing them here won’t reach everybody, and it still puts the onus on customers to tune or adapt the detections.
That’s where mutual friends come in handy.
Over the past few months, Okta’s Defensive Cyber Operations team has shared bespoke detection logic with security analytics/SIEM providers, requesting the logic be baked into their content libraries “out of the box.”
The first of those discussions has already borne fruit with Splunk, the security analytics platform chosen most often by Okta customers, thanks to the assistance of James Brodsky, Splunk’s GVP for Security Strategy and Splunk Senior Threat Researcher Michael Haag.
As of Splunk Enterprise Security Content Update (ESCU) v3.62.0, security teams that ingest Okta System Log events into the Splunk platform can run and modify an initial set of bespoke detections in Splunk® Enterprise Security developed by Okta’s Defensive Cyber Operations team. James and Michael have tweaked these raw detections to make them more legible and applicable to a broader number of our mutual customers.
The Splunk update enhances their pre-existing analytic stories for Okta, and includes new approaches to detecting:
Session Hijacking via phishing for initial access
Post-compromise activity by threat actors abusing a stolen session token
Abuse of Push MFA (including “MFA Fatigue” attacks)
Credential Stuffing
Password Spray attacks
All of these detections are relevant to Okta Identity Engine (not the Classic Engine).
The logic for each is presented below:
Okta Phishing Detection with FastPass Origin Check
ID | T1556 |
Tactic | Phishing |
Description | Okta provides a platform detection for when a user enrolled in FastPass fails to authenticate via a real-time AiTM phishing proxy. More info here. |
Okta System Log Query | eventType eq "user.authentication.auth_via_mfa" AND result eq "FAILURE" AND outcome.reason eq "FastPass declined phishing attempt" |
Splunk Analytic | F4ca0057-cbf3-44f8-82ea-4e330ee901d3 |
Suspicious Use of an Okta Session Cookie
ID | T1539 |
Tactic | Steal Web Session Cookie |
Authors | Scott Dermott and Felicity Robson (Okta) |
Description | A detection opportunity arises when an adversary attempts to reuse a stolen web session cookie. The following analytic looks for one or more policy evaluation events in which multiple client values (IP, User Agent, etc.) change associated to the same Device Token for a specific user. The query below: Retrieves policy evaluation events from successful authentication events. Aggregates/Groups by Device Token and User, providing the first policy evaluation event in the search window. Evaluates whether there is more than one IP and whether there is more than one OS or browser for each combination of User/Device Token. |
Query | index=main sourcetype=OktaIM2:log eventType IN (policy.evaluate_sign_on) outcome.result IN (ALLOW, SUCCESS) | stats earliest(_time) as _time values(client.ipAddress) as src_ip values(client.userAgent.rawUserAgent) as user_agent values(client.userAgent.os) as userAgentOS_list values(client.userAgent.browser) as userAgentBrowser_list values(device.os_platform) as okta_device_os dc(client.userAgent.browser) as dc_userAgentBrowser dc(client.userAgent.os) as dc_userAgentOS dc(client.ipAddress) as dc_src_ip values(outcome.reason) as reason by debugContext.debugData.dtHash actor.alternateId ``` If we see different Operating Systems or Browsers from a UserAccount using with the same DTHash ``` | where dc_src_ip>1 AND (dc_userAgentOS>1 OR dc_userAgentBrowser>1) |
Splunk Analytic | 71ad47d1-d6bd-4e0a-b35c-020ad9a6959e |
Multiple Failed Requests to Access Okta Applications
ID | T1550.004, T1538 |
Tactic | Steal Web Session Cookie |
Authors | John Murphy (Okta) |
Description | A detection opportunity arises when an adversary attempts to reuse a stolen web session cookie in an org with well-configured authentication policies. The following analytic looks for multiple attempts to open app chiclets with no successful response to an authentication challenge. The query below: Retrieves policy evaluation and SSO details in events that contain the Application requested Formats target fields so we can aggregate specifically on Applications (AppInstances) Groups by User, Session and IP Creates a ratio of successful SSO events to total MFA challenges related to Application Sign On Policies Alerts when more than half of app sign on events are unsuccessful, and challenges were unsatisfied for more than three apps. |
Query | index=main sourcetype=oktaim2:log target{}.type=AppInstance (eventType=policy.evaluate_sign_on outcome.result=CHALLENGE) OR (eventType=user.authentication.sso outcome.result=SUCCESS) | eval targets=mvzip('target{}.type', 'target{}.displayName', ": ") | eval targets=mvfilter(targets LIKE "AppInstance%") ```Stats per user/session/ip/target app``` | stats count min(_time) as _time values(outcome.result) as outcome.result dc(eval(if(eventType="policy.evaluate_sign_on",targets,NULL))) as total_challenges sum(eval(if(eventType="user.authentication.sso",1,0))) as total_successes by authenticationContext.externalSessionId targets actor.alternateId client.ipAddress ```Exclude apps that don't require a challenge``` | search total_challenges > 0 ```Group events by session/actor/ip``` | stats min(_time) as _time values(*) as * sum(total_challenges) as total_challenges sum(total_successes) as total_successes values(eval(if('outcome.result'="SUCCESS",targets,NULL))) as success_apps values(eval(if('outcome.result'!="SUCCESS",targets,NULL))) as no_success_apps by authenticationContext.externalSessionId actor.alternateId client.ipAddress | fillnull | eval ratio=round(total_successes/total_challenges,2), severity="HIGH", mitre_technique_id="T1538", description='actor.alternateId'. " from " . 'client.ipAddress' . " seen opening " . total_challenges . " chiclets/apps with " . total_successes . " challenges successfully passed" | fields - count, targets ```Assuming a majority of apps have good sign-on policies, if we see three apps with ignored challenges, that's worth investigating``` | search ratio < 0.5 total_challenges > 2 |
Splunk Analytic | 1c21fed1-7000-4a2e-9105-5aaafa437247 |
Mismatch Between Source and Response for Verify Push Request
ID | T1621 |
Tactic | Multi-Factor Authentication Request Generation |
Authors | John Murphy and Jordan Ruocco (Okta) |
Description | A detection opportunity arises when an adversary that has stolen a user password attempts to trick a user into accepting a Okta Verify Push request. The following analytic identifies variations in client-based values for source and response events to identify suspicious request behavior. The detection is enhanced if the org is evaluating behavior conditions in sign-on policies using Okta Behavior Detection. The query below: Groups by SessionID and retrieves any system.push.send_factor_verify_push events (the source of the push) and user.authentication.auth_via_mfa events where the factor is OKTA_VERIFY_PUSH - (the user response to the push) Counts the total number of push events, successful authentication events, and any push sources where the client is a new device. Creates a ratio of successful sign-ins to pushes. If the ratio (currently tuned aggressively) indicates push spam, or if a user has rejected a push, the detection proceeds to evaluate whether there is more than one IP address used during the session (session roaming) and the presence of both a new IP and new device during the session. |
Query | index=main sourcetype=OktaIM2:log eventType IN (system.push.send_factor_verify_push) OR (eventType IN (user.authentication.auth_via_mfa) debugContext.debugData.factor="OKTA_VERIFY_PUSH") | eval groupby='authenticationContext.externalSessionId' ``` Each push is sent to each registered push device, so we should group pushes around the same time as a single event for the purpose of this use-case ``` | eval group_push_time=_time | bin span=2s group_push_time | fillnull value=NULL | stats min(_time) as _time by authenticationContext.externalSessionId eventType debugContext.debugData.factor outcome.result actor.alternateId client.device client.ipAddress client.userAgent.rawUserAgent debugContext.debugData.behaviors group_push_time groupby | iplocation client.ipAddress | fields - lat, lon, group_push_time ```Get counts for number of push events, successful authentication events, and any push sources where the client is a new device ``` | stats min(_time) as _time dc(client.ipAddress) as dc_ip sum(eval(if(eventType="system.push.send_factor_verify_push" AND 'outcome.result'="SUCCESS",1,0))) as total_pushes sum(eval(if(eventType="user.authentication.auth_via_mfa" AND 'outcome.result'="SUCCESS",1,0))) as total_successes sum(eval(if(eventType="user.authentication.auth_via_mfa" AND 'outcome.result'="FAILURE",1,0))) as total_rejected sum(eval(if(eventType="system.push.send_factor_verify_push" AND 'debugContext.debugData.behaviors' LIKE "%New Device=POSITIVE%",1,0))) as suspect_device_from_source sum(eval(if(eventType="system.push.send_factor_verify_push" AND 'debugContext.debugData.behaviors' LIKE "%New IP=POSITIVE%",1,0))) as suspect_ip_from_source values(eval(if(eventType="system.push.send_factor_verify_push",'client.ipAddress',""))) as src values(eval(if(eventType="user.authentication.auth_via_mfa",'client.ipAddress',""))) as dest values(*) as * by groupby | eval ratio = round(total_successes/total_pushes,2) ```Create a ratio of successful sign ins to pushes. If the push and response come from the same IP, it's likely legit. Note that the current ratio is quite aggressive. Aside from tuning the ratio you could add other conditions, for example: dc Country > 1, other behaviors (NEW Geo-Location=POSITIVE), device.managed=false, client.os!={SOE_OS}``` | search ((ratio < 0.5 AND total_pushes > 2) OR (total_rejected > 0)) AND dc_ip > 1 AND suspect_device_from_source > 0 AND suspect_ip_from_source > 0 |
Splunk Analytic | 8085b79b-9b85-4e67-ad63-351c9e9a5e9a |
ThreatInsight Alert: Login Failure with High Unknown Users
ID | T1110.004 |
Tactic | Brute Force: Credential Stuffing |
Description | Okta provides a platform detection for multiple login failures with high unknown user counts from the same IP across one or more Okta orgs. More info here. |
Okta System Log Query | eventType eq "security.threat.detected" AND outcome.reason co "Login failures with high unknown users count" |
Splunk Analytic | 632663b0-4562-4aad-abe9-9f621a049738 |
ThreatInsight Alert: Suspected Password Spray Attack
ID | T1110.003 |
Tactic | Brute Force: Password Spray |
Description | Okta provides a platform detection for failed password events across multiple user accounts. More info here. |
Okta System Log Query | eventType eq "security.threat.detected" AND outcome.reason co "Password Spray" |
Splunk Analytic | 25dbad05-6682-4dd5-9ce9-8adecf0d9ae2 |
Magic like this happens when best-in-class providers of security tools share knowledge, without any agenda outside of protecting our mutual customers.
A huge thanks to the authors and contributors in this initial effort:
James Brodsky (Splunk)
Scott Dermott (Okta)
Michael Haag (Splunk)
John Murphy (Okta)
Felicity Robson (Okta)
Jordan Ruocco (Okta)
To learn more, Splunk and Okta are hosting a joint session at .conf23, the annual Splunk conference, scheduled for July 17-20, 2023 in Las Vegas.