-
Notifications
You must be signed in to change notification settings - Fork 487
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[New Hunt] Add Initial Okta Hunting Queries (#4064)
* adding new Okta hunting queries * query format changes * adding docs * added query for mfa bombing * adding remainder hunting queries * adjusted incorrect hunt * updated queries * updated queries based on Samir's feedback * removed failed login eval * updated docs (cherry picked from commit 9181c00)
- Loading branch information
1 parent
ec92d4f
commit a6bd8df
Showing
28 changed files
with
1,204 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
...ng/okta/docs/docs/credential_access_hgher_than_average_failed_authentication.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Identify High Average of Failed Daily Authentication Attempts | ||
|
||
--- | ||
|
||
## Metadata | ||
|
||
- **Author:** Elastic | ||
- **Description:** This hunting query identifies when the average number of failed daily authentication attempts is higher than normal in Okta. Adversaries may attempt to brute force user credentials to gain unauthorized access to accounts. This query calculates the average number of daily failed authentication attempts for each user and identifies when the average is higher than normal. | ||
|
||
- **UUID:** `c8a35a26-71f1-11ef-9c4e-f661ea17fbcc` | ||
- **Integration:** [okta](https://docs.elastic.co/integrations/okta) | ||
- **Language:** `[ES|QL]` | ||
- **Source File:** [Identify High Average of Failed Daily Authentication Attempts](../queries/credential_access_hgher_than_average_failed_authentication.toml) | ||
|
||
## Query | ||
|
||
```sql | ||
from logs-okta* | ||
| where @timestamp > NOW() - 7 day | ||
|
||
// truncate the timestamp to daily intervals | ||
| eval target_time_window = DATE_TRUNC(1 days, @timestamp) | ||
| where | ||
|
||
// filter for invalid credential authentication events | ||
event.action == "user.session.start" | ||
and okta.outcome.result == "FAILURE" | ||
and okta.outcome.reason == "INVALID_CREDENTIALS" | ||
|
||
// add a count of 1 for each failed login | ||
| eval failed_login_count = 1 | ||
|
||
| stats | ||
// count the number of daily failed logins for each day and user | ||
failed_daily_logins = count(*) by target_time_window, okta.actor.alternate_id | ||
|
||
| stats | ||
// calculate the average number of daily failed logins for each day | ||
avg_daily_logins = avg(failed_daily_logins) by target_time_window | ||
|
||
// sort the results by the average number of daily failed logins in descending order | ||
| sort avg_daily_logins desc | ||
``` | ||
|
||
## Notes | ||
|
||
- Pivot to users by only keeping the first stats statement where `okta.actor.alternate_id` is the targeted accounts. | ||
- Pivot for successful logins from the same source IP by searching for `event.action` equal to `user.session.start` or `user.authentication.verify` where the outcome is `SUCCESS`. | ||
- User agents can be used to identify anomalous behavior, such as a user agent that is not associated with a known application or user. | ||
- Another `WHERE` count can be added to the query if activity has been baseline to filter out known behavior. | ||
|
||
## MITRE ATT&CK Techniques | ||
|
||
- [T1078.004](https://attack.mitre.org/techniques/T1078/004) | ||
|
||
## License | ||
|
||
- `Elastic License v2` |
46 changes: 46 additions & 0 deletions
46
hunting/okta/docs/docs/credential_access_mfa_bombing_push_notications.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Rapid MFA Deny Push Notifications (MFA Bombing) | ||
|
||
--- | ||
|
||
## Metadata | ||
|
||
- **Author:** Elastic | ||
- **Description:** This hunting query identifies MFA bombing attacks in Okta. Adversaries may attempt to flood a user with multiple MFA push notifications to disrupt operations or gain unauthorized access to accounts. This query identifies when a user has more than 5 MFA deny push notifications in a 10 minute window. | ||
|
||
- **UUID:** `223451b0-6eca-11ef-a070-f661ea17fbcc` | ||
- **Integration:** [okta](https://docs.elastic.co/integrations/okta) | ||
- **Language:** `[ES|QL]` | ||
- **Source File:** [Rapid MFA Deny Push Notifications (MFA Bombing)](../queries/credential_access_mfa_bombing_push_notications.toml) | ||
|
||
## Query | ||
|
||
```sql | ||
from logs-okta* | ||
| where @timestamp > NOW() - 7 day | ||
|
||
// Truncate the timestamp to 10 minute windows | ||
| eval target_time_window = DATE_TRUNC(10 minutes, @timestamp) | ||
|
||
// Filter for MFA deny push notifications | ||
| where event.action == "user.mfa.okta_verify.deny_push" | ||
|
||
// Count the number of MFA deny push notifications for each user in each 10 minute window | ||
| stats deny_push_count = count(*) by target_time_window, okta.actor.alternate_id | ||
|
||
// Filter for users with more than 5 MFA deny push notifications | ||
| where deny_push_count >= 5 | ||
``` | ||
|
||
## Notes | ||
|
||
- `okta.actor.alternate_id` is the targeted user account. | ||
- Pivot and search for `event.action` is `user.authentication.auth_via_mfa` to determine if the target user accepted the MFA push notification. | ||
- If a MFA bombing attack is suspected, both username and password are required prior to MFA push notifications. Thus the credentials are likely compromised. | ||
|
||
## MITRE ATT&CK Techniques | ||
|
||
- [T1621](https://attack.mitre.org/techniques/T1621) | ||
|
||
## License | ||
|
||
- `Elastic License v2` |
53 changes: 53 additions & 0 deletions
53
hunting/okta/docs/docs/credential_access_password_spraying_from_repeat_source.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Password Spraying from Repeat Source | ||
|
||
--- | ||
|
||
## Metadata | ||
|
||
- **Author:** Elastic | ||
- **Description:** This hunting query identifies password spraying attacks in Okta where the same source IP attempts to authenticate to multiple accounts with invalid credentials. Adversaries may attempt to use a single source IP to avoid detection and bypass account lockout policies. | ||
|
||
- **UUID:** `1c2d2b08-71ee-11ef-952e-f661ea17fbcc` | ||
- **Integration:** [okta](https://docs.elastic.co/integrations/okta) | ||
- **Language:** `[ES|QL]` | ||
- **Source File:** [Password Spraying from Repeat Source](../queries/credential_access_password_spraying_from_repeat_source.toml) | ||
|
||
## Query | ||
|
||
```sql | ||
from logs-okta* | ||
| where @timestamp > NOW() - 7 day | ||
|
||
// truncate the timestamp to daily intervals | ||
| eval target_time_window = DATE_TRUNC(1 days, @timestamp) | ||
| where | ||
|
||
// filter for invalid credential events | ||
event.action == "user.session.start" | ||
and okta.outcome.result == "FAILURE" | ||
and okta.outcome.reason == "INVALID_CREDENTIALS" | ||
| stats | ||
// count the distinct number of targeted accounts | ||
target_count = count_distinct(okta.actor.alternate_id), | ||
|
||
// count the number of invalid credential events for each source IP | ||
source_count = count(*) by target_time_window, okta.client.ip | ||
|
||
// filter for source IPs with more than 5 invalid credential events | ||
| where target_count >= 5 | ||
``` | ||
|
||
## Notes | ||
|
||
- `okta.actor.alternate_id` are the targeted accounts. | ||
- Pivot for successful logins from the same source IP by searching for `event.action` equal to `user.session.start` or `user.authentication.verify` where the outcome is `SUCCESS`. | ||
- User agents can be used to identify anomalous behavior, such as a user agent that is not associated with a known application or user. | ||
- The `target_count` can be adjusted depending on the organization's account lockout policy or baselined behavior. | ||
|
||
## MITRE ATT&CK Techniques | ||
|
||
- [T1078.004](https://attack.mitre.org/techniques/T1078/004) | ||
|
||
## License | ||
|
||
- `Elastic License v2` |
48 changes: 48 additions & 0 deletions
48
...ocs/docs/credential_access_rapid_reset_password_requests_for_different_users.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Rapid Reset Password Requests for Different Users | ||
|
||
--- | ||
|
||
## Metadata | ||
|
||
- **Author:** Elastic | ||
- **Description:** This hunting query identifies rapid reset password requests for different users in Okta. Adversaries may attempt to reset passwords for multiple users in rapid succession to gain unauthorized access to accounts or disrupt operations. This query identifies when the source user is different from the target user in reset password events and filters for users with more than 15 reset password attempts. | ||
|
||
- **UUID:** `c784106e-6ae8-11ef-919d-f661ea17fbcc` | ||
- **Integration:** [okta](https://docs.elastic.co/integrations/okta) | ||
- **Language:** `[ES|QL]` | ||
- **Source File:** [Rapid Reset Password Requests for Different Users](../queries/credential_access_rapid_reset_password_requests_for_different_users.toml) | ||
|
||
## Query | ||
|
||
```sql | ||
from logs-okta.system* | ||
| where @timestamp > NOW() - 7 day | ||
|
||
// Filter for reset password events where the source user is different from the target user | ||
| where event.dataset == "okta.system" and event.action == "user.account.reset_password" and source.user.full_name != user.target.full_name | ||
|
||
// Extract relevant fields | ||
| keep @timestamp, okta.actor.alternate_id, okta.debug_context.debug_data.dt_hash, user.target.full_name, okta.outcome.result | ||
|
||
// Count the number of reset password attempts for each user | ||
| stats | ||
user_count = count_distinct(user.target.full_name), | ||
reset_counts = by okta.actor.alternate_id, source.user.full_name, okta.debug_context.debug_data.dt_hash | ||
|
||
// Filter for more than 10 unique users and more than 15 reset password attempts by the source | ||
| where user_count > 10 and reset_counts > 15 | ||
``` | ||
|
||
## Notes | ||
|
||
- `okta.actor.alternate_id` is the potentially compromised account | ||
- An API access token may have been compromised, where okta.actor.alternate_id reflects the owner | ||
- To identify a list of tokens this user created, search for the `okta.actor.alternate_id` where `event.action` is `system.api_token*` which may require a larger time window | ||
|
||
## MITRE ATT&CK Techniques | ||
|
||
- [T1098.001](https://attack.mitre.org/techniques/T1098/001) | ||
|
||
## License | ||
|
||
- `Elastic License v2` |
51 changes: 51 additions & 0 deletions
51
...cs/defense_evasion_failed_oauth_access_token_retrieval_via_public_client_app.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Failed OAuth Access Token Retrieval via Public Client App | ||
|
||
--- | ||
|
||
## Metadata | ||
|
||
- **Author:** Elastic | ||
- **Description:** This hunting query identifies when a public client app fails to retrieve an OAuth access token using client credentials because of an uauthorized scope. Adversaries may attempt to retrieve access tokens using client credentials to bypass user authentication and access resources. This query identifies when a public client app fails to retrieve an access token using client credentials and scopes that are not implicitly granted. | ||
|
||
- **UUID:** `0b936024-71d9-11ef-a9be-f661ea17fbcc` | ||
- **Integration:** [okta](https://docs.elastic.co/integrations/okta) | ||
- **Language:** `[ES|QL]` | ||
- **Source File:** [Failed OAuth Access Token Retrieval via Public Client App](../queries/defense_evasion_failed_oauth_access_token_retrieval_via_public_client_app.toml) | ||
|
||
## Query | ||
|
||
```sql | ||
from logs-okta.system* | ||
| where @timestamp > NOW() - 7 day | ||
| where | ||
event.dataset == "okta.system" | ||
|
||
// filter on failed access token grant requests where source is a public client app | ||
and event.action == "app.oauth2.as.token.grant" | ||
and okta.actor.type == "PublicClientApp" | ||
and okta.outcome.result == "FAILURE" | ||
|
||
// filter out known Okta and Datadog actors | ||
and not ( | ||
okta.actor.display_name LIKE "Okta%" | ||
or okta.actor.display_name LIKE "Datadog%" | ||
) | ||
|
||
// filter for scopes that are not implicitly granted | ||
and okta.outcome.reason == "no_matching_scope" | ||
``` | ||
|
||
## Notes | ||
|
||
- Review `okta.debug_context.debug_data.flattened.grantType` to identify if the grant type is `client_credentials` | ||
- Ignore `okta.debug_context.debug_data.flattened.requestedScopes` values that indicate read-only access | ||
- Review `okta.actor.display_name` to identify the public client app that attempted to retrieve the access token. This may help identify the compromised client credentials. | ||
- Pivot for successful access token retrieval by the same public client app by searching `event.action` equal to `app.oauth2.as.token.grant.access_token` where the display name is the same. | ||
|
||
## MITRE ATT&CK Techniques | ||
|
||
- [T1550.001](https://attack.mitre.org/techniques/T1550/001) | ||
|
||
## License | ||
|
||
- `Elastic License v2` |
54 changes: 54 additions & 0 deletions
54
...s/docs/defense_evasion_multiple_application_sso_authentication_repeat_source.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Multiple Application SSO Authentication from the Same Source | ||
|
||
--- | ||
|
||
## Metadata | ||
|
||
- **Author:** Elastic | ||
- **Description:** This hunting query identifies when a user authenticates to multiple applications using Single Sign-On (SSO) from the same source. Adversaries may attempt to authenticate to multiple applications using SSO to gain unauthorised access to sensitive data or resources. Adversaries also rely on refresh tokens to maintain access to applications and services. This query identifies when a source IP authenticates to more than 15 applications using SSO within a 5-minute window. | ||
|
||
- **UUID:** `03bce3b0-6ded-11ef-9282-f661ea17fbcc` | ||
- **Integration:** [okta](https://docs.elastic.co/integrations/okta) | ||
- **Language:** `[ES|QL]` | ||
- **Source File:** [Multiple Application SSO Authentication from the Same Source](../queries/defense_evasion_multiple_application_sso_authentication_repeat_source.toml) | ||
|
||
## Query | ||
|
||
```sql | ||
from logs-okta* | ||
| eval target_time_window = DATE_TRUNC(5 minutes, @timestamp) | ||
|
||
// truncate the timestamp to a 5-minute window | ||
| where @timestamp > now() - 7 day | ||
|
||
// filter for SSO authentication events where the authentication step is 0 | ||
// filter on request URI string '/app/' to identify applications for a user | ||
| where | ||
event.action == "user.authentication.sso" | ||
and okta.authentication_context.authentication_step == 0 | ||
and okta.debug_context.debug_data.request_uri RLIKE "(.*)/app/(.*)" | ||
|
||
// dissect the request URI to extract the target application | ||
| dissect okta.debug_context.debug_data.request_uri"%{?}/app/%{target_application}/" | ||
|
||
// count the number of unique applications per source IP and user in a 5-minute window | ||
| stats application_count = count_distinct(target_application), window_count = count(*) by target_time_window, source.ip, okta.actor.alternate_id | ||
|
||
// filter for at least 15 distinct applications authenticated from a single source IP | ||
| where application_count > 15 | ||
``` | ||
|
||
## Notes | ||
|
||
- `okta.debug_context.debug_data.dt_hash` field can be used to identify the device token hash used for authentication. This can be used to pivot for additional activity from the same device. | ||
- `okta.debug_context.debug_data.flattened` contains additional information such as request ID, trace ID, sign-on mode and more to review for anomalies in the authentication flow. | ||
- `okta.request.ip_chain` can be used to understand more about the source address, which is potentially useful for profiling. | ||
- If `okta.security_context.is_proxy` is `true`, then an adversary may be attempting to mask their true source behind a proxy or VPN. | ||
|
||
## MITRE ATT&CK Techniques | ||
|
||
- [T1550.001](https://attack.mitre.org/techniques/T1550/001) | ||
|
||
## License | ||
|
||
- `Elastic License v2` |
Oops, something went wrong.