As organizations continue to shift to cloud-based or entirely cloud-native environments, incident responders now have the challenging task of researching and deciphering how each SaaS vendor can be both attacked and investigated. In this series, Mitiga incident responders share knowledge we’ve gained from our investigations and threat hunting to provide insight into the key log fields to use when investigating SaaS compromises.

For part one of this series, we will focus on Okta System Logs. The Okta System Log “records system events that are related to your organization in order to provide an audit trail that can be used to understand platform activity and to diagnose problems.1" While Okta System Logs give incident responders an opportunity for both forensic investigation and detection, there are various pitfalls and issues that they might also encounter. This blog will highlight those challenges, offer strategies to overcome them, and pseudocode to help you track sessions in Okta effectively. You can implement the pseudocode provided as an investigation function or use it as a query during an investigation.

Okta System Log Key Fields

The table below provides a list of important fields for tracking sessions, hunting, and investigating in Okta. As with many SaaS vendors, logs can change, new research may be conducted, and investigative techniques must adapt accordingly. Make sure to check back periodically for updates to this table and feel free to reach out to us if we can improve its content. 

While most of these fields are accurate and perform as expected, we have found that the debugContext.debugData.risk and debugContext.debugData.deviceFingerprint fields have inaccuracies and limitations that investigators and detection engineers should be aware of. Even if you are familiar with Okta logs, we recommend reviewing the notes on these two specific fields to understand the highlighted challenges.

Field Description Sample Value
published Action timestamp 2024-01-10T07:32:48.742Z
actor.alternateId This reflects the actor's identity, often their email, dependent on the 'actor_type'. For 'User', it's the user's email; 'PublicClientAppEntity' defaults to 'unknown'; 'SystemPrincipal' is either 'supportuser@okta.com' or 'system@okta.com'; 'Event Hook' remains unset. 'PublicClientApp' links to 'actor.id'. 0oae2szv32xaTYRst2p7
suspect_user@acme.com
unknown
supportuser@okta.com
system@okta.com
actor.id This reflects the actor's identity, identified by an Okta-specific identifier. 0oae2XXXXXXXXXXst2p7
actor.type Okta actor type. PublicClientApp
User
PublicClientAppEntity
SystemPrincipal
Event Hook
client.device Client device type. unknown
Unknown
Computer
Mobile
Tablet
client.ipAddress Client request IP address: either IPv4 or IPv6 format. 127.0.0.1
client.userAgent.rawUserAgent User agent of the web request used by the actor to perform an action. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
client.userAgent.browser Browser family identified by Okta from the user agent. FIREFOX
CHROME
unknown
client.zone Client zone name, based on client.ipAddress subnet range. This is organization specific as defined by organizations admins. null
<Custom Zone name>
client.geographicalContext.city City determined by Okta based on client.ipAddress. Charlestown
Kingston
New York
client.geographicalContext.country Country determined by Okta based on client.ipAddress. United States
India
Czechia
eventType Event type published, as detailed in Okta's documentation: Okta Event Types.2 system.email.mfa_reset_notification.sent_message
displayMessage Event display message: A human-readable description of the eventType. Send user MFA enrollment notification email
target.type Refers to the zero or more types that the action targets. ["AuthenticatorMethod","AuthenticatorMethod","AppInstance"]
target.displayName Target.type refers to the zero or more types that the action targets. Target.type and Target.DisplayName values are ordered. Think of Target.type as the key and Target.DisplayName as the corresponding values. ["Password","Okta Verify","Okta Dashboard"]
outcome.result The result of the eventType. SUCCESS
ALLOW
CHALLENGE
FAILURE
null
DENY
outcome.reason Reason for the result. Null if it was successful, otherwise it is populated with reason. Sign-on policy evaluation resulted in AUTHENTICATED
login_required
INVALID_CREDENTIALS
delivered
VERIFICATION_ERROR
LOCKED_OUT
no_matching_policy
transaction.id The ID of a series of actions, authenticated or not, that identifies events occurring together, such as a request to Okta's servers. The value will be identical to debugContext.debugData.requestId or debugContext.debugData.emailRequestId. f938cb7b727fe8XXXXXXXXXXXXXXXXXX
16a39fde26f5f6XXXXXXXXXXXXXXXXXX
3513cb19071ddcXXXXXXXXXXXXXXXXXX
securityContext.asOrg The organization, ASN, associated with the client's IP address from which the eventType was initiated. cox communications
amazon technologies inc.
t-mobile
authenticationContext.externalSessionId This ID is set following successful authentication and is unique per user session. Useful for correlating events that occurred within the same user session. 102XXXXXXXX
trsXXXXXXXX
idxXXXXXXXX
debugContext The debugContext field provides additional information for certain types of events where the default fields are insufficient to adequately describe the operations performed by the event. It contains valuable sub-fields, some of which have been documented in this sheet. The size and content of debugContext depend on the event type. { debugData: { behaviors: "{New Geo-Location=NEGATIVE, New Device=BAD_REQUEST, New IP=NEGATIVE, New State=NEGATIVE, New Country=NEGATIVE, Velocity=NEGATIVE, New City=NEGATIVE}", requestId: "3513cb19071ddcXXXXXXXXXXXXXXXXXX", dtHash: "1b9cdd35a8d4f0708072ae6957324c9adf8XXXXXXXXXXXXXXXXXX", risk: "{reasons=Anomalous Device, level=HIGH}", requestUri: "/api/v1/authn", threatSuspected: "false", url: "/api/v1/authn?" } }
debugContext.debugData.risk Okta performs a risk assessment for actions performed and assigns the risk level to this field. For instance, the risk level for a sign-in event might be determined by factors such as anomalous location, anomalous device, suspected threats based on Okta ThreatInsight detection, or missing cookies.

While this field provides valuable information, it should be interpreted with caution. At the time of writing historical examination revealed issues, such as the error-prone nature of anomalous device detection due to limitations in device fingerprinting.

Additionally, there may be bugs affecting anomalous location detection, where an IP address may appear to be from a new country despite being associated with a known city.
{reasons=Anomalous Location, Anomalous Device, level=HIGH}
null
{level=LOW}
debugContext.debugData.behaviours This field provides insight into the risk assessment performed by Okta, which is recorded as boolean assignments (True or False). {New Geo-Location=UNKNOWN, New Device=UNKNOWN, New IP=UNKNOWN, New State=UNKNOWN, New Country=UNKNOWN, Velocity=UNKNOWN, New City=UNKNOWN}
{New Geo-Location=NEGATIVE, New Device=NEGATIVE, New IP=NEGATIVE, New State=NEGATIVE, New Country=NEGATIVE, Velocity=NEGATIVE, New City=NEGATIVE}
debugContext.debugData.factor Authentication factor used for the action. This field is only set for "user.authentication.auth_via_mfa" events. SECURITY_QUESTION
OKTA_VERIFY_PUSH
FIDO_WEBAUTHN
PASSWORD_AS_FACTOR
SMS_FACTOR
OKTA_SOFT_TOKEN
SIGNED_NONCE
debugContext.debugData.factorIntent The initial actor intent that triggered the factor. This field is present for "user.authentication.verify" and "user.authentication.auth_via_mfa" events. AUTHENTICATION
CREDENTIAL_ENROLLMENT
CREDENTIAL_MODIFY
ENROLLMENT
LOGIN
RECOVERY
UNLOCK_ACCOUNT
debugContext.debugData.requestId The ID of a request, which identifies events occurring together as part of an operation (e.g., a request to Okta's servers). The value will be identical to transaction.id or debugContext.debugData.emailRequestId. It's recommended to use transaction.id. f938cb7b727fe8XXXXXXXXXXXXXXXXXX
16a39fde26f5f6XXXXXXXXXXXXXXXXXX
3513cb19071ddcXXXXXXXXXXXXXXXXXX
debugContext.debugData.emailRequestId If an action results in a "system.email.delivery" event, the transaction.id value of this event is recorded in this field. The value will be identical to transaction.id or debugContext.debugData.requestId. f938cb7b727fe8XXXXXXXXXXXXXXXXXX
16a39fde26f5f6XXXXXXXXXXXXXXXXXX
3513cb19071ddcXXXXXXXXXXXXXXXXXX
debugContext.debugData.authnRequestId Unique authentication request ID. The value may or may not be identical to transaction.id, debugContext.debugData.requestId, or debugContext.debugData.emailRequestId. f938cb7b727fe8XXXXXXXXXXXXXXXXXX
16a39fde26f5f6XXXXXXXXXXXXXXXXXX
3513cb19071ddcXXXXXXXXXXXXXXXXXX
debugContext.debugData.dtHash Based on available documentation, this field appears to represent the device token hash. While the exact calculation method is unclear, it seems to be a SHA256 hash. Overlap across multiple user accounts is possible. This field serves as a good indicator when targeting a single account to identify potential theft of session tokens. 9def5cf1c6bbb852021970f8a60cd176810XXXXXXXXXXXXXXXXXX
a57f0562fbf22edf89a6028abfcfb688a0fXXXXXXXXXXXXXXXXXX
1b9cdd35a8d4f0708072ae6957324c9adf8XXXXXXXXXXXXXXXXXX
debugContext.debugData.deviceFingerprint This field is intended to represent a unique device ID. However, significant overlap is observed, and there is no clear pattern regarding its calculation.

Documentation lacks clarity on the calculation method, suggesting that different tools may set it differently. It could be based solely on the user agent or utilize other browser-based fingerprinting techniques, such as cookies, device information, and IPs.

When used for investigation, it's important to note the common overlaps in this field. While it might appear that multiple users are using the same device, caution is advised. It's recommended to combine this information with other indicators to track malicious activity.
a9e2d1bbb4b46dd0a33b801c5f0a3c38
c74eee4d09815fa3a9d42c97a23d71e2
4beb8a4ca5af2388fc0e1ebdaeb11f46
debugContext.debugData.deviceCategory This field is set for system.push.send_factor_verify_push events. It specifies the device type where the MFA response was received/responded to. SmartPhone_Android
SmartPhone_IPhone

Session Tracking

In the event of a compromise to an Okta account, it's recommended to use the fields to track all actions performed by the threat actor in a session, covering both authenticated and pre-authentication stages, as well as actions initiated by the Okta system itself. 

  1. authenticationContext.externalSessionId
  2. transaction.id
  3. debugContext.debugData.emailRequestId
  4. debugContext.debugData.authnRequestId

To ensure a thorough investigation, it's also advised to identify all unique identifiers within these fields associated with confirmed malicious events and use them as pivot points for further analysis. It's important to recognize that transaction.id and debugContext.debugData.emailRequestId will always share identical values, whereas the debugContext.debugData.authnRequestId might only occasionally match.

Upon identifying any specific values assigned to these fields, we recommend employing the following filter logic for isolating malicious activity:

  • Match malicious authenticationContext.externalSessionId values with authenticationContext.externalSessionId.
    • OR
  • Match malicious values of transaction.id, debugContext.debugData.emailRequestId, and debugContext.debugData.authnRequestId to transaction.id, debugContext.debugData.emailRequestId, or debugContext.debugData.authnRequestId

Example pseudo code:

# Define lists of known malicious session and transaction/request IDs

malicious_sessions = ["idxXXXXXXXX"]
malicious _request_ids = [
    "f938cb7b727fe8XXXXXXXXXXXXXXXXXX",
    "16a39fde26f5f6XXXXXXXXXXXXXXXXXX",
    "3513cb19071ddcXXXXXXXXXXXXXXXXXX"
]

# Begin filtering process on Okta data
FOR EACH record IN okta_delta
    IF record's externalSessionId IS IN malicious_sessions
        OR record's transactionId IS IN malicious _request_ids
        OR record's emailRequestId IS IN malicious _request_ids
        OR record's authnRequestId IS IN malicious _request_ids
    THEN
        MARK record as malicious
    END IF
END FOR

Those who are fortunate may not be compromised and only need to review logs for detection engineering. However, during an investigation of a compromise, every piece of information is crucial in building a comprehensive picture. If there are issues with certain fields that you are unaware of, it can significantly sidetrack the investigation and impact the severity assessment of the incident.

We aim to continuously update this page as changes occur, providing the security community with thorough reference materials and insights necessary for confident investigations. We plan to cover other vendors and log sources in the upcoming months, ensuring you have the documentation needed to respond to threats effectively.

LAST UPDATED:

June 26, 2024

Don't miss these stories:

How Behavioral Detections Aid Healthcare Security

Healthcare organizations face unique cybersecurity challenges due to their hybrid IT (information technology) environments, sensitive data, and resource constraints.

Using Gen AI for Cloud Threat Detection and Investigation

AI-driven cloud attacks require and AI-driven response. Learn how AI can automate threat intelligence, accelerate response times, and simplify investigations.

Automating AWS Infrastructure Creation with Crossplane and GitOps

A while back, I started migrating my CD to a full GitOps process.