<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Cloud Security - Elastic Security Labs]]></title>
    <description><![CDATA[Trusted security news & research from the team at Elastic.]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Cloud Security - Elastic Security Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte2c6b841aff36df4/6a88d9784acc96e3f324863d/security-labs-thumbnail.png</url>
      <link>https://www.elastic.co/security-labs/blog/category/cloud-security</link>
    </image>
    <link>https://www.elastic.co/security-labs/blog/category/cloud-security</link>
    <atom:link href="https://www.elastic.co/security-labs/rss/category/cloud-security.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Tue, 15 Sep 2026 21:38:06 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Azure AD Graph Activity Logs: Ingestion and threat detection to close the visibility gap]]></title>
    <description><![CDATA[Azure AD Graph Activity Logs land in Elastic with full ECS parsing. Detect ROADrecon and AADInternals enumeration with ready-to-use detection rules.]]></description>
    <content:encoded><![CDATA[<p>AAD Graph Activity Logs are now ingestible into Elastic and usable for threat detection within the <a href="https://www.elastic.co/security/xdr">SIEM/XDR solution</a>. That sentence shouldn't be exciting, but it is. For most of the past decade, this slice of telemetry simply didn't exist as a customer-accessible log stream. Microsoft Graph Activity Logs (the modern <em>graph.microsoft.com</em> surface) went GA in April 2024. The legacy graph.windows.net surface, the one adversary tooling actually hits, stayed dark until early 2026.</p>
<p>This post walks the loop end-to-end. Why visibility matters, how to ingest the logs into Elastic, how to generate realistic recon manually and with ROADrecon, and how to hunt the result in ES|QL. Everything below was validated against a live tenant.</p>
<h2 id="keytakeaways">Key takeaways</h2>
<ul>
<li><p>AAD Graph Activity Logs ride into Elastic through the <a href="https://www.elastic.co/docs/reference/integrations/azure">Azure integration</a> and land in <code>logs-azure.aadgraphactivitylogs-*</code> with full ECS extraction.</p></li>
<li><p>ROADtools, AADInternals, and friends have been operating in a visibility gap for years. Defenders weren't capturing the calls.</p></li>
<li><p>AAD Graph is "deprecated" but still queryable in most tenants. The 1.61-internal API version still returns data that Microsoft Graph won't.</p></li>
<li><p>ECS fields land typed (<code>event.action</code>, <code>event.outcome</code>, <code>http.request.method</code>, <code>source.ip</code>, <code>user.id</code>, <code>user_agent.original</code>). Dataset extras stay queryable under <code>azure.aadgraphactivitylogs.properties.*</code>.</p></li>
<li><p>Five hunts reliably catch the activity: tooling user-agents, endpoint breadth, <code>*-internal</code> API misuse, FOCI client-ID mismatches, and 4xx surges.</p></li>
</ul>
<h2 id="ashorthistoryofdefendervisibility">A short history of defender visibility</h2>
<p>Defenders have spent years on sign-ins, conditional access, role assignments, and OAuth consent grants. Very little content covers the <em>underlying</em> directory APIs that adversary tooling actually hits. The reason is structural: customer-accessible logs for those APIs didn't exist. Microsoft Graph Activity Logs landed first (preview October 2023, GA April 2024). AzureADGraphActivityLogs finally showed up in early 2026.</p>
<p>For most of the past decade, AAD Graph enumeration was invisible to SOCs, not because the telemetry was hidden, but because it didn't exist. ROADtools, AADInternals, MSOLSpray, Microburst. None of them produced data that anyone could capture, even with a perfect logging configuration.</p>
<p>That changes the day AzureADGraphActivityLogs start landing in your platform-logs index.</p>
<h2 id="aadgraphisdeprecatedbutstillverymuchalive">AAD Graph is “deprecated” but still very much alive</h2>
<p>Quick refresher. Azure AD Graph is the legacy REST API for Entra ID directory objects, hosted at <code>https://graph.windows.net/{tenantId}/{objecttype}</code> with API versions like <em>1.5</em>, <em>1.6</em>, and <em>1.61-internal</em>. Microsoft has been telling everyone to migrate to Microsoft Graph since 2019, and the retirement date has slipped several times.</p>
<p>Deprecation isn’t gone. In 2026, AAD Graph can still answer requests in environments where legacy access paths remain available or where applications have not been explicitly blocked from using it. A few reasons it sticks around as an attacker target:</p>
<ul>
<li><p>Adversary tooling hasn't been ported. ROADrecon still uses it for <code>gather</code>. AADInternals has dozens of cmdlets wrapping it.</p></li>
<li><p>The <code>*-internal</code> API versions return more data. <code>1.61-internal</code> exposes <code>strongAuthenticationDetail</code> inline on the user object during a normal directory walk. The Microsoft Graph equivalent lives behind a separate /authentication/methods endpoint gated by <code>UserAuthenticationMethod.Read.All</code>. That asymmetry is exactly what bulk enumeration tooling exploits.</p></li>
<li><p>The block isn't a single toggle. The <code>blockAzureADGraphAccess</code> control lives per-app on <code>application.authenticationBehaviors</code>, so blocking tenant-wide means iterating every app registration. Most environments haven't done that because some legacy automation still depends on the API. Microsoft's phased retirement enforcement does the work on Microsoft's timeline, not the defender's.</p></li>
<li><p>Visibility did not exist, thus red teamers and adversaries could hammer the API endpoints for relevant information.</p></li>
</ul>
<p>Legitimate AAD Graph traffic is dominated by a handful of first-party Microsoft callers. In our test tenant, the order, by volume, was <code>Microsoft.OData.Client</code>, <code>Microsoft Azure Graph Client Library</code>, an empty-UA tail from first-party AppIds, <code>Microsoft ADO.NET Data Services</code>, and the Azure portal (Chrome UAs against the portal app ID). Anything outside that recognisable set is either internal tooling or unauthorized activity. That makes it a solid threat hunting/detection dataset. If you're capturing it.</p>
<h2 id="settinguptheingestionpipeline">Setting up the ingestion pipeline</h2>
<p>If you're already running the Elastic Azure <a href="https://www.elastic.co/docs/reference/integrations/azure">integration</a> with diagnostic settings forwarding to an event hub, skim this section. You probably just need to enable one extra log category. From scratch, it's about a 20-minute path.</p>
<h4 id="step1astacktoreceivethelogs">Step 1: A stack to receive the logs</h4>
<p>Any Elastic deployment works. An Elastic Cloud trial is the lowest-friction option for prototyping. Another option is the <a href="https://github.com/peasead/elastic-container">Elastic Container Project</a> for getting started. The Azure integration already handles AzureADGraphActivityLogs once it's enabled.</p>
<h4 id="step2addtheazureintegration">Step 2: Add the Azure integration</h4>
<p>In Kibana, Integrations &gt; Azure Logs &gt; Add Azure Logs. Plug in your Event Hub connection string, the Event Hub name, and a Storage account for offset checkpointing, all on an event hub in the same subscription as your tenant.</p>
<p>Enable the Azure logs v2 data stream specifically. That's the entry point for AAD Graph Activity Logs. The events router matches <code>category == "AzureADGraphActivityLogs"</code> and reroutes documents to <code>logs-azure.aadgraphactivitylogs-*</code>, where the dataset pipeline applies full ECS extraction.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt99edbfb23df7ad3e/6a7d7ae5fc63abb158649e97/collect-azure-logs.png" alt="" /></p>
<p>We've also broken Azure AD Graph Activity Logs out into its own integration item, so you can search for "Azure AD Graph Activity Logs" and install via the policy template directly.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta8f798ff4ef083dc/6a7d7ae9c33f4f53b4d579f2/azure-graph.png" alt="" /></p>
<h4 id="step3enablediagnosticsettingsonentraid">Step 3: Enable diagnostic settings on Entra ID</h4>
<p>This is the step most defenders miss. AzureADGraphActivityLogs as a diagnostic-settings category is newer. Even if your Entra ID diagnostic settings have been configured for a while now, the new category needs a fresh tick. Otherwise, the data lives and dies in Microsoft's tenant boundary.</p>
<p>In the Azure portal:</p>
<ol>
<li>Entra ID &gt; Monitoring &gt; Diagnostic settings &gt; + Add diagnostic setting.</li>
<li>Name it.</li>
<li>Under Logs, check AzureADGraphActivityLogs. While you're there, MicrosoftGraphActivityLogs, SignInLogs, and AuditLogs are worth turning on if they aren't already. The integration handles all of them.</li>
<li>Under Destination details, Stream to an event hub (the same one from step 2).</li>
<li>Save.</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta23511d2a4bae3c1/6a7d7aecc33f4f770fd579fa/diagnostic-setting.png" alt="" /></p>
<h4 id="step4verifydataisflowing">Step 4: Verify data is flowing</h4>
<p>Within a few minutes, you should start seeing events. Fastest sanity check:</p>
<pre><code>FROM logs-azure.aadgraphactivitylogs-*
| LIMIT 20
</code></pre>
<p>If documents come back with a populated <code>event.action</code>, <code>http.request.method</code>, and <code>zure.aadgraphactivitylogs.properties.*</code> fields, you're good. If nothing shows up, the usual suspects are a forgotten event hub permission, a typo in the connection string, or the AAD Graph category just not being ticked. </p>
<p>To force a few events, sign in to the Azure portal and click around Users or Applications. The portal still calls AAD Graph internally for some object details. If that doesn't generate anything, this curl loop will:</p>
<pre><code>TOKEN=$(az account get-access-token --resource https://graph.windows.net --query accessToken -o tsv)
TID=$(az account show --query tenantId -o tsv)
for obj in users groups servicePrincipals applications tenantDetails; do
  curl -sS -o /dev/null -H "Authorization: Bearer $TOKEN" \
    "https://graph.windows.net/$TID/$obj?api-version=1.6&amp;\$top=5"
done
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta956bb32d42fffb6/6a7d7aee6c6eac3f17f11271/verify-data-flowing.png" alt="" /></p>
<h2 id="fieldshape">Field shape</h2>
<p>Once data is flowing, properties land as typed, top-level fields. The ones that matter for hunting:</p>
<ul>
<li><a href="https://www.elastic.co/docs/reference/ecs">ECS</a>, populated directly: <code>event.action</code> (a semantic verb derived from method + collection, e.g., <code>users-read, batch-execute</code>), <code>event.outcome</code>, <code>event.duration</code>, <code>http.request.method</code>, <code>http.response.status_code, source.ip</code>, and <code>source.geo.*, user.id, user_agent.original</code> (plus parsed sub-fields), <code>url.path, azure.tenant_id, cloud.service.name = "Azure AD Graph"</code>.</li>
<li>Dataset-specific under <code>zure.aadgraphactivitylogs.properties.*: app_id,</code>, <code>app_id</code>, <code>api_version</code>, <code>actor_type</code>, <code>roles</code>, <code>scopes</code>, <code>wids</code>, <code>identity_provider</code>, <code>client_auth_method</code>, <code>sign_in_activity_id</code>, <code>token_issued_at</code>.</li>
<li><code>related.user</code> gets both <code>user.id</code> and <code>properties.app_id</code>, so pivots on the OAuth-client dimension work alongside the user pivot.</li>
</ul>
<p>Raw JSON stays in <em>event.original</em> for forensic replay. You shouldn't need to reach into it for normal hunting. If you do, ES|QL's <a href="https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/string-functions/json_extract"><em>JSON_EXTRACT()</em></a> is the lever.</p>
<h2 id="aadgraphenumerationwithroadrecon">AAD Graph enumeration with ROADrecon</h2>
<p>To know what to hunt, you need to know what the activity looks like. The two toolkits below are the most common sources of AAD Graph traffic in red team and security research workflows. I ran both against our testing tenant.</p>
<p>Note: I take no responsibility for misuse of this code. Run these tools only against tenants you own or have explicit written authorization to test.</p>
<h3 id="roadreconbulkenumerationtest">ROADrecon: Bulk enumeration test</h3>
<p>ROADrecon is the data-collection module of <a href="https://github.com/dirkjanm/ROADtools">ROADtools</a>, Dirk-jan Mollema's Entra ID research framework. Highly recommended if you haven't used it. <em>gather</em> walks every interesting object type in the directory (users, groups, service principals, applications, devices, directory roles, role assignments, eligible role assignments, OAuth2 permission grants, administrative units) and writes the result to SQLite.</p>
<p>Setup is the standard workflow:</p>
<pre><code>pip install roadrecon
roadrecon auth --device-code -c 04b07795-8ddb-461a-bbee-02f9e1bf7b46 -r https://graph.windows.net
</code></pre>
<p>The device-code flow hands you a URL and a code. We use the Microsoft Azure CLI as the default (<code>1b730954-1685-4b74-9bfd-dac224a7b894</code> - AAD PowerShell), which returned 403s in our tenant. After signing in:</p>
<pre><code>roadrecon gather
</code></pre>
<p>Running <em>roadrecon gather</em> with the resulting token completed cleanly. From the tenant's perspective, the run produced just over ~2,000 AAD Graph calls and logs in roughly 1 minute. Bulk enumeration across every object type ROADrecon knows.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc8ccdd9cd93ed0a1/6a7d7af1c33f4f48cbd57a00/roaddrecon.png" alt="" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1f2125a8ae85a91/6a7d7af4bdcff010cac3ff65/roaddrecon2.png" alt="" /></p>
<p>From this, we can form some initial detections to start flagging these anomalies.</p>
<h2 id="keyfieldsforaadgraphthreatdetection">Key fields for AAD Graph threat detection</h2>
<p>Before the hunts, here are some solid starting fields for detecting anomalies.</p>
<p>| Field | Description | What you can find |
|---------|-------------|-------------------|
| <code>event.action</code> | Semantic verb (HTTP method + collection, e.g.,<code>users-read, batch-execute) | A cheap filter to isolate AAD Graph activity by intent |
|</code>http.request.method<code>| GET, POST, PATCH</code>, DELETE | Reads (recon) vs writes (modification, credential injection, persistence) |
| <code>http.response.status_code</code> | HTTP status returned | Successful vs blocked recon; bursts of 4xx indicate permission-probing or brute-forcing |
| <code>user.id</code> | Calling user's directory object ID | Identity attribution; pivot to that user's other activity in SignInLogs / AuditLogs |
| <code>user_agent.original</code> | Full UA string of the caller | Whether the caller is a first-party Microsoft library, a developer tool (curl, Python aiohttp), or known offensive tooling |
| <code>url.path</code> | Resource path (/users, /policies, /servicePrincipals, …) | Which directory object types are being touched; breadth across distinct paths indicates bulk enumeration |
| <code>azure.aadgraphactivitylogs.properties.app_id</code> | OAuth client ID that issued the token | Whether traffic comes from a legitimate first-party client or from a FOCI-swap-style abuse path |
| <code>azure.aadgraphactivitylogs.properties.api_version</code> | 1.5, 1.6, 1.61-internal, etc. | Whether the caller is asking for internal-only fields (strongAuthenticationDetail, full CAP set) that adversary tooling specifically targets |
| <code>azure.aadgraphactivitylogs.properties.actor_type</code> | User, Application, ServicePrincipal | Human caller vs service-principal / app-only flow |
| <code>azure.aadgraphactivitylogs.properties.roles</code> / <code>wids</code> | Directory role display names and well-known role template GUIDs held by the caller | Whether a privileged role (Global Admin, Application Administrator, etc.) is being exercised at the moment of the call |
| <code>azure.aadgraphactivitylogs.properties.scopes</code> | OAuth scopes on the calling token | Which directory permissions the token actually grants the caller |
| <code>azure.aadgraphactivitylogs.properties.client_auth_method</code> | How the client authenticated (PRT, certificate, secret, …) | Fingerprints for PRT abuse, device-PRT exploitation, or stolen client-credential use |
| <code>azure.aadgraphactivitylogs.properties.sign_in_activity_id</code> | Correlation ID to the originating sign-in | Pivot from an AAD Graph call back to the sign-in event that produced the calling token |
| <code>azure.aadgraphactivitylogs.properties.token_issued_at</code> | Timestamp the token was minted | Token-age analysis; calls riding on a token issued days ago can indicate stale-token / refresh-token abuse |</p>
<h2 id="detectionandprevention">Detection and prevention</h2>
<h3 id="detection">Detection</h3>
<p>The prerequisite for any AAD Graph detection is having the logs in the first place. The <em>AzureADGraphActivityLogs</em> diagnostic category needs to be enabled in Entra ID and routed to a destination you can query (at minimum a Log Analytics workspace, ideally also forwarded to an event hub for Elastic ingestion as described in the setup section above). Until that's done, the calls described in this post happen entirely off-camera, and none of the hunts below will fire.</p>
<p>If you can't ingest into Elastic right now, enable the diagnostic setting anyway and send to Log Analytics. The KQL equivalents of the hunts below are straightforward, and the data accumulates with retention even without further processing.</p>
<h3 id="prevention">Prevention</h3>
<p>There's no single tenant-wide AAD Graph kill-switch in the portal. The actual application-layer control is:</p>
<ul>
<li><code>application.authenticationBehaviors.blockAzureADGraphAccess</code></li>
</ul>
<p>A per-app Boolean on the application resource (Microsoft Graph beta, <a href="https://learn.microsoft.com/en-us/graph/api/resources/authenticationbehaviors">docs</a>). Blocking at scale means walking through every app registration and flipping it manually or programmatically. Microsoft's own phased retirement is doing this on their timeline regardless. The further along that gets, the less surface there is to defend.</p>
<p>Defenders can move on the same axes in the meantime:</p>
<ul>
<li><p>Audit applications in your tenant that still hold tokens for <em>graph.windows.net</em>. Set <code>blockAzureADGraphAccess = true</code> on the ones that don't need it. Anything still depending on AAD Graph breaks loudly, which surfaces legacy automation you didn't know you had.</p></li>
<li><p>Apply Conditional Access with Azure AD Graph as a target resource. The Azure AD Graph service principal (<code>00000002-0000-0000-c000-000000000000</code>) doesn't show in the standard CA app picker, but it's covered by <em>All resources</em> policies and is individually targetable via the <a href="https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-conditional-access-cloud-apps#protect-directory-information">custom security attribute filter approach</a>. Microsoft's <a href="https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-conditional-access-cloud-apps#new-conditional-access-behavior-when-an-all-resources-policy-has-a-resource-exclusion">March 2026 enforcement change</a> makes this more practical: low-privilege scopes (<em>User.Read</em>, <em>People.Read</em>, etc.) that used to be auto-excluded from CA enforcement are now treated as AAD Graph access, so <em>all resource</em> policies actually gate them. CA evaluates at token issuance, so already-valid tokens keep working until expiry.</p></li>
<li><p>Apply CA to the FOCI clients adversary tooling rides on (Microsoft Teams, Microsoft Office, OneDrive, Azure PowerShell, etc.). Require managed and compliant devices. The swap path collapses if the underlying client can't sign in.</p></li>
<li><p>For service-principal callers, <a href="https://learn.microsoft.com/en-us/entra/identity/conditional-access/workload-identity">Workload Identities Premium</a> adds CA scoped to service principals. Conditions are limited to location, Identity Protection risk, and authentication context; the only grant control is Block. Useful for collapsing external- and risky-context paths, not for scoping an SP to specific cloud apps the way user CA does.</p></li>
<li><p>Disable device-code flow for users who don't need it. <code>roadrecon auth --device-code</code> is the path of least resistance into the entire pipeline above and is extremely common in OAuth phishing.</p></li>
</ul>
<h3 id="behaviordetection">Behavior detection</h3>
<p>We shipped detection rules covering the AAD Graph recon shapes documented above. Each lives in the <a href="https://github.com/elastic/detection-rules">Elastic detection-rules</a> repository and runs natively against the parsed <code>logs-azure.aadgraphactivitylogs-*</code> data stream.</p>
<p><a href="https://github.com/elastic/detection-rules/blob/31d1fa31152c208dfde4feeb6737ca06e030ae53/rules/integrations/azure/discovery_aad_graph_suspicious_user_agent.toml">Azure AD Graph Access with Suspicious User-Agent</a> - KQL match rule. Triggers when AAD Graph receives traffic from user-agent strings matching offensive tooling families (Python, aiohttp, curl, Go-http-client, axios, AzureHound, BloodHound, AADIntenals, etc.). Solid baseline signal because no first-party Microsoft component identifies as any of these, while default tooling does. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb438b54aee0edfd9/6a7d7af73cab1c76d40e18f0/azuread-graph-suspicious-user-agent.png" alt="" /></p>
<p><a href="https://github.com/elastic/detection-rules/blob/df0396ea4a3b0fb25529444166c36c430941d3a6/rules/integrations/azure/discovery_aad_graph_high_4xx_ratio_by_user.toml">Azure AD Graph High 4xx Error Ratio from User</a> - ES|QL aggregation. Triggers when a single caller produces an unusually high ratio of 4xx responses against AAD Graph in a short window. Recon and brute-force token usage leave a tail of 403s and 404s as tools walk endpoints they don't have permission for, ask for object IDs they don't have, or use a client ID unauthorized for AAD Graph. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc19b1a45deb54e9c/6a7d7afac2cc094e14246569/azure-ad-graph-high-error-ratio-user.png" alt="" /></p>
<p><a href="https://github.com/elastic/detection-rules/blob/0c15c6c581780d962b33972a8a83263b75fb2d79/rules/integrations/azure/discovery_aad_graph_unusual_client_for_user.toml">Azure AD Graph Access with Unusual Client and User</a> - KQL new_terms rule, medium severity. Fires when a (calling OAuth client, signed-in user) pair appears on AAD Graph for the first time in the prior 14 days. Catches FOCI swaps, phished refresh tokens redeemed for clients the user doesn't normally use, and stolen tokens used under unfamiliar clients. Ignores known first-party applications that were commonly observed interacting with Azure AD that are backend owned by Microsoft.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb5b45c7517bd3c7f/6a7d7afd3ce8e20caecf2584/azure-unusual-client-user.png" alt="" /></p>
<p><a href="https://github.com/elastic/detection-rules/blob/6f933e04ddbe720898c9ea9c4bae234700a822fe/rules/integrations/azure/initial_access_aad_graph_unusual_asn.toml">Azure AD Graph Access with Unusual User and ASN</a> - KQL match rule. Excludes the common Microsoft / AWS / GCP / Akamai / Cloudflare ASN organisations and flags AAD Graph traffic originating outside that set. Adversary tooling typically rides on residential ISPs, VPS providers, or anonymising networks that produce a different ASN distribution than legitimate first-party callers. Tunable per tenant by adjusting the excluded ASN list.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt545005226eb2015e/6a7d7b00bd2198386e7551b7/3.png" alt="" /></p>
<p><a href="https://github.com/elastic/detection-rules/blob/4256409e8925a8da016448d1378bc669c2333961/rules/integrations/azure/discovery_aad_graph_roadrecon_aiohttp_enumeration.toml">Azure AD Graph Potential Enumeration (ROADrecon)</a> - ES|QL aggregation, <strong>high severity</strong>. Requires both an <em>aiohttp</em> user-agent and a burst of 500+ AAD Graph requests from a single identity. ROADrecon's <em>gather</em> command uses aiohttp by default and walks every directory object type, so the combination is essentially a tool fingerprint. Higher severity than the generic non-Microsoft UA rule because the additional burst requirement removes the developer-prototype false-positive class.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4a2bb7de7ceb2065/6a7d7b034df50c45a442d884/graph-potential.png" alt="" /></p>
<p><a href="https://github.com/elastic/detection-rules/blob/6a946179e66c7a952e55a33741c160d6bd83f3b8/rules/integrations/azure/credential_access_device_code_signin_aad_graph_enum.toml">Entra ID OAuth Device Code Sign-in to Azure AD Graph Enumeration</a> - EQL sequence, <strong>high severity</strong>. Joins a successful device-code sign-in to the legacy AAD Graph audience (<code>00000002-0000-0000-c000-000000000000</code>) on an unmanaged device with directory enumeration against <em>graph.windows.net</em> by the same user within five minutes. Device-code phishing lands an OAuth token without touching the user's password or MFA, so immediate Graph reads of users, service principals, applications, role assignments, policies, or tenant details under that token are the compromised identity being driven by the attacker. Cross-data-stream sequence removes the single-event false-positive class that the other AAD Graph rules carry.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf15138c6144db4d1/6a7d7b06fc63ab31cb649ea3/id-oauth.png" alt="" /></p>
<h2 id="aadgraphvisibilitywhatcomesnext">AAD Graph visibility: what comes next</h2>
<p>For most of the past decade, AAD Graph activity was the telemetry equivalent of dark matter. We knew it was there because adversary tooling kept pointing at it, but customers had no diagnostic stream to subscribe to and no logs to query. Microsoft Graph Activity Logs closed half the gap when they went GA in April 2024. <em>AzureADGraphActivityLogs</em> finally closed the other half in early 2026.</p>
<p>Now that the data exists, the rest is on us. Add the new diagnostic setting, point it at an event hub, ingest into your stack, turn detections on (or create your own) and get to monitoring.</p>
<p>The detections in this post are a starting point. Once you have AAD Graph traffic landing in your stack and a baseline of what normal looks like in your tenant, the same patterns generalize. Legitimate first-party Microsoft callers form a small, recognisable set, and anything outside that set deserves a closer look.</p>
<p>The activity was always there. The visibility finally is too.</p>
<p>Happy hunting!</p>
<h2 id="references">References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.elastic.co/docs/reference/integrations/azure">Elastic Azure Integration</a></li>
<li><a href="https://github.com/dirkjanm/ROADtools">ROADtools GitHub</a></li>
<li><a href="https://github.com/dirkjanm/ROADtools/wiki">ROADtools wiki</a></li>
<li><a href="https://github.com/dirkjanm/BloodHound-AzureAD">BloodHound with Azure AD capabilities</a></li>
<li><a href="https://github.com/Gerenios/AADInternals">AADInternals</a></li>
<li><a href="https://aadinternals.com/aadinternals/">AADInternals documentation</a></li>
<li><a href="https://learn.microsoft.com/en-us/graph/migrate-azure-ad-graph-overview">Migrate your apps from Azure AD Graph to Microsoft Graph</a></li>
<li><a href="https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-configure-diagnostic-settings">Configure Microsoft Entra diagnostic settings for activity logs</a></li>
<li><a href="https://learn.microsoft.com/en-us/graph/microsoft-graph-activity-logs-overview">Access Microsoft Graph activity logs</a></li>
<li><a href="https://techcommunity.microsoft.com/blog/microsoft-entra-blog/microsoft-graph-activity-logs-is-now-generally-available/4094535">Microsoft Graph activity logs is now generally available</a></li>
<li><a href="https://www.invictus-ir.com/news/the-missing-link-aadgraphactivitylogs-finally-arrives">The Missing Link: AADGraphActivityLogs Finally Arrives</a></li>
<li><a href="https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/">Azure AD privilege escalation - Taking over default application permissions as Application Admin</a></li>
<li><a href="https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/">Abusing Azure AD SSO with the Primary Refresh Token</a></li>
</ul>
<h2 id="aboutelasticsecuritylabs">About Elastic Security Labs</h2>
<p>Elastic Security Labs is the threat intelligence branch of Elastic Security dedicated to creating positive change in the threat landscape. Elastic Security Labs provides publicly available research on emerging threats with an analysis of strategic, operational, and tactical adversary objectives, then integrates that research with the built-in detection and response capabilities of Elastic Security.Follow Elastic Security Labs on Twitter <a href="https://twitter.com/elasticseclabs?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">@elasticseclabs</a> and check out our research at <a href="https://www.elastic.co/security-labs/">www.elastic.co/security-labs/</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/aad-graph-activity-logs-threat-detection</link>
    <guid isPermaLink="false">aad-graph-activity-logs-threat-detection</guid>
    <category><![CDATA[Cloud Security]]></category>
    <dc:creator><![CDATA[Terrance DeJesus]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a3aae5041504e90/6a7d7b0ab4377062a54d3e5e/covernew.png" length="0" type="image/png"/>
    <pubDate>Fri, 19 Jun 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Microsoft Entra ID OAuth Phishing and Detections]]></title>
    <description><![CDATA[This article explores OAuth phishing and token-based abuse in Microsoft Entra ID. Through emulation and analysis of tokens, scope, and device behavior during sign-in activity, we surface high-fidelity signals defenders can use to detect and hunt for OAuth misuse.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>Members of the Threat Research and Detection Engineering (TRADE) team at Elastic have recently turned their attention to an emerging class of threats targeting OAuth workflows in Microsoft Entra ID (previously Azure AD). This research was inspired by Volexity's recent blog, <a href="https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/">Phishing for Codes: Russian Threat Actors Target Microsoft 365 OAuth Workflows</a>, which attributes a sophisticated OAuth phishing campaign against NGOs to the threat actor designated <a href="https://malpedia.caad.fkie.fraunhofer.de/actor/uta0352">UTA0352</a>.</p>
<p>Volexity's investigation presents compelling forensic evidence of how attackers abused trusted first-party Microsoft applications to bypass traditional defenses. Using legitimate OAuth flows and the open-source tool <a href="https://github.com/dirkjanm/ROADtools">ROADtools</a>, the actors crafted customized Microsoft authentication URLs, harvested security tokens and leveraged them to impersonate users, elevate privilege, and exfiltrate data via Microsoft Graph — including downloading Outlook emails and accessing SharePoint sites.</p>
<p>While their report thoroughly documents the <strong>what</strong> of the attack, our team at Elastic focused on understanding the <strong>how</strong>. We emulated the attack chain in a controlled environment to explore the mechanics of token abuse, device registration, and token enrichment firsthand. This hands-on experimentation yielded deeper insights into the inner workings of Microsoft's OAuth implementation, the practical use of ROADtools, recommended mitigations, and most importantly, effective detection strategies to identify and respond to similar activity.</p>
<h2 id="oauthinmicrosoftentraid">OAuth in Microsoft Entra ID</h2>
<p>Microsoft Entra ID implements OAuth 2.0 to enable delegated access to Microsoft 365 services like Outlook, SharePoint, and Graph API. While the OAuth specification is standardized (<a href="https://datatracker.ietf.org/doc/html/rfc6749">RFC6749</a>), Entra ID introduces unique behaviors and token types that influence how delegated access works and how adversaries exploit them.</p>
<p>In delegated access, an application is authorized to act on behalf of a signed-in user, constrained by scopes (permissions) the app requests and the user or admin consents to. This model is common in enterprise environments where apps retrieve a user's emails, files, or directory data without prompting for credentials each time.</p>
<p>A typical delegated authorization flow includes:</p>
<p><strong>Authorization request (OAuth 2.0 Authorization Code Grant)</strong>: The app requests access to a resource (e.g., Graph) with specific scopes (e.g., Mail.Read, offline_access). These are added as parameters to the URI.</p>
<ul>
<li><em>client_id</em>: The application’s ID (e.g., VSCode)  </li>
<li><em>Response_type</em>: Determines the grant type OAuth workflow (e.g. device code, auth code)  </li>
<li><em>Scope</em>: Permissions requested for the target resource (e.g. <em>Mail.Read, offline_access)</em>  </li>
<li><em>Redirect_uri</em>: Where to send our authorization codes  </li>
<li><em>State</em>: CSRF protection  </li>
<li><em>Login_hint</em>: Pre-fills username</li>
</ul>
<p><strong>User authentication (OpenID Connect)</strong>: Entra ID authenticates the user via policy (password, MFA, device trust).</p>
<ul>
<li>Single-Factor Authentication (SFA)  </li>
<li>Multi-factor Authentication (MFA)  </li>
<li>Device Trust (Hybrid Join, Intune compliance)  </li>
<li>Conditional Access Policies (CAP)  </li>
<li>Single Sign-On (SSO)</li>
</ul>
<p><strong>Consent:</strong> Consent governs whether the app can receive an authorization code and what scopes are permitted.</p>
<ul>
<li>User-consentable scopes (e.g. <em>Mail.Read, offline_access)</em>  </li>
<li>Admin-Consent required scopes (e.g. <em>Directory.ReadWrite</em>) requires elevated approval.</li>
</ul>
<p><strong>Token issuance</strong>: The app receives an authorization code, then redeems it for :</p>
<ul>
<li>Access Token – short-lived token used to call APIs like Graph.  </li>
<li>Refresh Token (RT) – longer-lived token to obtain new access tokens silently.  </li>
<li>Identity Token - Describes authenticated user; present in OpenID flows.  </li>
<li>(Optional) Primary Refresh Token: If the user is on a domain-joined or registered device, a Primary Refresh Token (PRT) may enable silent SSO and additional token flows without user interaction.  </li>
<li><strong>Token claims:</strong> Claims are key-value pairs embedded in JWT tokens that describe the user, app, device, scopes and context of the authentication.</li>
</ul>
<h2 id="whatdefinesanmsftoauthphishingurl">What Defines an MSFT OAuth Phishing URL</h2>
<p>Before diving into key findings from Volexity's report that help shape our detection strategy, it's important to break down what exactly defines a Microsoft OAuth phishing URL.</p>
<p>As described earlier, Microsoft Entra ID relies on these URLs to determine which application (client) is requesting access, on behalf of which user principal, to what resource, and with what permissions. Much of this context is embedded directly in the query parameters of the OAuth authorization request,  making them a critical source of metadata for both adversaries and defenders.</p>
<p>Here's an example of a phishing URL aligned with the authorization code grant flow, adapted from Volexity's blog:</p>
<pre><code>https://login.microsoftonline[.]com/organizations/oauth2/v2.0/authorize?state=https://mae.gov[.]ro/[REMOVED]&amp;client_id=aebc6443-996d-45c2-90f0-388ff96faa56&amp;scope=https://graph.microsoft.com/.default&amp;response_type=code&amp;redirect_uri=https://insiders.vscode.dev/redirect&amp;login_hint=&lt;EMAIL HERE&gt;
</code></pre>
<p>Let's break down some of the key components:</p>
<ul>
<li>login.microsoftonline.com – The global Microsoft Entra ID authentication endpoint.  </li>
<li>/oauth2/v2.0/authorize - MSFT Entra ID OAuth v2.0 endpoint for authorization workflows  </li>
<li>state – Optional value used to prevent CSRF and maintain application state. Sometimes abused to obfuscate phishing redirections.  </li>
<li>client_id – The application ID making the request. This could belong to Microsoft first-party apps (like VSCode, Teams) or malicious third-party apps registered by adversaries.  </li>
<li>scope – Defines the permissions the application is requesting (e.g., Mail.Read, offline_access). The .default scope is often used for client credential flows to get pre-consented permissions.  </li>
<li>response_type=code – Indicates the flow is requesting an authorization code, which can later be exchanged for an access and/or refresh token.  </li>
<li>redirect_uri – Where Entra ID will send the response after the user authenticates. If an attacker controls this URI, they gain the code or it is a MSFT-managed URI that is valid.  </li>
<li>login_hint – Specifies the target user (e.g., alice @ tenant.onmicrosoft.com). Often pre-filled to lower friction during phishing.</li>
</ul>
<p>Note: While this example illustrates a common Microsoft Entra ID OAuth phishing URL, there are many variations. Adversaries may adjust parameters such as the client ID, scopes, grant types or redirect URIs depending on their specific objectives, whether it's to gain persistent access, exfiltrate emails, or escalate privileges via broader consent grants.</p>
<h2 id="whydoesthismatter">Why Does This Matter?</h2>
<p>Because these parameters are customizable, adversaries can easily swap out values to suit their operation. For example:</p>
<ul>
<li>They might use a legitimate Microsoft client ID to blend in with benign applications.  </li>
<li>They may use a .default scope to bypass specific consent prompts.  </li>
<li>They’ll point the redirect_uri to a site under their control to collect the authorization code.  </li>
<li>They can target specific user principals they may have identified during reconnaissance.  </li>
<li>They can adjust permissions to target resources based on their operational needs.</li>
</ul>
<p>Once a target authenticates, the goal is simple – obtain an authorization code. This code is then exchanged (often using tools like ROADtools) for a refresh token and/or access token, enabling the attacker to make Graph API calls or pivot into other Microsoft 365 services, all without further user interaction.</p>
<h2 id="abstractionofvolexityskeyfindings">Abstraction of Volexity's Key Findings</h2>
<p>For threat detection, it is critical to understand the protocols like OAuth, workflow implementation in Microsoft Entra ID, and contextual metadata about the behaviors and/or steps taken by the adversary regarding this operation.</p>
<p>From Volexity's investigation and research, we can key in the different variations of OAuth phishing reported. We decided to break these down for easier understanding:</p>
<p><strong>OAuth Phishing To Access Graph API as VSCode Client On-Behalf-Of Target User Principal</strong>: These URLs are similar to our example “What Defines an MSFT OAuth Phishing URL” – the end game goal being an access token to Graph API with default permissions. </p>
<ul>
<li>OAuth phishing URLs were custom, pointing to "authorize" endpoint  </li>
<li>Client IDs were specifically VSCode ("aebc6443-996d-45c2-90f0-388ff96faa56")  </li>
<li>Resource/Scope was MSFT Graph ("https://graph.microsoft.com/.default") with .default permissions  </li>
<li>Token grant flows were auth code (response_type=code)  </li>
<li>Redirect URIs were for legitimate MSFT domains (insiders[.]vscode[.]dev or vscode-redirect[.]azurewebsites[.]net)  </li>
<li>Login hints were the specific user principal being targeted (not service principals)  </li>
<li>Adversary required the target to open the URL, authenticate and share the authorization code (1.AXg….)</li>
</ul>
<p>From here, the adversary would be able to make a request to MSFT's OAuth token endpoint (<em>https://login.microsoftonline.com/[tenant_id]/oauth2/v2.0/token</em>) and exchange the refresh token for an access token. This is enough to allow the adversary to access Graph API and access resources normally available to the user. These indicators will be crucial to factoring our detection and hunting strategies later on in this blog.</p>
<p><strong>OAuth Phishing for Device Registration as MSFT Auth Broker</strong>: These URLs are unique as they are chained with subsequence ROADtools usage to register a virtual device, exchange an RT for a PRT, and require PRT enrichment to accomplish email access via Graph API and Sharepoint access.</p>
<ul>
<li>OAuth phishing URLs were custom, pointing to authorize (<em>https://login.microsoftonline.com/[tenant_id]/oauth2/v2.0/authorize</em>) endpoint  </li>
<li>Client IDs were specifically MSFT Authentication Broker ("29d9ed98-a469-4536-ade2-f981bc1d605e")  </li>
<li>Resource/Scope was Device Registration Service (DRS) ("01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9")  </li>
<li>Token grant flows were auth code (response_type=code)  </li>
<li>Redirect URI includes cloud-based domain join endpoint (typically used during Windows setup or Autopilot)  </li>
<li>Login hint contains user principal email address (Target)  </li>
<li>Request is ultimately for an ADRS token</li>
</ul>
<p>If the user is phished and opens the URL, authenticating will provide an ADRS token that is required for the adversary to register a device and subsequently obtain a PRT with the device’s private key and PEM file.</p>
<p>Volexity's blog also includes additional information about tracking the activity of the compromise identity via the device ID registered as well as post-compromise activity following an approved 2FA request was identified, allowing the adversary to download the target's email with a session tied to the newly registered device.</p>
<p>With this understanding of each phishing attempt, our next goal is to replicate this in our own MSFT tenant as accurately as possible to gather data for plausible detections.</p>
<h2 id="ouremulationefforts">Our Emulation Efforts</h2>
<p>Alright – so at this point, we’ve covered the fundamentals of OAuth and how Microsoft Entra ID implements it. We broke down what defines a Microsoft OAuth phishing URL, decoded its critical parameters, and pulled key insights from Volexity's excellent investigation to identify indicators aligned with these phishing workflows.</p>
<p>But theory and a glimpse into Volexity's notebook only takes us so far.</p>
<p>To truly understand the attacker's perspective, the full chain of execution, tooling quirks, subtle pitfalls, and opportunities for abuse,  we decided to go hands-on with whitebox testing. We recreated the OAuth phishing process in our own tenant, emulating everything from token harvesting to resource access. The goal? Go beyond static indicators and surface the behavioral breadcrumbs that defenders can reliably detect.</p>
<p>Let's get into it.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>For starters, it is good to share some details about our threat research and detection environment in Azure.</p>
<ul>
<li>Established Azure tenant: TENANT.onmicrosoft.com  </li>
<li>Established Sharepoint Domain: DOMAIN.sharepoint.com  </li>
<li>Native IdP Microsoft Entra ID – Enabling our IAM  </li>
<li>Microsoft 365 Licenses (P2) for All Users  </li>
<li>Azure Activity Logs Streaming to EventHub  </li>
<li>Microsoft Entra ID Sign-In Logs Streaming to EventHub  </li>
<li>Microsoft Entra ID Audit Logs Streaming to EventHub  </li>
<li>Microsoft Graph Audit Logs Streaming to EventHub  </li>
<li>Microsoft 365 Audit Logs Streaming to EventHub  </li>
<li>Elastic Azure and M365 Integration Enabled for Log Digestion from EventHub  </li>
<li>Basic Admin User Enabled with CAP Requiring MFA  </li>
<li>MSFT Authenticator App on Mobile for 2FA Emulation  </li>
<li>Windows 10 Desktop with NordVPN (Adversary Box)  </li>
<li>macOS endpoint (Victim box)</li>
</ul>
<p>Note that while we could follow the workflows from a single endpoint, often we need data that reflects separate source addresses to developer detection variations of impossible travel.</p>
<h2 id="scenario1oauthphishingasvscodeclient">Scenario 1: OAuth Phishing as VSCode Client</h2>
<h3 id="emulation">Emulation</h3>
<p>To emulate the phishing technique documented by Volexity, we built a Python script to generate an OAuth 2.0 authorization URL using Microsoft Entra ID. The URL initiates an authorization code grant flow, impersonating the first-party Visual Studio Code app to request delegated access to the Microsoft Graph API.</p>
<p>We configured the URL with the following parameters:</p>
<pre><code>{
  "client_id": "aebc6443-996d-45c2-90f0-388ff96faa56",
  "response_type": "code",
  "redirect_uri": "insiders.vscode.dev/redirect",
  "scope": "https://graph.microsoft.com/.default",
  "login_hint": "user @ tenant.onmicrosoft.com",
  "prompt": "select_account",
  "state": "nothingtoseehere"
}
</code></pre>
<p><em>Figure 1: Parameters for OAuth Phishing URL</em></p>
<p>This URL is shared with the target (in our case, a MacOS test user). When opened, it authenticates the user and completes the OAuth workflow. Using browser developer tools, we capture the authorization code returned in the redirect URI,  exactly what the attackers asked their victims to send back.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdf6a7d7d9f938cd0/6a7d801342a117b38b959108/image7.png" alt="Figure 2: Redirect query string parameters with authorization code after authentication" title="Figure 2: Redirect query string parameters with authorization code after authentication" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3c0638229254b53c/6a7d80168fc2d0c27e3eb899/image2.png" alt="Figure 3: Python script execution for generating OAuth phishing URL and exchanging auth code for Token" title="Figure 3: Python script execution for generating OAuth phishing URL and exchanging auth code for Token" /></p>
<p>After receiving the code, we issue a POST request to:</p>
<pre><code>{token_url: "https://login.microsoftonline.com/organizations/oauth2/v2.0/token"}
</code></pre>
<p>This exchange uses the authorization_code grant type, passing the code, client ID, and redirect URI. Microsoft returns an access token, but no refresh token. You might ask why that is?</p>
<p>The scope https://graph.microsoft.com/.default instructs Microsoft to issue a bearer token for all Graph permissions already granted to the VSCode app on behalf of the user. This is a static scope, pulling from the app registration,  it does not include dynamic scopes like Mail.Read or offline_access.</p>
<p>Microsoft's documentation states:</p>
<p>““<em>Clients can’t combine static (.default) consent and dynamic consent in a single request.</em>””</p>
<p>Therefore, trying to include offline_access alongside <em>.default</em> results in an error. If the attacker wants a refresh token, they must avoid <em>.default</em> and instead explicitly request <em>offline_access</em> and the required delegated scopes (e.g., Mail.Read) – Assuming the app registration supports those.</p>
<p>With the access token in hand, we pivoted to a second script to interact with the Microsoft Graph API. The goal – extract email messages from the victim’s account — just as the attacker would.</p>
<p>To do this, we included the access token as a Bearer JWT in the authorization header and made a GET request to the following endpoint:</p>
<pre><code>{graph_url: "https://graph.microsoft.com/v1.0/me/messages"}
</code></pre>
<p>The response returns a JSON array of email objects. From here, we simply iterate through the results and parse out useful metadata such as sender, subject, and received time.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3cc8e35610c2bde9/6a7d801933fa8aa8551ff963/image4.png" alt="Figure 4: Leveraging access token to access user emails via Graph API" title="Figure 4: Leveraging access token to access user emails via Graph API" /></p>
<p>To test the token’s broader privileges, we also attempted to enumerate SharePoint sites using:</p>
<pre><code>{graph_search_url: "https://graph.microsoft.com/v1.0/sites?search=*"}
</code></pre>
<p>The request failed with an access denied error – which leads us to an important question: why did email access work, but SharePoint access did not? The reason is that the first-party client (VSCode: aebc6443-996d-45c2-90f0-388ff96faa56) does not have default delegated permissions with Graph for Sharepoint – as predefined by Microsoft. Therefore, we know the adversary is limited on what they can access.</p>
<p>To ensure this was accurate, we decoded the access token to identify the SCP associated with VSCode with <em>.default</em> permissions to Graph – Verifying no <em>Sites.</em>* permissioned by Microsoft.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc76a8ec4d69aec57/6a7d801c2f00b27166efbec7/image11.png" alt="Figure 5: Decoded Entra ID Access Token" title="Figure 5: Decoded Entra ID Access Token" /></p>
<p>This is one of the variations described by Volexity, but does help us understand more about the processes behind the scenes for the adversary – as well as resources, OAuth, and more for Microsoft Entra ID.</p>
<p>With the emulation complete, we now turn to identifying high-fidelity signals that are viable for SIEM detection and threat hunting. Our focus is on behavior observables in Microsoft Entra ID and Microsoft Graph logs.</p>
<h3 id="detection">Detection</h3>
<h4 id="signal1microsoftentraidoauthphishingasvisualstudiocodeclient">Signal 1 - Microsoft Entra ID OAuth Phishing as Visual Studio Code Client</h4>
<p>A successful OAuth 2.0 (authorization) and OpenID Connect (authentication) flow was completed using the first-party Microsoft application Visual Studio Code (VSCode). The sign-in occurred on behalf of the phished user principal, resulting in delegated access to Microsoft Graph with <em>.default</em> permissions.</p>
<pre><code>event.dataset: "azure.signinlogs" and
event.action: "Sign-in activity" and
event.outcome: "success" and
azure.signinlogs.properties.user_type: "Member" and
azure.signinlogs.properties.authentication_processing_details: *Oauth* and
azure.signinlogs.category: "NonInteractiveUserSignInLogs" and
(
  azure.signinlogs.properties.resource_display_name: "Microsoft Graph" or
  azure.signinlogs.properties.resource_id: "00000003-0000-0000-c000-000000000000"
) and (
  azure.signinlogs.properties.app_id: "aebc6443-996d-45c2-90f0-388ff96faa56" or
  azure.signinlogs.properties.app_display_name: "Visual Studio Code"
)
</code></pre>
<h4 id="signal2microsoftentrasessionreusewithsuspiciousgraphaccess">Signal 2 - Microsoft Entra Session Reuse with Suspicious Graph Access</h4>
<p>While traditional query languages like KQL are excellent for filtering and visualizing individual log events, they struggle when a detection relies on correlating multiple records across datasets, time, and identifiers. This is where ES|QL (Elasticsearch Query Language) becomes essential. These types of multi-event correlations, temporal logic, and field normalization are difficult or entirely impossible in static filter-based query languages like KQL without writing multiple disjointed queries and manually correlating them after the fact.</p>
<p>This detection relies on correlating multiple events that happen close together but from different data sources,  namely sign-in logs and Microsoft Graph activity. The goal is to find suspicious reuse of the same session ID across multiple IPs, potentially indicating session hijacking or token abuse. For the sake of space regarding this publication, you can view the actual detection rule in the Detection Rules section. To better illustrate the flow of the query and meaning, below is a diagram to illustrate at a higher level.</p>
<pre><code>[ FROM logs-azure.* ]
        |
        |  ← Pulls events from all relevant Microsoft Cloud datasets:
        |     - azure.signinlogs (authentication)
        |     - azure.graphactivitylogs (resource access)
        ↓
[ WHERE session_id IS NOT NULL AND IP NOT MICROSOFT ASN ]
        |
        |  ← Filters out Microsoft-owned infrastructure (e.g., internal proxy,
        |     Graph API relays) using ASN checks.
        |  ← Ensures session ID exists so events can be correlated together.
        ↓
[ EVAL session_id, event_type, time_window, etc. ]
        |
        |  ← Normalizes key fields across datasets:
        |     - session_id (from signin or Graph)
        |     - user ID, app ID, event type ("signin" or "graph")
        |  ← Buckets events into 5-minute windows using DATE_TRUNC()
        ↓
[ KEEP selected fields ]
        |
        |  ← Retains only what's needed:
        |     session_id, timestamp, IP, user, client ID, etc.
        ↓
[ STATS BY session_id + time_window ]
        |
        |  ← Groups by session and time window to compute:
        |     - unique IPs used
        |     - apps involved
        |     - first and last timestamps
        |     - whether both signin and graph occurred
        ↓
[ EVAL time_diff + signin_to_graph_delay ]
        |
        |  ← Calculates:
        |     - time_diff: full session duration
        |     - delay: gap between signin and Graph access
        ↓
[ WHERE types_count &gt; 1 AND unique_ips &gt; 1 AND delay &lt;= 5 ]
        |
        |  ← Flags sessions where:
        |     - multiple event types (signin + graph)
        |     - multiple IPs used
        |     - all occurred within 5 minutes
        ↓
[ Output = Suspicious Session Reuse Detected ]
</code></pre>
<h4 id="signal3microsoftentraidconcurrentsigninswithsuspiciousproperties">Signal 3 - Microsoft Entra ID Concurrent Sign-Ins with Suspicious Properties</h4>
<p>This detection identifies suspicious sign-ins in Microsoft Entra ID where a user authenticates using the device code flow without MFA or sign-ins using the VSCode client. When the same identity signs in from two or more distinct IPs within a short time window using either method, it may indicate token replay, OAuth phishing, or adversary-in-the-middle (AitM) activity. </p>
<pre><code>[ FROM logs-azure.signinlogs* ]
        |
        |  ← Pulls only Microsoft Entra ID sign-in logs
        ↓
[ WHERE @timestamp &gt; NOW() - 1h AND event.outcome == "success" ]
        |
        |  ← Filters to the last hour and keeps only successful sign-ins
        ↓
[ WHERE source.ip IS NOT NULL AND identity IS NOT NULL ]
        |
        |  ← Ensures the sign-in is tied to a user and IP for correlation
        ↓
[ KEEP fields: identity, app_id, auth_protocol, IP, etc. ]
        |
        |  ← Retains app/client, IP, auth method, and resource info
        ↓
[ EVAL detection flags ]
        |
        |  ← Labels events as:
        |     - device_code: if MFA not required
        |     - visual_studio: if VS Code client used
        |     - other: everything else
        ↓
[ STATS BY identity ]
        |
        |  ← Aggregates all sign-ins per user, calculates:
        |     - IP count
        |     - Device Code or VSCode usage
        |     - App/client/resource details
        ↓
[ WHERE src_ip &gt;= 2 AND (device_code_count &gt; 0 OR vsc &gt; 0) ]
        |
        |  ← Flags users with:
        |     - Sign-ins from multiple IPs
        |     - And either:
        |         - Device Code w/o MFA
        |         - Visual Studio Code app
        ↓
[ Output = Potential OAuth Phishing or Token Misuse ]
</code></pre>
<p>While this variation of OAuth phishing lacks the full persistence offered by refresh tokens or PRTs, it still provides adversaries with valuable one-time access to sensitive user data – such as emails – through legitimate channels. This exercise helps us understand the limitations and capabilities of static <em>.default</em> scopes, the influence of app registrations, and how Microsoft Graph plays a pivotal role in post-authentication. It also reinforces a broader lesson: not all OAuth phishing attacks are created equal. Some aim for longevity (as we will see later) through refresh tokens or device registration, while others focus on immediate data theft via first-party clients. Understanding the nuances is essential for accurate detection logic.</p>
<h2 id="scenario2oauthphishingfordeviceregistration">Scenario 2: OAuth Phishing for Device Registration</h2>
<p>As we stated earlier – Volexity also reported a separate phishing playbook targeting victims, this time with the goal of registering a virtual device and obtaining a PRT. While this approach requires more steps from the adversary, the payoff is a token-granting token that offers far more utility for completing their operations. For our emulation efforts, we needed to expand our toolset and rely on ROADtools, just as the adversary did to remain accurate, however, several other python scripts were made for initial phishing and post-compromise actions.</p>
<h3 id="emulation-1">Emulation</h3>
<p>Starting with the initial phishing, we adjusted our Python script to craft a different OAuth URL that would be sent to our victim. This time, the focus was on our first-party client ID being the Microsoft Authentication Broker, requesting a refresh token with <em>offline_access</em> and redirecting to Entra ID’s cloud domain device joining endpoint URI.</p>
<pre><code>{
  "client_id": "29d9ed98-a469-4536-ade2-f981bc1d605e",
  "response_type": "code",
  "response_mode": "query",
  "redirect_uri": "https://login.microsoftonline.com/WebApp/CloudDomainJoin/8",
  "resource": "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9",
  "state": "nothingtoseehere"
}
</code></pre>
<p>If successful and our victim authenticates, the OAuth workflow will complete and the user will be redirected to the specified URI with an appended authorization code in the query parameters. Again, this code is the critical piece,  it must be shared back with the adversary in order to exchange it for tokens. In our case, once the phishing URL is opened and the target authenticates, we capture the authorization code embedded in the redirect and use it to request tokens from the Microsoft Entra ID token endpoint.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt903d51da02d2f8fb/6a7d801f1967eaf46132d88b/image5.png" alt="Figure 6: Microsoft Authentication Broker OAuth Phishing and token exchange with custom Python script" title="Figure 6: Microsoft Authentication Broker OAuth Phishing and token exchange with custom Python script" /></p>
<p>Now, here's where it gets interesting. In response to the token request, we receive three types of tokens: an access token, a refresh token, and an ID token. You might be asking –  why do we get more than just an access token? The answer lies in the scopes we initially requested: <em>openid</em>, <em>offline_access</em>, and <em>profile</em>.</p>
<ul>
<li><em>openid</em> grants us an ID token, which is part of the OpenID Connect layer and confirms the identity of the user — this is your authentication (authN) artifact.  </li>
<li><em>offline_access</em> provides a refresh token, enabling us to maintain a session and request new access tokens without requiring re-authentication, this supports persistent access but is critical for our use with ROADtx.  </li>
<li>And the access token itself is used to authorize requests to protected APIs like Microsoft Graph, this represents authorization (authZ).</li>
</ul>
<p>With these three tokens, we have everything: authentication, authorization, and long-term session continuity. That’s enough to shift from a simple OAuth phishing play into a more persistent foothold — like registering a new device in Microsoft Entra ID.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0462f575728ddbc6/6a7d8021de2315e1c5fd4e11/image10.png" alt="Figure 7: Captured JWT access, refresh and id token after exchange with authorization code" title="Figure 7: Captured JWT access, refresh and id token after exchange with authorization code" /></p>
<p>Now let’s connect the dots. A PRT requires registration of a valid device, one that Entra ID recognizes via a device certificate and private key. This is where ROADtx comes into play. Because our initial OAuth phishing impersonated a joined device flow, and the client used was the Microsoft Authentication Broker (a first-party client that interacts with the Device Registration Service), we already have the right access token in hand to interact with DRS. Notice in our returned object the scope is <em>adrs_access</em> which indicates Azure DRS access and is important for detections later.</p>
<p>From here, we simply drop the JSON object received from our token exchange into the <em>.roadtool_auth</em> file. This file is natively consumed by ROADtools, which uses the stored tokens to perform the device registration, completing the adversary’s move into persistence and setting the stage for obtaining a valid PRT.</p>
<p>After obtaining the tokens, we prep them for ROADtx by reformatting the JSON. ROADtx expects keys in camelCase, and we must also include the Microsoft Authentication Broker’s client ID as <em>_clientId</em>. This setup allows us to run the <em>refreshtokento</em> command, which takes our refresh token and exchanges it for a new JWT scoped to the DRS — specifically, the service principal <em>urn:ms-drs:enterpriseregistration.windows.net</em>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltec08c152b3d659be/6a7d8024fc63ab7a75649f8c/image1.png" alt="Figure 8: New authentication material from “refreshtokento” command for DRS as Microsoft Authentication Broker" title="Figure 8: New authentication material from “refreshtokento” command for DRS as Microsoft Authentication Broker" /></p>
<p>Once that’s in place, we use the device command to simulate a new device registration. This operation doesn’t require any actual virtual machine or physical host because it’s a backend registration that simply creates an entry in Entra ID. Upon success, we’re issued a valid device ID, PEM-encoded certificate, and private key — all of which are required to simulate a valid hybrid-joined device in the Microsoft ecosystem.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt879fd6b91827804a/6a7d80271967ea92fb32d89b/image9.png" alt="Figure 9: “device” command output from registering a device and receiving a PEM certificate and private key" title="Figure 9: “device” command output from registering a device and receiving a PEM certificate and private key" /></p>
<p>With our device identity established, we invoke the <em>prt</em> command. This uses the refresh token, device certificate, and private key to mint a new PRT — a highly privileged credential that effectively ties together user and device trust in Microsoft Entra ID.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt478c420f56b3f766/6a7d8029448e4e47675bdb1d/image3.png" alt="Figure 10: “prt” command with refresh token, PEM certificate and private key to obtain a PRT" title="Figure 10: “prt” command with refresh token, PEM certificate and private key to obtain a PRT" /></p>
<p>And just like that — whollah! — we have a PRT.</p>
<p>But why go through all this? Why register a device, generate a cert, and obtain a PRT when we already had an access token, ID token, and refresh token?</p>
<p>Because the PRT is the key to full user and device identity emulation. Think of it as a Kerberos-like ticket-granting token in Entra ID’s world, but instead – a token-granting token. With a valid PRT:</p>
<ul>
<li>An adversary can request new access and ID tokens for first-party apps like Outlook, SharePoint, or Teams without needing user interaction.  </li>
<li>The PRT enables seamless single sign-on SSO across multiple services, bypassing MFA and other conditional access policies (CAP) that would typically re-prompt the user. This is crucial for persistence as CAP and MFA are often huge barriers for adversaries.  </li>
<li>It supports long-lived persistence, as the PRT can be silently renewed and leveraged across sessions as long as the device identity remains trusted.</li>
</ul>
<p>And perhaps most dangerously — the PRT allows adversaries to impersonate a fully compliant, domain-joined device and user combo, effectively bypassing most conventional detection and response controls making the line between benign vs suspicious extremely thin for hunters and analysts.</p>
<p>This makes the PRT an incredibly valuable asset or one that enables covert lateral movement, privilege escalation, and deep access to Microsoft 365 services. It’s not just about getting in anymore — it’s about staying undetected.</p>
<p>Let’s not forget post-compromise activity…</p>
<p>ROADtx offers a few powerful commands frequently used by adversaries – <em>prtenrich</em> and <em>browserprtauth</em>. For example, we can access most browser-based UI services in the Microsoft suite by supplying our PRT which includes the necessary metadata for authentication and authorization – which originally belonged to our phishing victim (me), but is actually the Microsoft Authentication Broker acting on their behalf.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt96ee30d39ae16af6/6a7d802ce88c65d067008950/image12.png" alt="Figure 11: Accessing M365 Copilot with PRT via “browserprtauth” command" title="Figure 11: Accessing M365 Copilot with PRT via “browserprtauth” command" /></p>
<p>Volexity also reported that following device registration and the PRT acquisition – a 2FA request was sent to the initial victim, approved and then used to access emails via SharePoint. While they do not specify exactly how requests were made to – it’s reasonable to assume the adversary used the PRT to authenticate via a first-party Microsoft client – with the actual data access happening through Microsoft Graph. Graph remains a popular target post-compromise because it serves as a central API hub for most Microsoft 365 resources.</p>
<p>To start – let’s leverage ROADtx to auth with our PRT where Microsoft Teams is our client and Microsoft Graph is our resource. When using the <em>prtauth</em> command with our PRT, we are able to obtain a new access token and refresh token – clearly demonstrating the utility of the PRT as a token-granting token within Microsoft’s identity fabric.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt174db892b3983c2e/6a7d802ee02fac6ae05d3504/image8.png" alt="Figure 12: “prtauth” command for tokens as MSFT Teams client for MSFT Graph resource" title="Figure 12: “prtauth” command for tokens as MSFT Teams client for MSFT Graph resource" /></p>
<p>Once our access token is obtained, we plug it into a custom Python script to start enumerating our SharePoint sites, drives, items which allows us to identify files of interest and download their contents.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltef09c98193111afd/6a7d8031fc63ab9c61649f98/image6.png" alt="Figure 13: Discovering all SharePoint sites in tenant and downloading user files via MSFT Graph" title="Figure 13: Discovering all SharePoint sites in tenant and downloading user files via MSFT Graph" /></p>
<p>With this emulation – we showed how adversaries can chain OAuth phishing with the Microsoft Authentication Broker and obtain necessary credential material to leverage ROADtx for acquiring a PRT. This PRT then being an important utility post-compromise to access sensitive files, enumerate tenant resources and much more.</p>
<p>Now, let’s shift focus: what are plausible and accurate signals for detecting this activity?</p>
<h3 id="detection-1">Detection</h3>
<h4 id="signal1microsoftentraidoauthphishingasmicrosoftauthenticationbroker">Signal 1 - Microsoft Entra ID OAuth Phishing as Microsoft Authentication Broker</h4>
<p>Identifies instances where a user principal initiates an OAuth authorization code flow using the Microsoft Authentication Broker (MAB) as the client and the Device Registration Service (DRS) as the target resource. This detection focuses on cases where a single session ID is reused across two or more distinct IP addresses within a short time window, and at least one request originates from a browser — behavior commonly associated with phishing.</p>
<pre><code>[ FROM logs-azure.signinlogs-* ]
        |
        |  ← Pulls all Microsoft Entra ID sign-in logs
        ↓
[ WHERE app_id == MAB AND resource_id == DRS ]
        |
        |  ← Filters to OAuth auth code requests targeting
        |     Microsoft Authentication Broker + Device Reg Service
        ↓
[ EVAL session_id + is_browser ]
        |
        |  ← Extracts session ID and flags browser-based activity
        ↓
[ STATS BY 30-minute window, user, session_id ]
        |
        |  ← Groups logins within same session and time window,
        |     then aggregates:
        |       - user/session/token identifiers
        |       - distinct IPs and geo info
        |       - user agent, browser presence
        |       - app/resource/client info
        ↓
[ WHERE ip_count ≥ 2 AND session_id_count == 1 ]
        |
        |  ← Identifies reuse of a single session ID
        |     across ≥ 2 different IP addresses
        ↓
[ AND has_browser ≥ 1 AND auth_count ≥ 2 ]
        |
        |  ← Requires at least one browser-based request
        |     and at least two total sign-in events
        ↓
[ Output = Suspicious OAuth Flow with Auth Broker for DRS ]
</code></pre>
<h4 id="signal2suspiciousadrstokenrequestbymicrosoftauthbroker">Signal 2 - Suspicious ADRS Token Request by Microsoft Auth Broker</h4>
<p>Identifies Microsoft Entra ID sign-in events where a user principal authenticates using a refresh token issued to the Microsoft Authentication Broker (MAB) client, targeting the Device Registration Service (DRS) with the <em>adrs_access</em> OAuth scope. This pattern may indicate token-based access to DRS following an initial authorization code phishing or device registration flow.</p>
<pre><code>event.dataset: "azure.signinlogs" and azure.signinlogs.properties.app_id : "29d9ed98-a469-4536-ade2-f981bc1d605e" and azure.signinlogs.properties.resource_id : "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9" and azure.signinlogs.properties.authentication_processing_details.`Oauth Scope Info`: *adrs_access* and azure.signinlogs.properties.incoming_token_type: "refreshToken" and azure.signinlogs.properties.user_type: "Member"
</code></pre>
<h4 id="signal3unusualdeviceregistrationinentraid">Signal 3 - Unusual Device Registration in Entra ID</h4>
<p>Detects a sequence of Entra ID audit log events indicating potential malicious device registration activity using a refresh token, commonly seen after OAuth phishing. This pattern mimics the behavior of tools like ROADtx, where a newly registered Windows device (with a hardcoded OS version 10.0.19041.928) is added by the Device Registration Service, followed by user and owner assignments. All events must share the same correlation ID and occur within a one-minute window, strongly suggesting automation or script-driven registration rather than legitimate user behavior.</p>
<pre><code>sequence by azure.correlation_id with maxspan=1m
[any where event.dataset == "azure.auditlogs" and azure.auditlogs.identity == "Device Registration Service" and azure.auditlogs.operation_name == "Add device" and azure.auditlogs.properties.additional_details.value like "Microsoft.OData.Client/*" and (
  azure.auditlogs.properties.target_resources.`0`.modified_properties.`1`.display_name == "CloudAccountEnabled" and 
azure.auditlogs.properties.target_resources.`0`.modified_properties.`1`.new_value: "[true]") and azure.auditlogs.properties.target_resources.`0`.modified_properties.`3`.new_value like "*10.0.19041.928*"]
[any where event.dataset == "azure.auditlogs" and azure.auditlogs.operation_name == "Add registered users to device" and azure.auditlogs.properties.target_resources.`0`.modified_properties.`2`.new_value like "*urn:ms-drs:enterpriseregistration.windows.net*"]
[any where event.dataset == "azure.auditlogs" and azure.auditlogs.operation_name == "Add registered owner to device"]
</code></pre>
<h4 id="signal4entraidrttoprttransitionfromsameuseranddevice">Signal 4 - Entra ID RT to PRT Transition from Same User and Device</h4>
<p>This detection identifies when a Microsoft Entra ID user first authenticates using a refresh token issued to the Microsoft Authentication Broker (MAB), followed shortly by the use of a Primary Refresh Token (PRT) from the same device. This sequence is rare in normal user behavior and may indicate an adversary has successfully registered a device and escalated to persistent access using tools like ROADtx. By filtering out activity tied to the Device Registration Service (DRS) in the second step, the rule focuses on post-registration usage of the PRT to access other Microsoft 365 services. </p>
<p>This behavior strongly suggests token-based compromise and long-term session emulation, particularly when device trust is established silently. Catching this transition from refresh token to PRT is critical for surfacing high-fidelity signals of OAuth phishing and post-compromise persistence.</p>
<pre><code>sequence by azure.signinlogs.properties.user_id, azure.signinlogs.properties.device_detail.device_id with maxspan=1d
  [authentication where 
    event.dataset == "azure.signinlogs" and
    azure.signinlogs.category == "NonInteractiveUserSignInLogs" and
    azure.signinlogs.properties.app_id == "29d9ed98-a469-4536-ade2-f981bc1d605e" and
    azure.signinlogs.properties.incoming_token_type == "refreshToken" and
    azure.signinlogs.properties.device_detail.trust_type == "Azure AD joined" and
    azure.signinlogs.properties.device_detail.device_id != null and
    azure.signinlogs.properties.token_protection_status_details.sign_in_session_status == "unbound" and
    azure.signinlogs.properties.user_type == "Member" and
    azure.signinlogs.result_signature == "SUCCESS"
  ]
  [authentication where 
    event.dataset == "azure.signinlogs" and
    azure.signinlogs.properties.incoming_token_type == "primaryRefreshToken" and
    azure.signinlogs.properties.resource_display_name != "Device Registration Service" and
    azure.signinlogs.result_signature == "SUCCESS"
  ]
</code></pre>
<h4 id="signal5unusualprtusageandregistereddeviceforuserprincipal">Signal 5 - Unusual PRT Usage and Registered Device for User Principal</h4>
<p>This detection surfaces when a Microsoft Entra ID user registers a new device not previously seen within the last 7 days – behavior often associated with OAuth phishing campaigns that chain into ROADtx-based device registration. In these attacks, adversaries trick users into authorizing access for the Microsoft Authentication Broker (MAB) targeting the DRS, obtain a RT, and then use ROADtx to silently register a fake Windows device and mint a PRT. This rule alerts when a user principal authenticates from a newly observed device ID, particularly if the session is unbound, which is characteristic of token replay or device spoofing. Because PRTs require a registered and trusted device, this signal plays a critical role in identifying when an adversary has crossed from basic token abuse into persistent, stealthy access aligned with long-term compromise.</p>
<pre><code>event.dataset: "azure.signinlogs" and
    event.category: "authentication" and
    azure.signinlogs.properties.user_type: "Member" and
    azure.signinlogs.properties.token_protection_status_details.sign_in_session_status: "unbound" and
    not azure.signinlogs.properties.device_detail.device_id: "" and
    azure.signinlogs.properties.user_principal_name: *
</code></pre>
<p><a href="https://www.elastic.co/docs/solutions/security/detect-and-alert/about-detection-rules">New Terms</a> Values:</p>
<ul>
<li>azure.signinlogs.properties.user_principal_name  </li>
<li>azure.signinlogs.properties.device_detail.device_id</li>
</ul>
<p>This emulation helped us validate the full attacker workflow – from phishing for consent to establishing device trust and minting a PRT for long-term persistence. By chaining OAuth abuse with device registration, adversaries can satisfy CAPs, impersonate compliant endpoints and move laterally through cloud environments – often without triggering traditional security controls.</p>
<p>These nuances matter. When viewed in isolation, individual events like token issuance or device registration may appear benign. But when correlated across sign-in logs, audit data and token metadata, they expose a distinct trail of identity compromise.</p>
<h2 id="keytelemetrydetailsfordetectionandabuse">Key Telemetry Details for Detection and Abuse</h2>
<p>Throughout our emulation and detection efforts, specific telemetry artifacts consistently proved essential for separating benign OAuth activity from malicious abuse. Understanding how these fields appear in Microsoft Entra ID logs – and how attackers manipulate them – is critical for effective hunting and detection engineering. From client IDs and grant types to device compliance, token types and conditional access outcomes, these signals tell the story of identity-based attacks. Below we have curated a list of those most important and how they can enable us.</p>
<p><strong>Client Application IDs (client_id)</strong>: Identify the application initiating the OAuth request. First-party clients (e.g. VSCode, Auth Broker) can be abused to blend in. Third-party clients may be malicious or unreviewed - often representing consent grant attacks. Mainly used to identify risky or unexpected app usage.</p>
<p><strong>Target Resource (resource_id / resource_display_name)</strong>: Defines which MSFT service is being accessed (e.g. MSFT Graph or Teams). High value targets include – Graph API, SharePoint, Outlook, Teams and Directory Services. Resource targeting is often scoped by attacker objectives.</p>
<p><strong>Principal type (user_type)</strong>: Indicates if the sign-in was by a member (user) or service principal. Phishing campaigns almost always target member accounts. This enables easy filtering in detection logic but helps pair unusual first-party client requests on-behalf-of user principals.</p>
<p><strong>OAuth Grant Type (authentication_processing_details)</strong>: Key to understanding how the token was obtained – authorization codes, refresh tokens, device codes, client credentials, etc. Whereas refresh tokens and device code reuse are high-fidelity signals of post-compromise.</p>
<p><strong>Geolocation</strong>: Enables us to identify atypical sign-ins (e.g. rare country seen) or impossible travel (same user from distant locations in a short time). Combined with session ID and correlation IDs, these can reveal token hijacking, post identity compromise or lateral movement.</p>
<p><strong>Device Metadata (device_detail, trust_type, compliance_state)</strong>: Includes Device IDs, operating system, trust types, compliance, managed-state and more. Device registration and PRT issuance are tied to this metadata. Often a goal for adversaries to satisfy CAP and gain trusted access that is persistent.</p>
<p><strong>Authentication Protocols and Types (authentication_protocol / incoming_token_type)</strong>: Reveals whether the session was OAuth-based or if MFA was used. Token sources incoming are those used for this request that provide authN or authZ. Useful for detecting token reuse, non-interactive sign-ins.</p>
<p><strong>Authentication Material and Session Context</strong>: Tokens used can be inferred via incoming token type, token protection status and the session ID. Session reuse, long session duration or multiple IPs tied to a single session often indicate abuse.</p>
<p><strong>Conditional Access Policy Status</strong>: Evaluated during token issuance – however it heavily influences whether access was granted. This helps identify CAP evasion, unexpected policy outcomes or can factor into risk.</p>
<p><strong>Scopes and Consent Behavior</strong>: Requested scopes appear in the SCP or OAuth parameters captured in sign-in logs. Indicators of abuse include <em>offline_access</em>, <em>.default</em>, or broad scopes like <em>Mail.ReadWrite</em>. Consent telemetry can help pivot or correlate if the user approved a suspicious application.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Microsoft Entra ID’s OAuth implementation presents a double-edged sword: it enables powerful, seamless authentication experiences – but also exposes new opportunities for adversaries to exploit trust, session persistence and device registration attack paths.</p>
<p>By replicating the OAuth phishing techniques observed by Volexity, our team was able to validate how attackers abuse legitimate Microsoft applications, token flows, and open-source tools to gain stealthy access to sensitive data. We extended this work through hands-on emulation, diving deep into the mechanics of OAuth phishing and workflows, security token metadata and acquisition, helping surface behavioral indicators that defenders can detect.</p>
<p>Our findings reinforce a key point: OAuth abuse doesn’t rely on malware or code execution. It weaponizes identity, consent, and token reuse – making traditional security controls a challenge – and why log-based detection, correlation and behavioral analysis are so critical.</p>
<p>We hope the emulation artifacts, detection rules, and lessons shared here help defenders across the community better understand – and detect/hunt – this evolving class of cloud-based identity threats.</p>
<p>If you're using Elastic, we’ve open-sourced all the detection rules discussed in this blog to get you started. And if you're hunting in another SIEM, we encourage you to adapt the logic and adjust to your environment accordingly. </p>
<p>Identity is the new perimeter – and it’s time we treated it that way. Stay safe and happy hunting!</p>
<h2 id="detectionrules">Detection Rules</h2>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/d41a83059c78129b4e1337dca10b190b862ca0d2/rules/integrations/azure/initial_access_entra_graph_single_session_from_multiple_addresses.toml">Microsoft Entra ID Session Reuse with Suspicious Graph Access</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/integrations/azure/initial_access_entra_oauth_phishing_via_vscode_client.toml">Microsoft Entra ID OAuth Phishing via Visual Studio Code Client</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/3625b1b392e03aa7693a5b8251e7a5d3cfa53cce/rules/integrations/azure/initial_access_entra_id_suspicious_oauth_flow_via_auth_broker_to_drs.toml">Suspicious Microsoft OAuth Flow via Auth Broker to DRS</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/6b6407df88319f466c6cc56147210635bba5eb01/rules/integrations/azure/persistence_entra_id_suspicious_adrs_token_request.toml">Suspicious ADRS Token Request by Microsoft Auth Broker</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/43b0f0ada7e290bbbc0d4b1d53ed158e7bfbe75c/rules/integrations/azure/persistence_entra_id_suspicious_cloud_device_registration.toml">Unusual Device Registration in Entra ID</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/a18c76fe84eedc00efd9a712e74a0877b1061550/rules/integrations/azure/persistence_entra_id_rt_to_prt_transition_from_user_device.toml">Entra ID RT to PRT Transition from Same User and Device</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/integrations/azure/persistence_entra_id_user_signed_in_from_unusual_device.toml">Unusual Registered Device for User Principal</a></li>
</ul>
<h2 id="references">References:</h2>
<ul>
<li><a href="https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/">https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/</a>  </li>
<li><a href="https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/">https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/</a>  </li>
<li><a href="https://posts.specterops.io/requesting-azure-ad-request-tokens-on-azure-ad-joined-machines-for-browser-sso-2b0409caad30">https://posts.specterops.io/requesting-azure-ad-request-tokens-on-azure-ad-joined-machines-for-browser-sso-2b0409caad30</a>  </li>
<li><a href="https://learn.microsoft.com/en-us/entra/identity/devices/concept-primary-refresh-token">https://learn.microsoft.com/en-us/entra/identity/devices/concept-primary-refresh-token</a>  </li>
<li><a href="https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens">https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens</a>  </li>
<li><a href="https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow">https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow</a>  </li>
<li><a href="https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc#the-default-scope">https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc#the-default-scope</a></li>
</ul>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/entra-id-oauth-phishing-detection</link>
    <guid isPermaLink="false">entra-id-oauth-phishing-detection</guid>
    <category><![CDATA[Cloud Security]]></category>
    <dc:creator><![CDATA[Terrance DeJesus]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltafe92a005c66d54c/6a7d80343ce8e2714acf266a/Security_Labs_Images_22.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 25 Jun 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Exploring AWS STS AssumeRoot]]></title>
    <description><![CDATA[Explore AWS STS AssumeRoot, its risks, detection strategies, and practical scenarios to secure against privilege escalation and account compromise using Elastic's SIEM and CloudTrail data.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>Welcome to another installment of AWS detection engineering with Elastic. This article will dive into the new AWS Security Token Service(STS) API operation, AssumeRoot, simulate some practical behavior in a sandbox AWS environment, and explore detection capabilities within Elastic’s SIEM.</p>
<p>What to expect from this article:</p>
<ul>
<li>Basic insight into AWS STS web service  </li>
<li>Insight into STS’ AssumeRoot API operation  </li>
<li>Threat scenario using AssumeRoot with Terraform and Python code  </li>
<li>Detection and hunting opportunities for potential AssumeRoot abuse</li>
</ul>
<h2 id="understandingawsstsandtheassumerootapi">Understanding AWS STS and the AssumeRoot API</h2>
<p>AWS Security Token Service (STS) is a web service that enables users, accounts, and roles to request temporary, limited-privilege credentials. For IAM users, their accounts are typically registered in AWS Identity and Access Management (IAM), where either a login profile is attached for accessing the console or access keys, and secrets are created for programmatic use by services like Lambda, EC2, and others.</p>
<p>While IAM credentials are persistent, <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html#sts-regionalization"><strong>STS credentials</strong></a> are temporary. These credentials - comprising an access key, secret key, and session token - are granted upon request and are valid for a specific period. Requests are typically sent to the global <code>sts.amazonaws.com</code> endpoint, which responds with temporary credentials for a user or role. These credentials can then be used to access other AWS services on behalf of the specified user or role, as long as the action is explicitly allowed by the associated permission policy.</p>
<p>This process is commonly known as assuming a role, executed via the <a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html"><code>AssumeRole</code></a> API. It is frequently used in AWS environments and organizations for various scenarios. For example:</p>
<ul>
<li>An EC2 instance with an attached role will automatically use <code>AssumeRole</code> to retrieve temporary credentials for API requests.  </li>
<li>Similarly, Lambda functions often invoke <code>AssumeRole</code> to authenticate and perform their designated actions.</li>
</ul>
<p>Although <code>AssumeRole</code> is incredibly useful, it can pose a risk if roles are over-permissioned by the organization. Misconfigured policies with excessive permissions can allow adversaries to abuse these roles, especially in environments where the <a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/sec_permissions_least_privileges.html">Principle of Least Privilege</a> (PoLP) is not strictly enforced. Note that the security risks associated with AssumeRole are typically attributed to misconfigurations or not following best security practices by organizations. These are not the result of AssumeRole or even AssumeRoot development decisions.</p>
<h3 id="introductiontoassumeroot">Introduction to AssumeRoot</h3>
<p>AWS recently introduced the <code>AssumeRoot</code> API operation to STS. Similar to <code>AssumeRole</code>, it allows users to retrieve temporary credentials - but specifically for the <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html">root user</a> of a member account in an AWS organization.</p>
<h3 id="whatarememberaccounts">What Are Member Accounts?</h3>
<p>In AWS, <a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_access.html">member accounts</a> are separate accounts within an organization that have their own IAM users, services, and roles. These accounts are distinct from the management account, but they still fall under the same organizational hierarchy. Each AWS organization is created with a unique root account tied to the email address used during its setup. Similarly, every member account requires a root user or email address at the time of its creation, effectively establishing its own root identity.</p>
<h3 id="howdoesassumerootwork">How Does AssumeRoot Work?</h3>
<p>When a privileged user in the management account needs root-level privileges for a member account, they can use the <code>AssumeRoot</code> API to retrieve temporary credentials for the member account's root user. Unlike <code>AssumeRole</code>, where the target principal is a user ARN, the target principal for <code>AssumeRoot</code> is the member account ID itself. Additionally, a task policy ARN must be specified, which defines the specific permissions allowed with the temporary credentials.</p>
<p>Here are the available task policy ARNs for <code>AssumeRoot</code>:</p>
<ul>
<li><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMAuditRootUserCredentials">IAMAuditRootUserCredentials</a>  </li>
<li><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMCreateRootUserPassword">IAMCreateRootUserPassword</a>  </li>
<li><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMDeleteRootUserCredentials">IAMDeleteRootUserCredentials</a>  </li>
<li><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-S3UnlockBucketPolicy">S3UnlockBucketPolicy</a>  </li>
<li><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-SQSUnlockQueuePolicy">SQSUnlockQueuePolicy</a></li>
</ul>
<h3 id="potentialabuseoftaskpolicies">Potential Abuse of Task Policies</h3>
<p>While these predefined task policies limit what can be done with <code>AssumeRoot</code>, their scope can still be theoretically abused in the right circumstances. For example:</p>
<ul>
<li><strong>IAMCreateRootUserPassword</strong>: This policy grants the <a href="https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateLoginProfile.html"><code>iam:CreateLoginProfile</code></a> permission, allowing the creation of a login profile for a user that typically doesn't require console access. If an adversary gains access to programmatic credentials, they could create a login profile and gain console access to the account that is more persistent.  </li>
<li><strong>IAMDeleteRootUserCredentials</strong>: This policy allows the deletion of root credentials, but also grants permissions like <a href="https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html"><code>iam:ListAccessKeys</code></a> and <a href="https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListMFADevices.html"><code>iam:ListMFADevices</code></a>. These permissions could help an adversary gather critical information about access credentials or MFA configurations for further exploitation.</li>
</ul>
<h2 id="assumerootinaction">AssumeRoot in Action</h2>
<p>Now that we understand how AssumeRoot works at a high level, how it differs from AssumeRole, and the potential risks associated with improper security practices, let’s walk through a practical scenario to simulate its usage. It should be noted that this is one of many potential scenarios where AssumeRoot may or could be abused. As of this article's publication, no active abuse has been reported in the wild, as expected with a newer AWS functionality.</p>
<p>Below is a simple depiction of what we will accomplish in the following sections:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda73f4a8e6af2201/6a7d804142a117d74995911a/image3.png" alt="AssumeRoot scenario workflow" title="AssumeRoot scenario workflow" /></p>
<p>Before diving in, it’s important to highlight that we’re using an admin-level IAM user configured as the default profile for our local AWS CLI. This setup enables us to properly configure the environment using <a href="https://developer.hashicorp.com/terraform">Terraform</a> and simulate potential threat scenarios in AWS for detection purposes.</p>
<h3 id="memberaccountcreation">Member Account Creation</h3>
<p>The first step is to enable centralized root access for member accounts, as outlined in the <a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts.html">AWS documentation</a>. Centralized root access allows us to group all AWS accounts into a single organization, with each member account having its own root user.</p>
<p>Next, we manually create a member account within our organization through the Accounts section in the AWS Management Console. For this scenario, the key requirement is to note the member account ID, a unique 12-digit number. For our example, we’ll assume this ID is <code>000000000001</code> and name it <em>AWSAssumeRoot</em>. Centralized management of AWS accounts is a common practice for organizations that may separate different operational services into separate AWS accounts but want to maintain centralized management.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0232529910294c20/6a7d804473d9bd58af29abf3/image4.png" alt="AWS console showing management account and member account *AWSAssumeRoot*" title="AWS console showing management account and member account *AWSAssumeRoot*" /></p>
<p>We also add the member account as the <a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_delegate_policies.html">delegated administrator</a> for centralized root access as well, which allows that root member account to have centralized root access for any other member accounts of the organization.</p>
<p>While we won’t cover it in depth, we have also enabled the new <a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html">Resource control policies</a> (RCPs) within Identity and Access Management (IAM), which will allow central administration over permissions granted to resources within accounts in our organization, but by default, the <em>RCPFullAWSAccess</em> policy allows all permissions to all services for all principals and is attached directly to root.</p>
<h3 id="environmentsetup">Environment Setup</h3>
<p>For our simulation, we use Terraform to create an overly permissive IAM user named compromised_user. This user is granted the predefined <a href="https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AdministratorAccess.html">AdministratorAccess</a> policy, which provides admin-level privileges. Additionally, we generated an access key for this user while intentionally omitting a login profile to reflect a typical setup where credentials are used programmatically. This is not an uncommon practice, especially in developer environments.</p>
<p>Below is the <code>main.tf</code> configuration used to create the resources:</p>
<pre><code>provider "aws" {
  region = var.region
}

data "aws_region" "current" {}

# Create an IAM user with AdministratorAccess (simulated compromised user)
resource "aws_iam_user" "compromised_user" {
  name = "CompromisedUser"
}

# Attach AdministratorAccess Policy to the compromised user
resource "aws_iam_user_policy_attachment" "compromised_user_policy" {
  user       = aws_iam_user.compromised_user.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

# Create access keys for the compromised user
resource "aws_iam_access_key" "compromised_user_key" {
  user = aws_iam_user.compromised_user.name
}
</code></pre>
<p>We also define an <code>outputs.tf</code> file to capture key details about the environment, such as the region, access credentials, and the user ARN:</p>
<pre><code>output "aws_region" {
  description = "AWS Region where the resources are deployed"
  value       = var.region
}

output "compromised_user_access_key" {
  value       = aws_iam_access_key.compromised_user_key.id
  sensitive   = true
  description = "Access key for the compromised IAM user"
}

output "compromised_user_secret_key" {
  value       = aws_iam_access_key.compromised_user_key.secret
  sensitive   = true
  description = "Secret key for the compromised IAM user"
}

output "compromised_user_name" {
  value       = aws_iam_user.compromised_user.name
  description = "Name of the compromised IAM user"
}

output "compromised_user_arn" {
  value       = aws_iam_user.compromised_user.arn
  description = "ARN of the compromised IAM user"
}
</code></pre>
<p>Once we run <code>terraform apply</code>, the configuration creates a highly permissive IAM user (<code>compromised_user</code>) with associated credentials. These credentials simulate those that an adversary might obtain for initial access or escalating privileges.</p>
<p>This is one of the first hurdles for an adversary, collecting valid credentials. In today’s threat landscape information stealer malware and phishing campaigns are more common than ever, aimed at obtaining credentials that can be sold or used for lateral movement. While this is a hurdle, the probability of compromised credentials for initial access is high - such as those with <a href="https://www.cisa.gov/sites/default/files/2023-11/aa23-320a_scattered_spider_0.pdf">SCATTERED SPIDER</a> and <a href="https://sysdig.com/blog/scarleteel-2-0/">SCARLETEEL</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6d7d28d3a94c8a5f/6a7d80472f00b25b40efbedf/image1.png" alt="" /></p>
<h3 id="establishanstsclientsessionwithstolencredentials">Establish an STS Client Session with Stolen Credentials</h3>
<p>The next step is to establish an STS client session using the compromised credentials (<code>compromised_user</code> access key and secret key). This session allows the adversary to make requests to AWS STS on behalf of the compromised user.</p>
<p>Here’s the Python code to establish the STS client using the <a href="https://aws.amazon.com/sdk-for-python/">AWS Boto3 SDK</a> (the AWS SDK used to create, configure, and manage AWS services, such as Amazon EC2 and Amazon S3). This Python code is used to create the STS client with stolen IAM user credentials:</p>
<pre><code> sts_client = boto3.client(
     "sts",
     aws_access_key_id=compromised_access_key,
     aws_secret_access_key=compromised_secret_key,
     region_name=region,
     endpoint_url=f'https://sts.{region}.amazonaws.com'
 )
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt809e30d50222a575/6a7d804a2f00b20230efbee3/image7.png" alt="Terminal output when creating STS client with stolen IAM user credentials" title="Terminal output when creating STS client with stolen IAM user credentials" /></p>
<p><strong>Note:</strong> During testing, we discovered that the <code>endpoint_url</code> must explicitly point to <code>https://sts.&lt;region&gt;.amazonaws.com</code>. Omitting this may result in an <code>InvalidOperation</code> error when attempting to invoke the <code>AssumeRoot</code> API.</p>
<p>This STS client session forms the foundation for simulating an adversary's actions as we have taken compromised credentials and initiated our malicious actions.</p>
<h3 id="assumerootformemberaccountonbehalfofcompromiseduser">Assume Root for Member Account on Behalf of Compromised User</h3>
<p>After establishing an STS client session as the compromised user, we can proceed to call the AssumeRoot API. This request allows us to assume the root identity of a member account within an AWS Organization. For the request, the TargetPrincipal is set to the member account ID we obtained earlier, the session duration is set to 900 seconds (15 minutes), and the TaskPolicyArn is defined as <code>IAMCreateRootUserPassword</code>. This policy scopes the permissions to actions related to creating or managing root login credentials.</p>
<p>A notable permission included in this policy is <a href="https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateLoginProfile.html"><code>CreateLoginProfile</code></a>, which enables the creation of a login password for the root user. This allows access to the AWS Management Console as the root user.</p>
<p>Below is the Python code to assume root of member account <code>000000000001</code>, with permissions scoped by <em>IAMCreateRootUserPassword</em>.</p>
<pre><code>response = sts_client.assume_root(
    TargetPrincipal=member_account_id,
    DurationSeconds=900,
    TaskPolicyArn={"arn": "arn:aws:iam::aws:policy/root-task/IAMCreateRootUserPassword"},
)
root_temp_creds = response["Credentials"]
</code></pre>
<p>If the AssumeRoot request is successful, the response provides temporary credentials (<code>root_temp_creds</code>) for the root account of the target member. These credentials include an access key, secret key, and session token, enabling temporary root-level access for the duration of the session.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt73ec0a1f4d60546e/6a7d804c2f00b27f6befbee7/image6.png" alt="Terminal output showing AssumeRoot with IAMCreateRootUserPassword for AWSAssumeRoot member account
" title="Terminal output showing AssumeRoot with IAMCreateRootUserPassword for AWSAssumeRoot member account" /> </p>
<h3 id="creatingaloginprofileforthememberrootaccount">Creating a Login Profile for the Member Root Account</h3>
<p>With temporary root credentials in hand, the next step is to establish an authenticated IAM client session as the root user of the member account. Using this session, we can call the <code>create_login_profile()</code> method. This method allows us to assign a login password to the root user, enabling console access.</p>
<p>The following Python code establishes an authenticated IAM client and creates a login profile:</p>
<pre><code>iam_client = boto3.client(
    "iam",
    aws_access_key_id=root_temp_creds["AccessKeyId"],
    aws_secret_access_key=root_temp_creds["SecretAccessKey"],
    aws_session_token=root_temp_creds["SessionToken"],
)

response = iam_client.create_login_profile()
</code></pre>
<p>It’s worth noting that the <code>create_login_profile()</code> method requires no explicit parameters for the root user, as it acts on the credentials of the currently authenticated session. In this case, it will apply to the root user of the member account.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte47e5b26d5d93251/6a7d8050fc63ab20ec649fac/image5.png" alt="Terminal output showing IAM client established as Root member account and CreateLoginProfile request" title="Terminal output showing IAM client established as Root member account and CreateLoginProfile request" /> </p>
<h3 id="resettheadministratorpasswordandlogintotheawsconsole">Reset the Administrator Password and Login to the AWS Console</h3>
<p>At this stage, we’re nearly complete! Let’s recap the progress so far:</p>
<ol>
<li>Using compromised IAM user credentials, we established an STS session to assume the identity of an overly permissive user.  </li>
<li>Leveraging this session, we assumed the identity of the root user of a target member account, acquiring temporary credentials scoped to the <code>IAMCreateRootUserPassword</code> task policy.  </li>
<li>With these temporary root credentials, we established an IAM client session and successfully created a login profile for the root user.</li>
</ol>
<p>The final step involves resetting the root user password to gain permanent access to the AWS Management Console. To do this, visit the AWS console login page and attempt to log in as the root user. Select the “Forgot Password” option to initiate the password recovery process. This will prompt a CAPTCHA challenge, after which a password reset link is sent to the root user’s email address. This would be the third roadblock for an adversary as they would need access to the root user’s email inbox to continue with the password reset workflow. It should be acknowledged that if <em>CreateLoginProfile</em> is called, you can specify the password for the user and enforce a “password reset required”. However, this is not allowed for root accounts by default, and for good reason by AWS. Unlike the first hurdle of having valid credentials, access to a user’s inbox may prove more difficult and less likely, but again, with enough motivation and resources, it is still possible.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt525a0d9e7b428264/6a7d8053bdcff02320c4005a/image2.png" alt="Password recovery request from AWS sign-in for root" title="Password recovery request from AWS sign-in for root" /></p>
<p>After selecting the password reset link, you can set a new password for the root user. This step provides lasting access to the console as the root user. Unlike the temporary credentials obtained earlier, this access is no longer limited by the session duration or scoped permissions of the IAMCreateRootUserPassword policy, granting unrestricted administrative control over the member account.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4b3d65da339e3f9/6a7d8055b43770b7da4d3f55/image8.png" alt="Successful login as root for AWSAssumeRoot member account" title="Successful login as root for AWSAssumeRoot member account" /></p>
<p><strong>Before moving on, if you followed along and tried this in your environment, we want to gently remind you to use Terraform to remove testing resources</strong> using the terraform destroy command in the same folder where you initialized and deployed the resources.</p>
<h2 id="detectionandhuntingopportunities">Detection and Hunting Opportunities</h2>
<p>While exploring cloud features and APIs from an adversary's perspective is insightful, our ultimate responsibility lies in detecting and mitigating malicious or anomalous behavior, alerting stakeholders, and responding effectively. Also, while such a scenario has not been publicly documented in the wild, we should not wait to be a victim either and be reactive, hence the reason for our whitebox scenario.</p>
<p>The following detection and hunting queries rely on AWS CloudTrail data ingested into the Elastic Stack using the <a href="https://www.elastic.co/docs/current/integrations/aws">AWS integration</a>. If your environment differs, you may need to adjust these queries for custom ingestion processes or adapt them for a different SIEM or query tool.</p>
<p><strong>Note:</strong> Ensure that AWS CloudTrail is enabled for all accounts in your organization to provide comprehensive visibility into activity across your AWS environment. You may also need to enable the specific trail used for monitoring across the entire organization so all member accounts are observed properly.</p>
<h3 id="huntingunusualactionforiamuseraccesskey">Hunting - Unusual Action for IAM User Access Key</h3>
<p>This query identifies potentially compromised IAM access keys that are used to make unusual API calls. It sorts the results in ascending order to surface less frequent API calls within the last two weeks. This query can be adjusted to account for different API calls or include other CloudTrail-specific fields.</p>
<p>Hunting Query: <a href="https://github.com/elastic/detection-rules/blob/7b88b36d294407cc1ea2ab1b0acbbbf3104162a9/hunting/aws/docs/iam_unusual_access_key_usage_for_user.md">AWS IAM Unusual AWS Access Key Usage for User</a></p>
<p>MITRE ATT\&amp;CK: </p>
<ul>
<li>T1078.004 - <a href="https://attack.mitre.org/techniques/T1078/004/">Valid Accounts: Cloud Accounts</a></li>
</ul>
<p>Language: ES|QL</p>
<pre><code>FROM logs-aws.cloudtrail*
| WHERE @timestamp &gt; now() - 14 day
| WHERE
    event.dataset == "aws.cloudtrail"
    and event.outcome == "success"
    and aws.cloudtrail.user_identity.access_key_id IS NOT NULL
    and aws.cloudtrail.resources.arn IS NOT NULL
    and event.action NOT IN ("GetObject")
| EVAL daily_buckets = DATE_TRUNC(1 days, @timestamp)
| STATS
    api_counts = count(*) by daily_buckets, aws.cloudtrail.user_identity.arn, aws.cloudtrail.user_identity.access_key_id, aws.cloudtrail.resources.arn, event.action
| WHERE api_counts &lt; 2
| SORT api_counts ASC
</code></pre>
<h3 id="detectionunusualassumerootactionbyrareiamuser">Detection - Unusual Assume Root Action by Rare IAM User</h3>
<p>Detection Rule: <a href="https://github.com/elastic/detection-rules/blob/main/rules/integrations/aws/privilege_escalation_sts_assume_root_from_rare_user_and_member_account.toml">AWS STS AssumeRoot by Rare User and Member Account</a></p>
<p>This query identifies instances where the <code>AssumeRoot</code> API call is made by an IAM user ARN and member account that have not performed this action in the last 14 days. This anomaly-based detection uses Elastic’s <a href="https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule">New Terms</a> detection rule.</p>
<ul>
<li>The <code>aws.cloudtrail.user_identity.arn</code> field identifies the source IAM user from the management AWS account.  </li>
<li>The <code>aws.cloudtrail.resources.account_id</code> field reflects the target member account.</li>
</ul>
<p>MITRE ATT\&amp;CK: </p>
<ul>
<li>T1548.005 - <a href="https://attack.mitre.org/techniques/T1548/005/">Temporary Elevated Cloud Access</a>  </li>
<li>T1098.003 - <a href="https://attack.mitre.org/techniques/T1098/003/">Additional Cloud Roles</a></li>
</ul>
<p>Language: KQL</p>
<pre><code>event.dataset: "aws.cloudtrail"
    and event.provider: "sts.amazonaws.com"
    and event.action: "AssumeRoot"
    and event.outcome: "success"
</code></pre>
<p>New Term Fields:<br />
If any combination of these fields has not been seen executing AssumeRoot within the last 14 days, an alert is generated.</p>
<ul>
<li><code>aws.cloudtrail.user_identity.arn</code>  </li>
<li><code>aws.cloudtrail.resources.account_id</code></li>
</ul>
<h3 id="detectionselfcreatedloginprofileforrootmemberaccount">Detection - Self-Created Login Profile for Root Member Account</h3>
<p>This query detects instances where a login profile is created for a root member account by the root account itself, potentially indicating unauthorized or anomalous behavior.</p>
<p>Detection Rule: <a href="https://github.com/elastic/detection-rules/blob/4374128458d116211d5d22993b6d87f6c82a30a0/rules/integrations/aws/persistence_iam_create_login_profile_for_root.toml">AWS IAM Login Profile Added for Root</a></p>
<p>MITRE ATT\&amp;CK:</p>
<ul>
<li>T1098.003 - <a href="https://attack.mitre.org/techniques/T1098/003/">Account Manipulation: Additional Cloud Roles</a>  </li>
<li>T1548.005 - <a href="https://attack.mitre.org/techniques/T1548/005/">Abuse Elevation Control Mechanism: Temporary Elevated Cloud Access</a>  </li>
<li>T1078.004 - <a href="https://attack.mitre.org/techniques/T1078/004/">Valid Accounts: Cloud Accounts</a></li>
</ul>
<p>Language: ES|QL</p>
<pre><code>FROM logs-aws.cloudtrail* 
| WHERE
    // filter for CloudTrail logs from IAM
    event.dataset == "aws.cloudtrail"
    and event.provider == "iam.amazonaws.com"
    // filter for successful CreateLoginProfile API call
    and event.action == "CreateLoginProfile"
    and event.outcome == "success"
    // filter for Root member account
    and aws.cloudtrail.user_identity.type == "Root"
    // filter for an access key existing which sources from AssumeRoot
    and aws.cloudtrail.user_identity.access_key_id IS NOT NULL
    // filter on the request parameters not including UserName which assumes self-assignment
    and NOT TO_LOWER(aws.cloudtrail.request_parameters) LIKE "*username*"
| keep
    @timestamp,
    aws.cloudtrail.request_parameters,
    aws.cloudtrail.response_elements,
    aws.cloudtrail.user_identity.type,
    aws.cloudtrail.user_identity.arn,
    aws.cloudtrail.user_identity.access_key_id,
    cloud.account.id,
    event.action,
    source.address
    source.geo.continent_name,
    source.geo.region_name,
    source.geo.city_name,
    user_agent.original,
    user.id
</code></pre>
<p>These detections are specific to our scenario, however, are not fully inclusive regarding all potential AssumeRoot abuse. If you choose to explore and discover some additional hunting or threat detection opportunities, feel free to share in our <a href="https://github.com/elastic/detection-rules">Detection Rules</a> repository or the <a href="https://github.com/elastic/detection-rules/tree/main/hunting">Threat Hunting</a> library of ours.</p>
<h2 id="hardeningpracticesforassumerootuse">Hardening Practices for AssumeRoot Use</h2>
<p>AWS <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html">documentation</a> contains several important considerations for best security practices regarding IAM, STS, and many other services. However, cloud security is not a “one size fits all” workflow and security practices should be tailored to your environment, risk-tolerance, and more.</p>
<p><strong>Visibility is Key:</strong> If you can’t see it, you can’t protect it. Start by enabling CloudTrail with organization-wide trails to log activity across all accounts. Focus on capturing IAM and STS operations for insights into access and permission usage. Pair this with Security Hub for continuous monitoring and tools like Elastic or GuardDuty to hunt for unusual AssumeRoot actions.</p>
<p><strong>Lock Down AssumeRoot Permissions:</strong> Scope AssumeRoot usage to critical tasks only, like audits or recovery, by restricting task policies to essentials like IAMAuditRootUserCredentials. Assign these permissions to specific roles in the management account and keep those roles tightly controlled. Regularly review and remove unnecessary permissions to maintain the PLoP.</p>
<p><strong>MFA and Guardrails for Root Access:</strong> Enforce MFA for all users, especially those with access to AssumeRoot. Use AWS Organizations to disable root credential recovery unless absolutely needed and remove unused root credentials entirely. RCPs can help centralize and tighten permissions for tasks involving AssumeRoot or other sensitive operations.</p>
<h1 id="conclusion">Conclusion</h1>
<p>We hope this article provides valuable insight into AWS’ AssumeRoot API operation, how it can be abused by adversaries, and some threat detection and hunting guidance. Abusing AssumeRoot is one of many living-off-the-cloud (LotC) techniques that adversaries have the capability to target, but we encourage others to explore, research, and share their findings accordingly with the community and AWS.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/exploring-aws-sts-assumeroot</link>
    <guid isPermaLink="false">exploring-aws-sts-assumeroot</guid>
    <category><![CDATA[Cloud Security]]></category>
    <dc:creator><![CDATA[Terrance DeJesus]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfd368056a9ceca0b/6a7d80588fc2d0336f3eb8a5/Security_Labs_Images_20.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 10 Dec 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Monitoring Okta threats with Elastic Security]]></title>
    <description><![CDATA[This article guides readers through establishing an Okta threat detection lab, emphasizing the importance of securing SaaS platforms like Okta. It details creating a lab environment with the Elastic Stack, integrating SIEM solutions, and Okta.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>Welcome to another installment of Okta threat research with Elastic. <a href="https://www.elastic.co/security-labs/starter-guide-to-understanding-okta">Previously</a>, we have published articles exploring Okta’s core services and offerings. This article is dedicated to the practical side of cyber defense - setting up a robust Okta threat detection lab. Our journey will navigate through the intricacies of configuring a lab environment using the Elastic Stack, integrating SIEM solutions, and seamlessly connecting with Okta.</p>
<p>The goal of this article is not just to inform but to empower. Whether you're a seasoned cybersecurity professional or a curious enthusiast, our walkthrough aims to equip you with the knowledge and tools to understand and implement advanced threat detection mechanisms for Okta environments. We believe that hands-on experience is the cornerstone of effective cybersecurity practice, and this guide is crafted to provide you with a practical roadmap to enhance your security posture.</p>
<p>As we embark on this technical expedition, remember that the world of cybersecurity is dynamic and ever-evolving. The methods and strategies discussed here are a reflection of the current landscape and best practices. We encourage you to approach this guide with a mindset of exploration and adaptation, as the techniques and tools in cybersecurity are continually advancing.</p>
<p>So, let's dive into our detection lab setup for Okta research.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>For starters, an Okta license (a <a href="https://www.okta.com/free-trial/">trial license</a> is fine) is required for this lab setup. This will at least allow us to generate Okta system logs within our environment, which we can then ingest into our Elastic Stack.</p>
<p>Secondarily, after Okta is set up, we can deploy a Windows Server, set up Active Directory (AD), and use the <a href="https://help.okta.com/en-us/content/topics/directory/ad-agent-main.htm">AD integration</a> in Okta to sync AD with Okta for Identity and Access Management (IAM). This step is not necessary for the rest of the lab, however, it can help extend our lab for other exercises and scenarios where endpoint and Okta data are both necessary for hunting.</p>
<h2 id="signupforoktaworkforceidentity">Sign up for Okta Workforce Identity</h2>
<p>We will set up a fresh Okta environment for this walkthrough by signing up for a Workforce Identity Cloud trial. If you already have an Okta setup in your environment, then feel free to skip to the <code>Setting Up the Elastic Stack</code> section.</p>
<p>Once signed up for the trial, you are typically presented with a URL containing a trial license subdomain and the email to log into the Okta admin console.</p>
<p>To start, users must pivot over to the email they provided when signing up and follow the instructions of the activation email by Okta, which contains a QR code to scan. </p>
<p>The QR code is linked to the Okta Verify application that is available on mobile devices, iOS and Android. A prompt on the mobile device for multi-factor authentication (MFA) using a phone number and face recognition is requested. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt19d2018c5c7b1c1b/6a7d832f42a1173a2e959154/image23.png" alt="Setting up Okta Verify through a mobile device" title="Setting up Okta Verify through a mobile device" /></p>
<p><em>Image 1: Setting up Okta Verify through a mobile device</em></p>
<p>Once set up, we are redirected to the Okta admin console to configure MFA using Okta Verify.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2b27a5484b5568cd/6a7d8332227b1c44b859583f/image9.png" alt="The Okta Admin console" title="The Okta Admin console" /></p>
<p><em>Image 2: The Okta Admin console</em></p>
<p>At this point, you should have a trial license for Okta, have setup MFA, and have access to the Okta admin console.</p>
<h2 id="settingupyourfreecloudstack">Setting up your free cloud stack</h2>
<p>For this lab, we will use a <a href="https://cloud.elastic.co/registration">free trial</a> of an Elastic Cloud instance. You also have the option to create the stack in <a href="https://www.elastic.co/partners/aws?utm_campaign=Comp-Stack-Trials-AWSElasticsearch-AMER-NA-Exact&amp;utm_content=Elasticsearch-AWS&amp;utm_source=adwords-s&amp;utm_medium=paid&amp;device=c&amp;utm_term=amazon%20elk&amp;gclid=Cj0KCQiA1ZGcBhCoARIsAGQ0kkqI9gFWLvEX--Fq9eE8WMb43C9DsMg_lRI5ov_3DL4vg3Q4ViUKg-saAsgxEALw_wcB">Amazon Web Services</a> (AWS), <a href="https://www.elastic.co/guide/en/cloud/current/ec-billing-gcp.html">GCP</a>, or Microsoft Azure if you’d like to set up your stack in an existing cloud service provider (CSP). Ensure you <a href="https://www.elastic.co/guide/en/cloud/current/ec-account-user-settings.html#ec-account-security-mfa">enable MFA for your Elastic Cloud environment</a>.</p>
<p>Once registered for the free trial, we can focus on configuring the Elastic Stack deployment. For this lab, we will call our deployment okta-threat-detection and deploy it in GCP. It is fine to leave the default settings for your deployment, and we recommend the latest version for all the latest features. For the purposes of this demo, we use the following:</p>
<ul>
<li>Name: okta-threat-detection</li>
<li>Cloud provider: Google Cloud</li>
<li>Region: Iowa (us-central1)</li>
<li>Hardware profile: Storage optimized</li>
<li>Version: 8.12.0 (latest)</li>
</ul>
<p>The option to adjust additional settings for Elasticsearch, Kibana, Integrations, and more is configurable during this step. However, default settings are fine for this lab exercise. If you choose to leverage the Elastic Stack for a more permanent, long-term strategy, we recommend planning and designing architecturally according to your needs.</p>
<p>Once set, select “Create deployment” and the Elastic Stack will automatically be deployed in GCP (or whatever cloud provider you selected). You can download the displayed credentials as a CSV file or save them wherever you see fit. The deployment takes approximately 5 minutes to complete and once finished, you can select “Continue” to log in. Congratulations, you have successfully deployed the Elastic Stack within minutes!</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte24203601d2511c2/6a7d8335de23153f98fd4e7c/image14.png" alt="Your newly deployed Elastic stack" title="Your newly deployed Elastic stack" /></p>
<p><em>Image 3: Your newly deployed Elastic stack</em></p>
<h2 id="setupfleetfromthesecuritysolution">Setup Fleet from the Security Solution</h2>
<p>As a reminder, <a href="https://www.elastic.co/guide/en/fleet/current/fleet-overview.html">Fleet</a> enables the creation and management of an agent policy, which will incorporate the <a href="https://docs.elastic.co/en/integrations/okta">Okta integration</a> on an Elastic Agent. This integration is used to access and ingest Okta logs into our stack.</p>
<h3 id="createanoktapolicy">Create an Okta policy</h3>
<p>For our Elastic Agent to know which integration it is using, what data to gather, and where to stream that data within our stack, we must first set up a custom Fleet policy we’re naming Okta.</p>
<p>To set up a fleet policy within your Elastic Stack, do the following in your Elastic Stack:</p>
<ol>
<li>Navigation menu &gt; Management &gt; Fleet &gt; Agent Policies &gt; Create agent policy</li>
<li>Enter “Okta” as a name &gt; Create Agent Policy</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte3bac1dbe3ea9e33/6a7d8338de23151a6dfd4e80/image19.png" alt="Fleet agent policies page in Elastic Stack" title="Fleet agent policies page in Elastic Stack" /></p>
<p><em>Image 4: Fleet agent policies page in Elastic Stack</em></p>
<h2 id="setuptheoktaintegration">Setup the Okta integration</h2>
<p>Once our policy is established, we need to install the Okta integration for the Elastic Stack we just deployed.</p>
<p>By selecting the “Okta” name in the agent policies that was just created, we need to add the Okta integration by selecting “Add integration” as shown below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7dfb7ea8d7a45313/6a7d833bdd26d254c22a728d/image17.png" alt="The Okta integration within the agent policies" title="The Okta integration within the agent policies" /></p>
<p><em>Image 5: The Okta integration within the agent policies</em></p>
<p>Typing “Okta” into the search bar will show the Okta integration that needs to be added. Select this integration and the following prompt should appear.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt022be71cc1e4e13f/6a7d833f1967eae55c32d8dc/image22.png" alt="The Okta Integration page" title="The Okta Integration page" /></p>
<p><em>Image 6: The Okta Integration page</em></p>
<p>By selecting “Add Okta” we can now begin to set up the integration with a simple step-by-step process, complimentary to adding our first integration in the Elastic Stack.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcf9b6851a679905/6a7d83422f00b238a3efbf23/image7.png" alt="Adding integrations into the Elastic Stack" title="Adding integrations into the Elastic Stack" /></p>
<p><em>Image 7: Adding integrations into the Elastic Stack</em></p>
<h2 id="installtheelasticagentonanendpoint">Install the Elastic Agent on an endpoint</h2>
<p>As previously mentioned, we have to install at least one agent on an endpoint to access data in Okta, associated with the configured Okta policy. We recommend a lightweight Linux host, either as a VM locally or in a CSP such as GCP, to keep everything in the same environment. For this publication, I will use a VM instance of <a href="https://releases.ubuntu.com/focal/">Ubuntu 20.04 LTS</a> VM in Google’s Compute Engine (GCE). Your endpoint can be lightweight, such as GCP N1 or E2 series, as its sole purpose is to run the Elastic Agent.</p>
<p>Select the “Install Elastic Agent” button and select which host the agent will be installed on. For this example, we will be using a Linux host. Once selected, a “Copy” option is available to copy and paste the commands into your Linux console, followed by execution.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1429e691687069e6/6a7d834505b7b547f8188b82/image24.png" alt="Install Elastic Agent" title="Install Elastic Agent" /></p>
<p><em>Image 8: Install Elastic Agent</em></p>
<h2 id="createanoktatoken">Create an Okta token</h2>
<p>At this point, we need an API key and an Okta system logs API URL for the integration setup. Thus, we must pivot to the Okta admin console to create the API token.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcb0c8317b388f17b/6a7d8348fc63abaa45649ff0/image5.png" alt="Access the Okta Admin console" title="Access the Okta Admin console" /></p>
<p><em>Image 9: Access the Okta Admin console</em></p>
<p>From the Okta admin console, select the following:</p>
<ol>
<li>Security &gt; API &gt; Tokens</li>
<li>Select the “Create token” button</li>
</ol>
<p>In this instance, we name the API token “elastic”. Since my administrator account creates the token, it inherits the permissions and privileges of my account. In general, we recommend creating a separate user and scoping permissions properly with principle-of-least-privilege (PoLP) for best security practices. I recommend copying the provided API token key to the clipboard, as it is necessary for the Okta integration setup.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta2770b85171dae83/6a7d834b73d9bd12fd29ac3b/image16.png" alt="Copy your API token" title="Copy your API token" /></p>
<p><em>Image 10: Copy your API token</em></p>
<p>We also need to capture the Okta API Logs URL, which is our HTTPS URL with the URI <code>/api/v1/logs</code> or system logs API endpoint.</p>
<p>For example: <code>https://{okta-subdomain}.okta.com/api/v1/logs</code></p>
<p>The Elastic Agent, using the Okta integration, will send requests to this API URL with our API token included in the authorization header of the requests as a Single Sign-On for Web Systems (SSWS) token. With this information, we are ready to finalize our Okta integration setup in the Elastic Stack.</p>
<h2 id="addoktaintegrationrequirements">Add Okta integration requirements</h2>
<p>Pivoting back to the Okta integration setup in the Elastic Stack, it requires us to add the API token and the Okta System logs API URL as shown below. Aside from this, we change the “Initial Interval” from 24 hours to 2 minutes. This will help check for Okta logs immediately after we finish our setup.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc84e40e0df401e46/6a7d834e5967e564175da56f/image12.png" alt="Configure log collection" title="Configure log collection" /></p>
<p><em>Image 11: Configure log collection</em></p>
<p>Once this information is submitted to the Okta integration setup, we can select the “Confirm incoming data” button to verify that logs are properly being ingested from the Elastic Agent.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt03487fdd85655ddb/6a7d8351bd969ed5736ef48a/image11.png" alt="Preview data from Okta" title="Preview data from Okta" /></p>
<p><em>Image 12: Preview data from Okta</em></p>
<p>While we have confirmed that data is in fact being ingested from the Elastic Agent, we must also confirm that we have Okta-specific logs being ingested. I would suggest that you take a moment to pivot back to Okta and change some settings in the admin console. This will then generate Okta system logs that will eventually be extracted by our Elastic Agent and ingested into our Elastic Stack. Once completed, we can leverage the Discover feature within Kibana to search for the Okta system logs that should have been generated.</p>
<p>The following query can help us accomplish this - <code>event.dataset:okta*</code></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcbaeb2dba8d0366b/6a7d835473d9bd66b029ac41/image13.png" alt="Use Discover to explore your Okta data" title="Use Discover to explore your Okta data" /></p>
<p><em>Image 13: Use Discover to explore your Okta data</em></p>
<p>If you have managed to find Okta logs from this, then congratulations rockstar, you have successfully completed these steps:</p>
<ol>
<li>Signed up for Okta Workforce Identity with a trial license</li>
<li>Deployed a trial Elastic stack via cloud.elastic.co</li>
<li>Deployed an agent to your host of choice</li>
<li>Created an Okta policy</li>
<li>Setup the Okta integration</li>
<li>Created an Okta API token</li>
<li>Confirmed incoming data from our Elastic agent</li>
</ol>
<h2 id="enableoktadetectionrules">Enable Okta detection rules</h2>
<p>Elastic has 1000+ pre-built detection rules not only for Windows, Linux, and macOS endpoints, but also for several integrations, including Okta. You can view our current existing Okta <a href="https://github.com/elastic/detection-rules/tree/main/rules/integrations/okta">rules</a> and corresponding MITRE ATT&amp;CK <a href="https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-oktaWILDCARD.json&amp;leave_site_dialog=false&amp;tabs=false">coverage</a>.</p>
<p>To enable Okta rules, complete the following in the Elastic Stack:</p>
<ol>
<li>Navigation menu &gt; Security &gt; Manage &gt; Rules</li>
<li>Select “Load Elastic prebuilt rules and timeline templates”</li>
<li>Once all rules are loaded:
a. Select “Tags” dropdown
b. Search “Okta”
c. Select all rules &gt; Build actions dropdown &gt; Enable</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta88a17da51396482/6a7d8357fc63ab8bf5649ff4/image15.png" alt="Searching for Out-of-the-Box (OOB) Okta Detection Rules" title="Searching for Out-of-the-Box (OOB) Okta Detection Rules" /></p>
<p><em>Image 14: Searching for Out-of-the-Box (OOB) Okta Detection Rules</em></p>
<p>While we won’t go in-depth about exploring all rule information, we recommend <a href="https://www.elastic.co/guide/en/security/current/detection-engine-overview.html">doing so</a>. Elastic has additional information, such as related integrations, investigation guides, and much more! Also, you can add to our community by <a href="https://www.elastic.co/guide/en/security/current/rules-ui-create.html">creating your own</a> detection rule with the “Create new rule” button and <a href="https://github.com/elastic/detection-rules#how-to-contribute">contribute</a> it to our detection rules repository.</p>
<h2 id="letstriggeraprebuiltrule">Let’s trigger a pre-built rule</h2>
<p>After all Okta rules have been enabled, we can now move on to testing alerts for these rules with some simple emulation.</p>
<p>For this example, let’s use the <a href="https://github.com/elastic/detection-rules/blob/main/rules/integrations/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml">Attempt to Reset MFA Factors for an Okta User Account</a> detection rule that comes fresh out-of-the-box (OOB) with prebuilt detection rules.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta88a17da51396482/6a7d8357fc63ab8bf5649ff4/image15.png" alt="Enabling an OOB Okta detection rule to test alerting" title="Enabling an OOB Okta detection rule to test alerting" /></p>
<p><em>Image 15: Enabling an OOB Okta detection rule to test alerting</em></p>
<p>To trigger, we simply log into our Okta admin console and select a user of choice from Directory &gt; People and then More Actions &gt; Reset Multifactor &gt; Reset All.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt14732fc31a74d613/6a7d835aea068d3954f07254/image18.png" alt="Resetting MFA for a user in Okta" title="Resetting MFA for a user in Okta" /></p>
<p><em>Image 16: Resetting MFA for a user in Okta</em></p>
<p>Once complete, logs will be ingested shortly into the Elastic Stack, and the Detection Engine will run the rule’s query against datastreams whose patterns match <code>logs-okta*</code>. If all goes as expected, an alert should be available via the Security &gt; Alerts page in the Elastic stack.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd36edbc60375ef59/6a7d835d498caf762d01eeaa/image1.png" alt="Alert page flyout for triggered OOB Okta detection rule" title="Alert page flyout for triggered OOB Okta detection rule" /></p>
<p><em>Image 17: Alert page flyout for triggered OOB Okta detection rule</em></p>
<h2 id="letstriggeracustomrule">Let’s trigger a custom rule</h2>
<p>It is expected that not all OOTB Okta rules may be right for your environment or detection lab. As a result, you may want to create custom detection rules for data from the Okta integration.  Allow me to demonstrate how you would do this.</p>
<p>Let’s assume we have a use case where we want to identify when a unique user ID (Okta Actor ID) has an established session from two separate devices, indicating a potential web session hijack.</p>
<p>For this, we will rely on Elastic’s piped query language, <a href="https://www.elastic.co/blog/getting-started-elasticsearch-query-language">ES|QL</a>. We can start by navigating to Security &gt; Detection Rules (SIEM) &gt; Create new rules. We can then select ES|QL as the rule type.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt04a75e2718e2354d/6a7d836096b5a63214878677/image2.png" alt="Create new rule Kibana page in Elastic security solution" title="Create new rule Kibana page in Elastic security solution" /></p>
<p><em>Image 18: Create new rule Kibana page in Elastic security solution</em></p>
<p>To re-create Okta system logs for this event, we would log in to Okta with the same account from multiple devices relatively quickly. For replication, I have done so via macOS and Windows endpoints, as well as my mobile phone, for variety.</p>
<p>The following custom ES|QL query would identify this activity, which we can confirm via Discover in the Elastic Stack before adding it to our new rule.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc89003893947647f/6a7d8363de2315535dfd4e85/image6.png" alt="Testing ES|QL query in Elastic Discover prior to rule implementation" title="Testing ES|QL query in Elastic Discover prior to rule implementation" /></p>
<p><em>Image 19: Testing ES|QL query in Elastic Discover prior to rule implementation</em></p>
<p>Now that we have adjusted and tested our query and are happy with the results, we can set it as the query for our new rule.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte26a358a6632e01a/6a7d836686c8d9ff279863d0/image21.png" alt="Creating new custom detection rule with ES|QL query logic" title="Creating new custom detection rule with ES|QL query logic" /></p>
<p><em>Image 20: Creating new custom detection rule with ES|QL query logic</em></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta5e7e63e99dc1672/6a7d83691967ea7e2232d8e0/image8.png" alt="Enabled custom detection rule with ES|QL query for Okta threat" title="Enabled custom detection rule with ES|QL query for Okta threat" /></p>
<p><em>Image 21: Enabled custom detection rule with ES|QL query for Okta threat</em></p>
<p>Now that our rule has been created, tested, and enabled, let’s attempt to fire an alert by replicating this activity. For this, we simply log into our Okta admin console from the same device with multiple user accounts.</p>
<p>As we can see, we now have an alert for this custom rule!</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltadb554ae41666c7d/6a7d836c33fa8abe6b1ff9b4/image4.png" alt="Triggered alert for events matching custom detection rule" title="Triggered alert for events matching custom detection rule" /></p>
<p><em>Image 22: Triggered alert for events matching custom detection rule</em></p>
<h2 id="bonussynchronizeactivedirectoryad">Bonus: synchronize Active Directory (AD)</h2>
<p>As discussed in our <a href="https://www.elastic.co/security-labs/starter-guide-to-understanding-okta">previous Okta installation</a>, a core service offering in Okta is to synchronize with third-party IAM directory services such as AD, Google Workspace, and others. Doing so in your lab can enable further threat detection capabilities as cross-correlation between Windows logs and Okta for users would be possible. For this article, we will step through synchronizing with AD on a local Windows Server. Note - We recommend deploying a Windows Elastic Agent to your Windows Server and setting up the <a href="https://docs.elastic.co/en/integrations/windows">Windows</a> and <a href="https://www.elastic.co/guide/en/security/current/install-endpoint.html">Elastic Defend</a> integrations for additional log ingestion.</p>
<ol>
<li><a href="https://www.linkedin.com/pulse/how-install-active-directory-domain-services-windows-server-2019-/">Setup</a> your Windows Server (we are using WinServer 2019)</li>
<li>Deploy the Okta AD agent from your Okta admin console
a. Directory &gt; Directory Integrations
b. Add Directory &gt; Add Active Directory</li>
<li>Walk through guided steps to install Okta AD agent on Windows Server
a. Execution of the Okta Agent executable will require a setup on the Windows Server side as well</li>
<li>Confirm Okta AD agent was successfully deployed</li>
<li>Synchronize AD with Okta
a. Directory &gt; Directory Integrations
b. Select new AD integration
c. elect “Import Now”
Choose incremental or full import</li>
<li>Select which users and groups to import and import them</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5a516fdbb058074b/6a7d836f3ce8e2a46bcf26a6/image10.png" alt="Successful Okta agent deployment and synchronization with AD" title="Successful Okta agent deployment and synchronization with AD" /></p>
<p><em>Image 23: Successful Okta agent deployment and synchronization with AD</em></p>
<p>Once finished, under Directory in the Okta admin console, you should see people and groups that have been successfully imported. From here, you can emulate attack scenarios such as stolen login credentials locally (Windows host) being used to reset MFA in Okta.</p>
<h2 id="additionalconsiderations">Additional considerations</h2>
<p>While this is a basic setup of not only the Elastic Stack, Okta integration, and more for a threat research lab, there are additional considerations for our setup that are dependent on our research goals. While we won't dive into specifics nor exhaust possible scenarios, below is a list of considerations for your lab to accurately emulate an enterprise environment and/or adversary playbooks:</p>
<ul>
<li>Is Okta my IdP source of truth? If not, set up a third party such as Azure AD (AAD) or Google Workspace and synchronize directory services.</li>
<li>Will I simulate adversary behavior - for example, SAMLjacking? If so, what third-party integrations do I need that leverage SAML for authentication?</li>
<li>Do I want to research tenant poisoning? If so, should I set up a multi-tenant architecture with Okta?</li>
<li>Do I need separate software, such as VPNs or proxies, to emulate attribution evasion when attempting to bypass MFA?</li>
<li>What other tools, such as EvilGinx, let me attempt phishing playbooks, and what is the required set up in Okta for these exercises?</li>
<li>How should I capture authorization codes during OAuth workflows, and how can I replay an exchange request for an access token?</li>
<li>For password spraying or credential stuffing, which third-party applications should I integrate, and how many should suffice for accurate detection logic?</li>
<li>How might I explore lax access policies for user profiles?</li>
</ul>
<h2 id="takeaways">Takeaways</h2>
<p>In this guide, we've successfully navigated the setup of an Okta threat detection lab using the Elastic Stack, highlighting the importance of safeguarding SaaS platforms like Okta. Our journey included deploying the Elastic Stack, integrating and testing Okta system logs, and implementing both pre-built and custom detection rules.</p>
<p>The key takeaway is the Elastic Stack's versatility in threat detection, accommodating various scenarios, and enhancing cybersecurity capabilities. This walkthrough demonstrates that effective threat management in Okta environments is both achievable and essential.</p>
<p>As we wrap up, remember that the true value of this exercise lies in its practical application. By establishing your own detection lab, you're not only reinforcing your security posture but also contributing to the broader cybersecurity community. Stay tuned for additional threat research content surrounding SaaS and Okta, where we'll explore common adversary attacks against Okta environments and detection strategies.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/monitoring-okta-threats-with-elastic-security</link>
    <guid isPermaLink="false">monitoring-okta-threats-with-elastic-security</guid>
    <category><![CDATA[Cloud Security]]></category>
    <dc:creator><![CDATA[Terrance DeJesus]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt131564b34c51b8a6/6a7d83724c4bfbb238cca881/photo-edited-03.png" length="0" type="image/png"/>
    <pubDate>Fri, 23 Feb 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Starter guide to understanding Okta]]></title>
    <description><![CDATA[This article delves into Okta's architecture and services, laying a solid foundation for threat research and detection engineering. Essential reading for those aiming to master threat hunting and detection in Okta environments.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>The evolution of digital authentication from simple, unencrypted credentials to today’s advanced methods underscores the importance of data security. As organizations adapt to hybrid deployments and integral application access is no longer within the perimeter of a network, inherited authentication complexity and risk ensue. The adoption of standard authentication protocols and advanced workflows is mandatory to not only reduce risk but also maintain operational stability amongst users who require access to various applications. Okta provides solutions to these inherent industry problems with its comprehensive SaaS platform for Identity and Access Management (IAM) services.</p>
<p>We will examine Okta's services and solutions in the context of Software-as-a-Service (SaaS) platforms and against the backdrop of the broader threat landscape. We'll explore historical and potential vulnerabilities to understand their origins and impacts. This article will provide insights into:</p>
<ul>
<li>Universal Directory (UD)</li>
<li>Data Model</li>
<li>API Access Management</li>
<li>Access Policies</li>
<li>Session Management</li>
<li>Tenants</li>
<li>Authorization Workflows</li>
<li>Authentication Workflows.</li>
</ul>
<p>With a deeper understanding of Okta, security practitioners may leverage this knowledge to accurately assess attack surfaces where Okta is deployed.</p>
<h2 id="oktasofferings">Okta's offerings</h2>
<h3 id="overviewofcoreservices">Overview of core services</h3>
<p>In this introduction, we delve into the core services provided by Okta. Primarily, Okta is a SaaS platform, specializing in scalable Identity and Access Management (IAM) solutions. Central to its offerings are technologies such as Single Sign-On (SSO), Multi-Factor Authentication (MFA), and support for complex multi-tenant architectures. Okta also boasts a robust suite of RESTful APIs, facilitating seamless Create, Read, Update, and Delete (CRUD) operations.</p>
<p>At the heart of Okta’s IAM solutions lie users, groups, and policies. The platform provides comprehensive lifecycle management and a UD, allowing seamless IAM across hybrid environments encompassing applications, devices, and more. This includes synchronization capabilities with external directories like LDAP or Active Directory (AD), ensuring a unified identity management system.</p>
<p>A key aspect of Okta's service is its dual role as both a Service Provider (SP) and an Identity Provider (IdP). This dual functionality enables Okta to facilitate secure and seamless authentication via its <a href="https://help.okta.com/oie/en-us/content/topics/identity-engine/oie-index.htm">Identity Engine</a>, and robust authorization using standard protocols such as OAuth, while also supporting authentication protocols such as Security Assertion Markup Language (SAML) and OpenID Connect (OIDC).</p>
<p>For customers, Okta offers valuable tools for security and compliance. <a href="https://developer.okta.com/docs/api/openapi/okta-management/management/tag/SystemLog/">System logs</a>, environment-based events that are stored and retrievable via API, provide insights into user activities and organizational events. These logs are crucial for Security Information and Event Management (SIEM) systems, aiding in the detection of anomalies and potential threats.</p>
<p>Additionally, Okta's <a href="https://help.okta.com/en-us/content/topics/security/threat-insight/about-threatinsight.htm">ThreatInsight</a> feature stands out as a proactive security measure. It aggregates and analyzes system logs, dynamically identifying and responding to potential threats. This includes recognizing patterns indicative of malicious activities such as password spraying, credential stuffing, and detecting suspicious IP addresses. These features collectively enhance the security posture of organizations, fortifying them against a wide array of cyber threats.</p>
<h3 id="integrationcapabilities">Integration capabilities</h3>
<p>Aside from some of the many offerings, Okta is very developer-friendly with various other SaaS solutions and applications. Out of the box, Okta contains an <a href="https://www.okta.com/integrations/">integration network</a> that allows seamless integration with other applications such as Slack, Google Workspace, Office 365, GitHub, and many more.</p>
<p>Okta’s <a href="https://developer.okta.com/docs/reference/core-okta-api/">RESTful APIs</a> follow the System for Cross-domain Identity Management (<a href="https://datatracker.ietf.org/doc/html/rfc7644">SCIM</a>) protocol. This allows for straightforward Create, Read, Update, and Delete (CRUD) operations on users and groups by applications or developers, but also enables standardization within the SaaS ecosystem. SCIM is a pivotal component of Okta's scalability. As businesses expand, the need to integrate an increasing number of users, groups, and access controls across various SaaS platforms grows. SCIM addresses this challenge by standardizing how user identity data is communicated between these platforms. This standardization facilitates the process of user management, especially in synchronizing user information across different systems.</p>
<p>Okta’s object management regarding APIs is focused on several domains listed below:</p>
<ul>
<li>Apps API - Manage applications and their association with users and groups.</li>
<li>Users API - CRUD operations on users.</li>
<li>Sessions API - Creates and manages user’s authentication sessions.</li>
<li>Policy API - Creates and manages settings such as a user’s session lifetime.</li>
<li>Factors API - Enroll, manage, and verify factors for MFA.</li>
<li>Devices API - Manage device identity and lifecycles.</li>
</ul>
<p>When integrations are added to an Okta organization, authentication policies, both fine-grained and global, can be set up for access control based on end-user attributes stored within the user’s Okta profile.</p>
<h2 id="universaldirectory">Universal directory</h2>
<p>At the core of Okta’s user, group, policy, and device management is the <a href="https://www.okta.com/products/universal-directory">UD</a>. This is a single pane view of all assets, whether sourced from Okta, an integration, or a secondary directory service such as AD.</p>
<p>The UD is technically an Okta-managed, centralized, and cloud-based repository for all user, group, device, and policy profiles. Okta is either the source of truth regarding IAM or synchronizes with other federation services and identity providers such as AD or Google Workspace. The UD is accessible behind Okta’s core APIs for CRUD operations and used in conjunction with their single sign-on (SSO) platform, thus providing authentication and authorization to linked integrations or the admin console itself. Everything from user management to streamlined password management is enabled by the UD.</p>
<p>In conclusion, the UD classifies as a directory-as-a-service (<a href="https://jumpcloud.com/daas-glossary/directory-as-a-service-daas">DaaS</a>), similar to AWS directory service, Microsoft’s Entra ID and many more.</p>
<h3 id="customizationandmanagement">Customization and management</h3>
<p>Adding a bit more depth to the UD, profile customization is accessible. This enables an organization to store a record of information regarding users and groups that contain specific attributes. Base attributes are assigned by Okta, but custom attributes can be added as well between user, group, and app <a href="https://developer.okta.com/docs/concepts/user-profiles/">user profiles</a>. Attribute mappings are important for synchronization and data exchanges between integrations and other directory services. For example, the AD attribute givenName can be mapped specifically to FirstName and LastName in Okta. Aside from synchronization, this is important for other Okta-related features such as <a href="https://developer.okta.com/docs/concepts/inline-hooks/">inline hooks</a>, directory rules and actions, and more.</p>
<p>Additionally, this enables rich SAML assertions and <a href="https://auth0.com/docs/authenticate/protocols/ws-fed-protocol">WS-Federation</a> claims where applications can utilize this information to create rich user accounts, update accounts, or create complex authorization and authentication decisions.</p>
<p>There are additional <a href="https://help.okta.com/en-us/content/topics/provisioning/lcm/con-okta-prov.htm">autonomous provisioning and deprovisioning</a> options available as well with the UD and internal profiles, important for scalability and administrative tasks such as controlling which user types can access which applications, thus enabling more traditional role-based access control (RBAC) policies.</p>
<h3 id="integrationwithexternaldirectories">Integration with external directories</h3>
<p>As mentioned previously, the Okta <a href="https://www.okta.com/resources/whitepaper/ad-architecture/">Directory Integration</a> can synchronize with external directories such as LDAP, AD, Google Workspace and others. For cloud-based DaaS platforms, Okta leverages RESTful APIs and the SCIM protocol to perform data exchanges and more. For on-premise environments, Okta has an AD <a href="https://help.okta.com/en-us/content/topics/directory/ad-agent-new-integration.htm">endpoint agent</a> that can be deployed and thus pulls information from directory services and ships it back to the UD. </p>
<p>Alternatively, Desktop SSO (DSSO) provides an <a href="https://help.okta.com/en-us/content/topics/directory/configuring_agentless_sso.htm">agentless</a> option as well. This supplies flexibility to cloud, on-premise or hybrid based environments all while continuing scalability and direct integration with 3rd-party applications. Architecturally, this solves the many pitfalls of LAN-based environments, where applications are served to domain users behind a firewall. From a security perspective, credentials and profiles are then synchronized from all application directories into a single “source-of-truth”: Okta. It is much more approachable to audit a single directory as well in an instance where, for example, a disgruntled employee is no longer employed, and thus access across various applications must be deactivated. Single Log-Off (<a href="https://help.okta.com/en-us/content/topics/apps/apps_single_logout.htm">SLO</a>) is thus available for such situations thanks to these external directory integration capabilities.</p>
<p>Finally, we must not overlook the amount of maintenance this potentially reduces for organizations who may not have the resources to manage SAML, OAuth, and SCIM communications between RESTful APIs or compatibility issues between integrations as Okta manages this for them.</p>
<p>Additional solutions and examples of Okta providers with external directory support for AD can be found <a href="https://www.okta.com/resources/whitepaper/ad-architecture/">here</a>.</p>
<h2 id="datamodel">Data model</h2>
<p>As we traverse through the Okta landscape, understanding Okta’s <a href="https://developer.okta.com/docs/concepts/okta-data-model/">data models</a> is important to security practitioners who may be tasked with threat hunting, detection logic, and more.</p>
<h3 id="structureanddesign">Structure and design</h3>
<p>When Okta is first established for an organization, it inherits its own “space” where applications, directories, user profiles, authentication policies, and more are housed. A top-level directory resource is given as a “base” for your organization where entities can be sourced from Okta or externally (LDAP, AAD, Google Workspace, etc.).</p>
<p>Okta users are higher-privileged users who typically leverage the Okta <a href="https://help.okta.com/en-us/content/topics/dashboard/dashboard.htm">admin console</a> and perform administrative tasks, while end users are those who may rely on Okta for SSO, access to applications and more.</p>
<p>By default, entities in Okta are referred to as resources. Each resource has a combined set of default and custom attributes as discussed before. Links then describe relationships or actions that are acceptable for a resource, such as a deactivation link. This information is then aggregated into a profile which is then accessible from within the UD. Groups are made up of users more as a label to a specific set of users.</p>
<p>Applications hold information about policies for access related to users and groups, as well as how to communicate with each integrated application. Together, the data stored about application access and related users is stored as an <a href="https://support.okta.com/help/s/article/The-Okta-User-Profile-And-Application-User-Profile?language=en_US">AppUser</a> and if mapping is done correctly between directories, enables access for end users.</p>
<p>A policy contains a set of conditions and rules that affect how an organization behaves with applications and users. Policies are all-encompassing in Okta, meaning they are used for making decisions and completing actions such as - what is required for a password reset or how to enroll in MFA. These rules can be expressed using the Okta Expression Language (<a href="https://developer.okta.com/docs/reference/okta-expression-language-in-identity-engine/">OEL</a>).</p>
<p>Dedicated <a href="https://developer.okta.com/docs/concepts/auth-servers/">authorization servers</a> are used per organization to provide authorization codes and tokens for access to applications by API or resources. Here, authorization and authentication protocols such as OAuth, OIDC, and SAML are vital for workflows. These authorization servers are also responsible for communication with third-party IdPs such as Google Workspace. End users who may seek access to applications are entangled in communication between authorization servers and SPs as codes and tokens are exchanged rapidly to confirm authorization and authentication.</p>
<p>Altogether, this structure and design support scalability, customization, and seamless integration.</p>
<h2 id="apiaccessmanagement">API access management</h2>
<p>API access management is not only important for end users, administrators, and developers but also for integration-to-integration communication. Remember that at the forefront of Okta are its various RESTful <a href="https://developer.okta.com/docs/reference/core-okta-api/#manage-okta-objects">API endpoints</a>.</p>
<p>While we won’t dive deep into the design principles and object management of Okta’s APIs, we will attempt to discuss core concepts that are important for understanding attack surfaces later in this blog series.</p>
<h3 id="apisecurity">API Security</h3>
<h4 id="oauth20andoidcimplementation">OAuth 2.0 and OIDC implementation</h4>
<p>Understanding the core protocols of <a href="https://auth0.com/docs/authenticate/protocols/oauth">OAuth</a> and <a href="https://auth0.com/docs/authenticate/protocols/openid-connect-protocol">OIDC</a> is key before exploring various authorization and authentication workflows. OAuth, an open standard for delegated authorization in RESTful APIs, operates over HTTPS, enabling secure, delegated access using access tokens instead of credentials. These tokens, cryptographically signed by the Identity Provider (IdP), establish a trust relationship, allowing applications to grant user access. The typical OAuth workflow involves user access requests, user authentication, proof-of-authorization code delivery, and token issuance for API requests. Access tokens are verified with the IdP to determine access scope.</p>
<p>OIDC (<a href="https://developer.okta.com/docs/reference/api/oidc/#endpoints">API endpoints</a>) builds upon OAuth for authentication, introducing identity-focused scopes and an ID token in addition to the access token. This token, a JSON Web Token (<a href="https://developer.okta.com/blog/2020/12/21/beginners-guide-to-jwt">JWT</a>), contains identity information and a signature, crucial for SSO functionality and user authentication. Okta, as a certified OIDC provider, leverages these endpoints, especially when acting as an authorization server for Service Providers (SPs).</p>
<p>Demonstrating Proof-of-Possession (<a href="https://developer.okta.com/docs/guides/dpop/main/#oauth-2-0-dpop-jwt-flow">DPoP</a>) is crucial in this context, enhancing security by preventing misuse of stolen tokens through an application-level mechanism. It involves a public/private key pair where the public key, embedded in a JWT header, is sent to the authorization server. The server binds this public key to the access token, ensuring secure communication primarily between the user’s browser and the IdP or SP.</p>
<p><a href="https://developer.okta.com/docs/guides/tokens/">Tokens</a> and API keys in Okta’s API Access Management play a vital role, acting as digital credentials post-user authentication. They are transmitted securely via HTTPS and have a limited lifespan, contributing to a scalable, stateless architecture.</p>
<p>Lastly, understanding End-to-End Encryption (E2EE) is essential. E2EE ensures that data is encrypted at its origin and decrypted only by the intended recipient, maintaining security and privacy across the ecosystem. This encryption, using asymmetric cryptography, is a default feature within Okta’s APIs, safeguarding data across applications, browsers, IdPs, and SPs.</p>
<h3 id="restfulapiandcrud">RESTful API and CRUD</h3>
<p>Okta's RESTful API adheres to a standardized interface design, ensuring uniformity and predictability across all interactions. This design philosophy facilitates CRUD (Create, Read, Update, Delete) operations, making it intuitive for developers to work with Okta's API. Each <a href="https://developer.okta.com/docs/reference/core-okta-api/">API endpoint</a> corresponds to standard HTTP methods — POST for creation, GET for reading, PUT for updating, and DELETE for removing resources. This alignment with HTTP standards simplifies integration and reduces the learning curve for new developers.</p>
<p>A key feature of Okta providing a RESTful API is its statelessness — each request from client to server must contain all the information needed to understand and complete the request, independent of any previous requests. This approach enhances scalability, as it allows the server to quickly free resources and not retain session information between requests. The stateless nature of the API facilitates easier load balancing and redundancy, essential for maintaining high availability and performance even as demand scales.</p>
<h3 id="scim">SCIM</h3>
<p>SCIM (System for Cross-domain Identity Management) is an open standard that automates user identity management across various cloud-based applications and services. Integral to Okta's API Access Management, SCIM ensures seamless, secure user data exchange between Okta and external systems. It standardizes identity information, which is essential for organizations using multiple applications, reducing complexity and manual error risks.</p>
<p>Within Okta, SCIM’s role extends to comprehensive user and group management, handling essential attributes like usernames, emails, and group memberships. These are key for access control and authorization. Okta’s SCIM implementation is customizable, accommodating the diverse identity management needs of different systems. This adaptability streamlines identity management processes, making them more automated, efficient, and reliable - crucial for effective API access management.</p>
<p>More information on SCIM can be found in <a href="https://datatracker.ietf.org/doc/html/rfc7644">RFC 7644</a> or by <a href="https://developer.okta.com/docs/concepts/scim/#how-does-scim-work">Okta</a>.</p>
<h2 id="accesspolicies">Access policies</h2>
<p>Okta's <a href="https://developer.okta.com/docs/concepts/policies/">access policies</a> play a critical role in managing access to applications and APIs. They can be customized based on user/group membership, device, location, or time, and can enforce extra authentication steps for sensitive applications. These policies, stored as JSON in Okta, allow for:</p>
<ul>
<li>Creating complex authorization rules.</li>
<li>Specifying additional authentication levels for Okta applications.</li>
<li>Managing user access and modifying access token scopes with inline hooks.</li>
</ul>
<p>Key Policy Types in Okta include:</p>
<ul>
<li><p><em>Sign-On Policies</em>: Control app access with IF/THEN rules based on context, like IP address.</p></li>
<li><p><em>Global Session Policy</em>: Manages access to Okta, including factor challenges and session duration.</p></li>
<li><p><em>Authentication Policy</em>: Sets extra authentication requirements for each application.</p></li>
<li><p><em>Password Policy</em>: Defines password requirements and recovery operations.</p></li>
<li><p><em>Authenticator Enrollment Policy</em>: Governs multifactor authentication method enrollment.</p>
<p>Policy effectiveness hinges on their sequential evaluation, applying configurations when specified conditions are met. The evaluation varies between the AuthN and Identity Engine pipelines, with the latter considering both global session and specific authentication policies.</p></li>
</ul>
<p>Additionally, <a href="https://help.okta.com/en-us/content/topics/security/network/network-zones.htm">Network Zones</a> in Okta enhances access control by managing it based on user connection sources. These zones, allowing for configurations based on IP addresses and geolocations, integrate with access policies to enforce varied authentication requirements based on network origin. This integration bolsters security and aids in monitoring and threat assessment.</p>
<h2 id="sessionmanagement">Session management</h2>
<p>In web-based interactions involving Identity Providers (IdPs) like Okta and Service Providers (SPs), the concept of a session is central to the user experience and security framework. A session is typically initiated when an end-user starts an interaction with an IdP or SP via a web browser, whether this interaction is intentional or inadvertent.</p>
<p>Technically, a session represents a state of interaction between the user and the web service. Unlike a single request-response communication, a session persists over time, maintaining the user's state and context across multiple interactions. This persistence is crucial, as it allows the user to interact with web services without needing to authenticate for each action or request after the initial login.</p>
<p>A session can hold a variety of important data, which is essential for maintaining the state and context of the user's interactions. This includes, but is not limited to:</p>
<p><em>Cookies</em>: These are used to store session identifiers and other user-specific information, allowing the web service to recognize the user across different requests.</p>
<p><em>Tokens</em>: Including access, refresh, and ID tokens, these are critical for authenticating and authorizing the user, and for maintaining the security of their interactions with the web service.</p>
<p><em>User Preferences and Settings</em>: Customizations or preferences set by the user during their interaction.</p>
<p><em>Session Expiration Data</em>: Information about when the session will expire or needs to be refreshed. This is vital for security, ensuring that sessions don’t remain active indefinitely, which could pose a security risk.</p>
<p>The management of sessions, particularly their creation, maintenance, and timely expiration is a crucial aspect of web-based services. Effective session management ensures a balance between user convenience — by reducing the need for repeated logins — and security — by minimizing the risk of unauthorized access through abandoned or excessively long-lived sessions. In the interactions between the end-user, IdP, and SP, sessions facilitate a seamless yet secure flow of requests and responses, underpinning the overall security and usability of the service.</p>
<h3 id="sessioninitializationandauthentication">Session initialization and authentication:</h3>
<p>Okta manages <a href="https://developer.okta.com/docs/concepts/session/">user sessions</a> beginning with the IdP session, which is established when a user successfully authenticates using their credentials, and potentially multi-factor authentication (MFA). This IdP session is key to accessing various applications integrated into an organization's Okta environment. For instance, an HTTP POST request to Okta's <code>/api/v1/authn</code> endpoint initiates this session by validating the user's credentials. In addition, the <a href="https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Session/">Sessions endpoint API</a> can help facilitate creation and management at <code>/api/v1/sessions</code>.</p>
<p>Okta primarily uses cookies for session management, specifically in the context of identity provider (IdP) sessions. These cookies are crucial for maintaining the session state and user context across HTTP requests within the Okta environment. A typical session cookie retrieval for the end-user’s browser goes as follows:</p>
<ol>
<li>IdP or SP-initiated application access request</li>
<li>Authentication request either via OIDC or SAML</li>
<li>After successful credential validation, a session token is returned</li>
<li>Redirection to OIDC endpoint, session redirection, or application embed link for session cookie</li>
</ol>
<p>As detailed, when a user successfully authenticates, Okta ultimately sets a session cookie in the user’s browser. This cookie is then used to track the user session, allowing for seamless interaction with various applications without the need for re-authentication.</p>
<h3 id="tokensvscookies">Tokens vs cookies:</h3>
<p>While Okta utilizes tokens like ID and access tokens for API access and authorization, these tokens serve a different purpose from session cookies. Tokens are typically used in API interactions and are not responsible for maintaining the user’s session state. In contrast, session cookies are specifically designed for maintaining session continuity within the web browser, making them essential for web-based SSO and session management within Okta.</p>
<p>Session tokens are similar to client-side secrets, just like authorization codes during authorization requests. These secrets, along with the correct requests to specific API endpoints can allow an end-user, or adversary, to obtain a session cookie or access token which can then be used to make authenticated/authorized requests on behalf of the user. This should warrant increased security measures for session management and monitoring.</p>
<h3 id="singlesignonsso">Single sign-on (SSO):</h3>
<p><a href="https://www.okta.com/blog/2021/02/single-sign-on-sso/">SSO</a> is a critical feature in Okta's session management, allowing users to access multiple applications with a single set of credentials. This is achieved through protocols like SAML and OIDC, where an HTTP(S) request to the SAML endpoint, for instance, facilitates user authentication and grants access across different applications without the need for repeated logins.</p>
<p>In Single Sign-On (SSO) scenarios, Okta’s session cookies play a vital role. Once a user is authenticated and a session is established, the same session cookie facilitates access to multiple applications within the SSO framework by bundled with every service provider request. This eliminates the need for the user to log in separately to each application, streamlining the user experience.</p>
<h3 id="sessiontermination">Session termination:</h3>
<p>Terminating a session in Okta can occur due to expiration. This can also occur from a user, SP, or IdP-initiated sign-out. An HTTP GET request to Okta's <code>/api/v1/sessions/me</code> endpoint can be used to terminate the user’s session. In the case of SSO, this termination can trigger a single logout (SLO), ending sessions across all accessed applications.</p>
<h3 id="applicationsessionsandadditionalcontrols">Application sessions and additional controls:</h3>
<p>Application sessions are specific to the application a user accesses post-authentication with the IdP. Okta allows fine-grained control over these sessions, including different expiration policies for privileged versus non-privileged applications. Additionally, administrators can implement policies for single logout (<a href="https://support.okta.com/help/s/article/What-SLO-does-and-doesnt-do?language=en_US">SLO</a>) or local logout to further manage session lifecycles.</p>
<p>Understanding the mechanics of session initiation, management, and termination, as well as the role of tokens and cookies, is foundational for exploring deeper security topics. This knowledge is crucial when delving into areas like attack analysis and session hijacking, which will be discussed in later parts of this blog series.</p>
<p>More information on sessions can be found in <a href="https://developer.okta.com/docs/concepts/session/#application-session">Session management with Okta</a> or <a href="https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Session/">Sessions for Developers</a>.</p>
<h2 id="tenants">Tenants</h2>
<p>In the SaaS realm, a <a href="https://developer.okta.com/docs/concepts/multi-tenancy/">tenant</a> is a distinct instance of software and infrastructure serving a specific user group. In Okta's <a href="https://developer.okta.com/docs/concepts/multi-tenancy/">multi-tenant</a> platform, this concept is key for configuring access control. Tenants can represent various groups, from internal employees to external contractors, each requiring unique access to applications. This is managed through Okta, serving as the IdP.</p>
<p>Tenants are versatile within Okta: they can be tailored based on security policies, user groups, roles, and profiles, allowing them to operate independently within the organization. This independence is crucial in multi-tenant environments, where distinct tenants are segregated based on factors like roles, data privacy, and regulatory requirements. Such setups are common in Okta, enabling users to manage diverse access needs efficiently.</p>
<p>In multi-org environments, Okta facilitates tenants across separate organizations through its UD. The configuration of each tenant is influenced by various factors including cost, performance, and data residency, with user types and profiles forming the basis of tenant setup. Additionally, features like delegated admin support and DNS customization for post-sign-in redirects are instrumental in managing tenant access.</p>
<p>Understanding the nuances of tenant configuration in Okta is vital, not only for effective administration but also for comprehending potential security challenges, such as the risk of <a href="https://github.com/pushsecurity/saas-attacks/blob/main/techniques/poisoned_tenants/description.md">poisoned tenants</a>.</p>
<h2 id="authorizationworkflow">Authorization workflow</h2>
<p>As we discussed earlier, Okta - being an IdP - provides an authorization server as part of its services. It is critical to understand the authorization workflow that happens on the front and back-end channels. For this discussion and examples, we will use the client (end-user), authorization server (Okta), and SP (application server) as the actors involved.</p>
<h3 id="oauth20andoidcprotocols">OAuth 2.0 and OIDC protocols</h3>
<h4 id="highleveloverviewofoauth">High-level overview of OAuth</h4>
<p>OAuth 2.0, defined in <a href="https://datatracker.ietf.org/doc/html/rfc6749">RFC 6749</a>, is a protocol for authorization. It enables third-party applications to gain limited access approved by the end-user or resource owner. Operating over HTTPS, it grants access tokens to authorize users, devices, APIs, servers, and applications.</p>
<p>Key OAuth terminology:</p>
<p><a href="https://www.oauth.com/oauth2-servers/scope/defining-scopes/">Scopes</a>: Define the permissions granted within an access token. They represent session permissions for each interaction with a resource server.</p>
<p>Consent: A process where end users or clients agree or disagree with the permissions (scopes) requested by a client application. For example, a consent screen in Google Workspace.</p>
<p><a href="http://Tokens">Tokens</a>: Includes access tokens for resource access and refresh tokens for obtaining new access tokens without re-authorizing.</p>
<p><a href="https://auth0.com/docs/get-started/applications/confidential-and-public-applications">Grants</a>: Data sent to the authorization server to receive an access token, like an authorization code granted post-authentication.</p>
<p><a href="https://auth0.com/docs/get-started/applications/confidential-and-public-applications">Clients</a>: In OAuth, clients are either 'confidential', able to securely store credentials, or 'public', which cannot.</p>
<p>Authorization Server: Mints OIDC and OAuth tokens and applies access policies, each with a unique URI and signing key.</p>
<p><a href="https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/#:~:text=The%20user%20authenticates%20with%20their,server%20issues%20an%20authorization%20code.">Authorization Endpoint</a>: An API endpoint (/oauth/authorize) for user interaction and authorization.</p>
<p><a href="https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/#:~:text=The%20user%20authenticates%20with%20their,server%20issues%20an%20authorization%20code.">Token Endpoint</a>: An API endpoint (/oauth/token) for clients to obtain access or refresh tokens, typically requiring a grant type like authorization code.</p>
<p>Resource Server (or Service Provider, SP): Provides services to authenticated users, requiring an access token.</p>
<p>Front-end Channel: Communication between the user’s browser and the authorization or resource server.</p>
<p>Back-end Channel: Machine-to-machine communication, such as between resource and authorization servers.</p>
<p>This streamlined overview covers the essentials of OAuth in the Okta ecosystem, focusing on its function, key terms, and components.</p>
<h4 id="highleveloverviewofoidc">High-level overview of OIDC</h4>
<p>At the beginning of this blog, we also discussed how <a href="https://openid.net/specs/openid-connect-core-1_0.html">OIDC</a> is an identity authentication protocol that sits on top of the OAuth authorization framework. While OAuth provides authorization, it has no current mechanism for authentication, thus where OIDC protocol comes in handy. The identity of the authenticated user is often called the resource owner.</p>
<p>The OIDC connect flow looks similar to the OAuth flow, however during the initial HTTPS request, scope=openid is added to be used so that not only an access token is returned from the authorization server but an ID token as well.</p>
<p>The ID token is formatted as a JSON Web Token (JWT) so that the client can extract information about the identity. This is unlike the access token, which the client passes to the resource server every time access is required. Data such as expiration, issuer, signature, email, and more can be found inside the JWT - these are also known as claims.</p>
<h3 id="authorizationcodeflow">Authorization code flow</h3>
<h4 id="step1initialauthorizationrequest">Step 1 - Initial authorization request:</h4>
<p>The authorization code flow is initiated when the client sends an HTTP GET request to Okta’s authorization endpoint. This request is crucial in establishing the initial part of the OAuth 2.0 authorization framework.</p>
<p>Here’s a breakdown of the request components:</p>
<ul>
<li>Endpoint: The request is directed to <code>/oauth2/default/v1/authorize</code>, which is Okta’s authorization endpoint</li>
<li>Parameters:</li>
<li><code>response_type=code</code>: This parameter specified that the application is initiating an authorization code grant type flow.</li>
<li><code>client_id</code>: The unique identifier for the client application registered with Okta.</li>
<li><code>redirect_uri</code>: The URL to which Okta will send the authorization code.</li>
<li><code>scope</code>: Defines the level of access the application is requesting.</li>
</ul>
<p>Example Request:</p>
<pre><code>GET /oauth2/default/v1/authorize?response_type=code \ 
&amp;client_id=CLIENT_ID&amp;redirect_uri=REDIRECT_URI&amp;scope=SCOPE
</code></pre>
<h4 id="step2userauthenticationandconsent">Step 2 - User authentication and consent:</h4>
<p>Once the request is made, the user is prompted to authenticate with Okta and give consent for the requested scopes. This step is fundamental for user verification and to ensure that the user is informed about the type of access being granted to the application.</p>
<h4 id="step3authorizationcodereception">Step 3 - Authorization code reception:</h4>
<p>Post authentication and consent, Okta responds to the client with an authorization code. This code is short-lived and is exchanged for a more permanent secret to make further requests - an access token.</p>
<p>Example token exchange request:</p>
<pre><code>POST /oauth2/default/v1/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&amp;
code=AUTHORIZATION_CODE&amp;
redirect_uri=REDIRECT_URI&amp;
client_id=CLIENT_ID&amp;
client_secret=CLIENT_SECRET
</code></pre>
<h4 id="step4redirecturisandclientauthentication">Step 4 - Redirect URIs and client authentication</h4>
<p>Redirect URIs play a pivotal role in the security of the OAuth 2.0 flow. They are pre-registered URLs to which Okta sends the authorization code. The integrity of these URIs is paramount, as they ensure that the response is only sent to the authorized client.</p>
<p>The client application is authenticated at the token endpoint, usually by providing the <code>client_id</code> and <code>client_secret</code>. This step is crucial to verify the identity of the client application and prevent unauthorized access.</p>
<h4 id="step5tokenexchange">Step 5 - Token exchange</h4>
<p>In the final step, the client makes an HTTP POST request to Okta’s token endpoint, exchanging the authorization code for an access token. This access token is then used to make API requests on behalf of the user.</p>
<p>The inclusion of client credentials (client ID and client secret) in this request is a critical security measure, ensuring that the token is only issued to the legitimate client. </p>
<h3 id="accesstokensandscopes">Access tokens and scopes</h3>
<p>An <a href="https://www.okta.com/identity-101/access-token/">access token</a> is a compact code carrying extensive data about a user and their permissions. It serves as a digital key, facilitating communication between a server and a user's device. Commonly used in various websites, access tokens enable functionalities like logging in through one website (like Facebook) to access another (like Salesforce).</p>
<h4 id="compositionofanaccesstoken">Composition of an access token:</h4>
<p>An access token typically comprises three distinct parts, each serving a specific purpose:</p>
<ul>
<li><em>Header</em>: This section contains metadata about the token, including the type of token and the algorithm used for encryption.</li>
<li><em>Payload (claims)</em>: The core of the token, includes user-related information, permissions, group memberships, and expiration details. The payload dictates whether a user can access a specific resource, depending on the permissions granted within it. Developers can embed custom data in the payload, allowing for versatile applications, such as a single token granting access to multiple APIs.</li>
<li><em>Signature</em>: A hashed verification segment that confirms the token's authenticity. This makes the token secure and challenging to tamper with or replicate.</li>
</ul>
<p>A common format for access tokens JWT as we previously discussed, which is concise yet securely encodes all necessary information.</p>
<h4 id="scopesandpermissions">Scopes and permissions:</h4>
<p><a href="https://developer.okta.com/docs/api/oauth2/">Scopes</a> in OAuth 2.0 are parameters that define the level and type of access the client requests. Each scope translates into specific permissions granted to the access token. For instance, a scope of email would grant the client application access to the user's email address. The granularity of scopes allows for precise control over what the client can and cannot do with the access token, adhering to the principle of least privilege.</p>
<h4 id="tokenlifespanandrefreshtokens">Token lifespan and refresh tokens:</h4>
<p>Access tokens are inherently short-lived for security reasons, reducing the window of opportunity for token misuse in case of unintended disclosure. Okta allows customization of <a href="https://support.okta.com/help/s/article/What-is-the-lifetime-of-the-JWT-tokens?language=en_US#:~:text=ID%20Token%3A%2060%20minutes,Refresh%20Token%3A%2090%20days">token lifespans</a> to suit different security postures. Once an access token expires, it can no longer be used to access resources.</p>
<p><a href="https://developer.okta.com/docs/guides/refresh-tokens/main/">Refresh tokens</a>, where employed, serve to extend the session without requiring the user to authenticate again. A refresh token can be exchanged for a new access token, thus maintaining the user's access continuity to the application. The use of refresh tokens is pivotal in applications where the user remains logged in for extended periods.</p>
<h4 id="tokenstorage">Token storage:</h4>
<p>Regarding <a href="https://auth0.com/docs/secure/security-guidance/data-security/token-storage">token storage</a>, browser-based applications such as those utilizing services like Okta, are vital secure storage of access tokens is a critical aspect of user session management. These tokens are typically stored using one of several methods: browser in-memory storage, session cookies, or browser local/session storage. In-memory storage, preferred for its strong defense against XSS attacks, holds the token within the JavaScript memory space of the application, although it loses the token upon page refresh or closure. Session cookies offer enhanced security by being inaccessible to JavaScript, thereby reducing XSS vulnerabilities, but require careful implementation to avoid CSRF attacks. Local and session storage options, while convenient, are generally less recommended for sensitive data like access tokens due to their susceptibility to XSS attacks. The choice of storage method will depend on the application where a traditional web page, mobile device, or single-page app is being used.</p>
<h4 id="securityandexpiration">Security and expiration:</h4>
<p>The security of access tokens is of paramount importance in safeguarding user authentication and authorization processes, especially during their transmission over the internet. Encrypting these tokens is crucial, as it ensures that their contents remain confidential and impervious to unauthorized access. Equally important is the use of secure communication channels, notably HTTPS, to prevent the interception and compromise of tokens in transit. Furthermore, the signature component of a token, particularly in JWTs, plays a vital role in verifying its authenticity and integrity. This signature confirms that the token has not been altered and is genuinely issued by a trusted authority, thus preventing the risks associated with token forgery and replay attacks.</p>
<p>Access tokens are inherently designed with expiration mechanisms, a strategic choice to mitigate the risks associated with token theft or misuse. This finite lifespan of tokens necessitates regular renewal, typically managed through refresh tokens, thereby ensuring active session management and reducing opportunities for unauthorized use. The storage and handling of these tokens in client applications also significantly impact their overall security. Secure storage methods, such as in-memory or encrypted cookies, alongside careful management of token renewal processes, are essential to prevent unauthorized access and maintain the robustness of user sessions and access controls.</p>
<h2 id="authenticationworkflow">Authentication workflow</h2>
<h3 id="authenticationvsauthorization">Authentication vs authorization</h3>
<p>Before we dive into authentication in Okta, we should take a moment to understand the difference between authentication and authorization. To put it simply, authentication is providing evidence to prove identity, whereas authorization is about permissions and privileges once access is granted. </p>
<p>As we discussed throughout this blog, the Identity Engine and UD are critical to identity management in Okta. As a recap, the Identity Engine is used for enrolling, authentications, and authorizing users. The UD is used as the main directory service in Okta that contains users, groups, profiles, and policies, also serving as the source of truth for user data. The UD can be synchronized with other directory services such as AD or LDAP through the Okta endpoint agent.</p>
<p>Identity management can be managed via Okta or through an external IdP, such as Google Workspace. Essentially, when access to an application is requested, redirection to the authorization server’s endpoint APIs for authentication are generated to provide proof of identity.</p>
<p>Below are the main authentication protocols between the end user, resource server, and authorization server:</p>
<ul>
<li>OIDC: Authentication protocol that sits on top of the OAuth authorization framework. Workflow requires an ID token (JWT) to be obtained during an access token request.</li>
<li>SAML: Open standard protocol formatted in XML that facilitates user identity data exchange between SPs and IdPs.</li>
</ul>
<p>Within Okta, there is plenty of flexibility and customization regarding authentication. Basic authentication is supported where simple username and password schemes are used over HTTP with additional parameters and configurations.</p>
<h3 id="samlinauthentication">SAML in authentication</h3>
<p>As previously stated, <a href="https://developer.okta.com/docs/concepts/saml/">SAML</a> is a login standard that helps facilitate user access to applications based on HTTP(s) requests and sessions asynchronously. Over time the use of basic credentials for each application quickly became a challenge and thus federated identity was introduced to allow identity authentication across different SPs, facilitated by the identity providers. </p>
<p>SAML is primarily a web-based authentication mechanism as it relies on a flow of traffic between the end user, IdP, and SP. The SAML authentication flow can either be IdP or SP initiated depending on where the end user visits first for application access.</p>
<p>The SAML request is typically generated by the SP whereas the SAML response is generated by the IdP. The response contains the SAML assertion, which contains information about the authenticated user’s identity and a signed signature by the IdP.</p>
<p>It is important to note that during the SAML workflow, the IdP and SP typically never communicate directly, but instead rely on the end user’s browser for redirections. Typically, the SP trusts the IdP and thus the identity data forwarded through the user’s web browser to the SP is trusted in access is granted to the application requested.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb94865a182648cf2/6a7d8473ea068dfcd7f0726e/image1.png" alt="Diagram depicting Okta SAML authentication process" title="Diagram depicting Okta SAML authentication process" /></p>
<p>In step 5 from the diagram above, the SAML assertion would be sent as part of this response after the user has authenticated with the IdP. Remember that the assertion is in XML format and can be quite extensive as it contains identity information for the SP to parse and rely on for the end user’s identity verification. Generic examples of SAML assertions are <a href="https://www.samltool.com/generic_sso_res.php">provided</a> by OneLogin. Auth0 also <a href="https://samltool.io/">provides</a> a decoder and parser for these examples as well which is shown in the image below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt677ebc1e4a177c07/6a7d8476c2e914b178013ced/image2.png" alt="Auth0 decoder and parser for SAML" title="Auth0 decoder and parser for SAML" /></p>
<h3 id="idpvsspresponsibilities">IdP vs SP responsibilities</h3>
<p>When discussing the roles and responsibilities of the SP and IdP, keep in mind that the SP is meant to provide access to applications for the end user, whereas the IdP provides authentication and authorization. The SP and IdP are typically set up to trust each other with their designated responsibilities. Depending on the end user, workflows for authentication and authorization can be SP or IdP initiated where RESTful API endpoints are typically depended on for each workflow. For authentication, requests and responses are sent from the IdP and SP but often proxied through the end user’s browser.</p>
<p>Although Okta is mainly an IdP and provides authentication and authorization services, it can also be used as an SP. Previously we discussed how Okta’s integration network allows for various 3rd-party applications to be connected and accessible to users through their dashboard. We also explained how authentication workflows can be SP initiated, meaning users could visit their Okta dashboard to request access to an application. At the same time, a 3rd-party IdP could be established such as Google Workspace or Azure AD which would handle the authentication and authorization of the user. If the user were to request access with this type of setup, Okta would then redirect the user to Azure AD for authentication.</p>
<h3 id="singlefactorvsmultifactorauthentication">Single-factor vs multi-factor authentication</h3>
<p>Single-factor authentication (SFA) is the simplest form of authentication, requiring a user to supply one credential object for authentication. Commonly, users are familiar with password-based authentication methods where a username and password are supplied to validate themselves. This of course has security implications if the credentials used are stolen as they can be used by an adversary to login and access the same resources.</p>
<p>Multifactor authentication (MFA) is similar to SFA, except it requires two or more types of credentials or evidence to be supplied for authentication, typically in sequence. For example, a password-based credential may be supplied and once verified by the IdP, then requested by an OTP be supplied by a mobile device authenticator application, SMS message, email, and others. The common types of authentication factors are something that the user knows, possesses, or is inherent. This also increases the complexity to adversaries based on randomized string generation for OTPs and MFA token expirations.</p>
<p>Okta enables other types of authentication methods such as passwordless, risk-based, biometric, transaction, and others. A full list of authentication methods and descriptions can be found <a href="https://developer.okta.com/docs/concepts/iam-overview-authentication-factors/#authentication-methods">here</a>.</p>
<p>Every application or integration added to the Okta organization has an <a href="https://help.okta.com/oie/en-us/content/topics/identity-engine/policies/about-app-sign-on-policies.htm">authentication policy</a>, which verifies conditions for users who attempt to access each application. Authentication policies can also help enforce factor requirements based on these conditions where the UD and user profile are used to analyze information about the user. Authentication policies can be set globally for applications and users or can be more granular if set at the application level where specific user conditions are met. Authentication policies can be updated, cloned, preset, and merged if duplicate policies. Rules that define these granular conditions can be applied to these authentication policies with the Okta Expression Language (<a href="https://help.okta.com/oie/en-us/content/topics/identity-engine/devices/el-about.htm">EL</a>). </p>
<h3 id="clientsideandserversidecommunications">Client-side and server-side communications</h3>
<p>Understanding the distinction between front-end (user-browser interactions) and back-end (server-to-server communications) is crucial in web-based authentication systems. Front-end interactions typically involve user interfaces and actions, while back-end channels handle critical exchanges like SAML assertions or OAuth tokens, crucial for secure authentication.</p>
<p>In Okta's framework, the interplay between browser and server is key for security and user experience. When a user logs in via Okta, the browser first authenticates with Okta, which then sends back the necessary tokens. These are forwarded to the application server which validates them with Okta, ensuring a secure, behind-the-scenes token exchange.</p>
<p>Okta’s token management is marked by stringent security. Issued tokens like ID and access tokens are securely exchanged among the user’s browser, Okta, and application servers. Protocols like HTTPS and OAuth 2.0 safeguard these transmissions. Features like token rotation and automatic revocation further bolster security, preventing unauthorized access.</p>
<p>Integrating Okta into an application reshapes its design and security. This offloads significant security responsibilities, allowing developers to focus on core functions. Such integration leads to a modular architecture, where authentication services are separate from application logic. </p>
<h2 id="conclusion">Conclusion</h2>
<p>We’ve unraveled the complexities of Okta’s architecture and services, providing insights into its role as a leader in modern authentication and authorization. With the platform’s utilization of protocols like OAuth, OIDC, and SAML, Okta stands at the forefront of scalable, integrated solutions, seamlessly working with platforms such as Azure AD and Google Workspace.</p>
<p>Okta's SaaS design, featuring a RESTful API, makes it a versatile Identity Provider (IdP) and Service Provider (SP). Yet, its popularity also brings potential security vulnerabilities. For cybersecurity professionals, it’s crucial to grasp Okta’s complexities to stay ahead of evolving threats. This introduction sets the stage for upcoming deeper analyses of Okta's attack surface, the setup of a threat detection lab, and the exploration of common attacks.</p>
<p>Armed with this knowledge, you’re now better equipped to analyze, understand, and mitigate the evolving cybersecurity challenges associated with Okta’s ecosystem.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/starter-guide-to-understanding-okta</link>
    <guid isPermaLink="false">starter-guide-to-understanding-okta</guid>
    <category><![CDATA[Cloud Security]]></category>
    <dc:creator><![CDATA[Terrance DeJesus]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7dffd621666710a6/6a7d8479e02fac82125d3554/photo-edited-09.png" length="0" type="image/png"/>
    <pubDate>Tue, 23 Jan 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Google Cloud for Cyber Data Analytics]]></title>
    <description><![CDATA[This article explains how we conduct comprehensive cyber threat data analysis using Google Cloud, from data extraction and preprocessing to trend analysis and presentation. It emphasizes the value of BigQuery, Python, and Google Sheets - showcasing how to refine and visualize data for insightful cybersecurity analysis.]]></description>
    <content:encoded><![CDATA[<p>In today's digital age, the sheer volume of data generated by devices and systems can be both a challenge and an opportunity for security practitioners. Analyzing a high magnitude of data to craft valuable or actionable insights on cyber attack trends requires precise tools and methodologies.</p>
<p>Before you delve into the task of data analysis, you might find yourself asking:</p>
<ul>
<li>What specific questions am I aiming to answer, and do I possess the necessary data?</li>
<li>Where is all the pertinent data located?</li>
<li>How can I gain access to this data?</li>
<li>Upon accessing the data, what steps are involved in understanding and organizing it?</li>
<li>Which tools are most effective for extracting, interpreting, or visualizing the data?</li>
<li>Should I analyze the raw data immediately or wait until it has been processed?</li>
<li>Most crucially, what actionable insights can be derived from the data?</li>
</ul>
<p>If these questions resonate with you, you're on the right path. Welcome to the world of Google Cloud, where we'll address these queries and guide you through the process of creating a comprehensive report.</p>
<p>Our approach will include several steps in the following order:</p>
<p><strong>Exploration:</strong> We start by thoroughly understanding the data at our disposal. This phase involves identifying potential insights we aim to uncover and verifying the availability of the required data.</p>
<p><strong>Extraction:</strong> Here, we gather the necessary data, focusing on the most relevant and current information for our analysis.</p>
<p><strong>Pre-processing and transformation:</strong> At this stage, we prepare the data for analysis. This involves normalizing (cleaning, organizing, and structuring) the data to ensure its readiness for further processing.</p>
<p><strong>Trend analysis:</strong> The majority of our threat findings and observations derive from this effort. We analyze the processed data for patterns, trends, and anomalies. Techniques such as time series analysis and aggregation are employed to understand the evolution of threats over time and to highlight significant cyber attacks across various platforms.</p>
<p><strong>Reduction:</strong> In this step, we distill the data to its most relevant elements, focusing on the most significant and insightful aspects.</p>
<p><strong>Presentation:</strong> The final step is about presenting our findings. Utilizing tools from Google Workspace, we aim to display our insights in a clear, concise, and visually-engaging manner.</p>
<p><strong>Conclusion:</strong> Reflecting on this journey, we'll discuss the importance of having the right analytical tools. We'll highlight how Google Cloud Platform (GCP) provides an ideal environment for analyzing cyber threat data, allowing us to transform raw data into meaningful insights.</p>
<h2 id="explorationdeterminingavailabledata">Exploration: Determining available data</h2>
<p>Before diving into any sophisticated analyses, it's necessary to prepare by establishing an understanding of the data landscape we intend to study.</p>
<p>Here's our approach:</p>
<ol>
<li><strong>Identifying available data:</strong> The first step is to ascertain what data is accessible. This could include malware phenomena, endpoint anomalies, cloud signals, etc. Confirming the availability of these data types is essential.</li>
<li><strong>Locating the data stores:</strong> Determining the exact location of our data. Knowing where our data resides – whether in databases, data lakes, or other storage solutions – helps streamline the subsequent analysis process.</li>
<li><strong>Accessing the data:</strong> It’s important to ensure that we have the necessary permissions or credentials to access the datasets we need. If we don’t, attempting to identify and request access from the resource owner is necessary.</li>
<li><strong>Understanding the data schema:</strong> Comprehending the structure of our data is vital. Knowing the schema aids in planning the analysis process effectively.</li>
<li><strong>Evaluating data quality:</strong> Just like any thorough analysis, assessing the quality of the data is crucial. We check whether the data is segmented and detailed enough for a meaningful trend analysis.</li>
</ol>
<p>This phase is about ensuring that our analysis is based on solid and realistic foundations. For a report like the <a href="http://www.elastic.co/gtr">Global Threat Report</a>, we rely on rich and pertinent datasets such as:</p>
<ul>
<li><p><strong>Cloud signal data:</strong> This includes data from global Security Information and Event Management (SIEM) alerts, especially focusing on cloud platforms like AWS, GCP, and Azure. This data is often sourced from <a href="https://github.com/elastic/detection-rules">public detection rules</a>.</p></li>
<li><p><strong>Endpoint alert data:</strong> Data collected from the global <a href="https://docs.elastic.co/en/integrations/endpoint">Elastic Defend</a> alerts, incorporating a variety of public <a href="https://github.com/elastic/protections-artifacts/tree/main/behavior">endpoint behavior rules</a>.</p></li>
<li><p><strong>Malware data:</strong> This involves data from global Elastic Defend alerts, enriched with <a href="https://www.elastic.co/blog/introducing-elastic-endpoint-security">MalwareScore</a> and public <a href="https://github.com/elastic/protections-artifacts/tree/main/yara">YARA rules</a>.</p>
<p>Each dataset is categorized and enriched for context with frameworks like <a href="https://attack.mitre.org/">MITRE ATT&amp;CK</a>, Elastic Stack details, and customer insights. Storage solutions of Google Cloud Platform, such as BigQuery and Google Cloud Storage (GCS) buckets, provide a robust infrastructure for our analysis.</p></li>
</ul>
<p>It's also important to set a data “freshness” threshold, excluding data not older than 365 days for an annual report, to ensure relevance and accuracy.</p>
<p>Lastly, remember to choose data that offers an unbiased perspective. Excluding or including internal data should be an intentional, strategic decision based on its relevance to your visibility.</p>
<p>In summary, selecting the right tools and datasets is fundamental to creating a comprehensive and insightful analysis. Each choice contributes uniquely to the overall effectiveness of the data analysis, ensuring that the final insights are both valuable and impactful.</p>
<h2 id="extractionthefirststepindataanalysis">Extraction: The first step in data analysis</h2>
<p>Having identified and located the necessary data, the next step in our analytical journey is to extract this data from our storage solutions. This phase is critical, as it sets the stage for the in-depth analysis that follows.</p>
<h3 id="dataextractiontoolsandtechniques">Data extraction tools and techniques</h3>
<p>Various tools and programming languages can be utilized for data extraction, including Python, R, Go, Jupyter Notebooks, and Looker Studio. Each tool offers unique advantages, and the choice depends on the specific needs of your analysis.</p>
<p>In our data extraction efforts, we have found the most success from a combination of <a href="https://cloud.google.com/bigquery?hl=en">BigQuery</a>, <a href="https://colab.google/">Colab Notebooks</a>, <a href="https://cloud.google.com/storage/docs/json_api/v1/buckets">buckets</a>, and <a href="https://workspace.google.com/">Google Workspace</a> to extract the required data. Colab Notebooks, akin to Jupyter Notebooks, operate within Google's cloud environment, providing a seamless integration with other Google Cloud services.</p>
<h3 id="bigqueryfordatastagingandquerying">BigQuery for data staging and querying</h3>
<p>In the analysis process, a key step is to "stage" our datasets using BigQuery. This involves utilizing BigQuery queries to create and save objects, thereby making them reusable and shareable across our team. We achieve this by employing the <a href="https://hevodata.com/learn/google-bigquery-create-table/#b2">CREATE TABLE</a> statement, which allows us to combine multiple <a href="https://cloud.google.com/bigquery/docs/datasets-intro">datasets</a> such as endpoint behavior alerts, customer data, and rule data into a single, comprehensive dataset.</p>
<p>This consolidated dataset is then stored in a BigQuery table specifically designated for this purpose–for this example, we’ll refer to it as the “Global Threat Report” dataset. This approach is applied consistently across different types of data, including both cloud signals and malware datasets.</p>
<p>The newly created data table, for instance, might be named <code>elastic.global_threat_report.ep_behavior_raw</code>. This naming convention, defined by BigQuery, helps in organizing and locating the datasets effectively, which is crucial for the subsequent stages of the extraction process.</p>
<p>An example of a BigQuery query used in this process might look like this:</p>
<pre><code>CREATE TABLE elastic.global_threat_report.ep_behavior_raw AS
SELECT * FROM ...
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbd326024448763c0/6a7d80e3e88c6555a500897a/image8.png" alt="Diagram for BigQuery query to an exported dataset table" title="Diagram for BigQuery query to an exported dataset table" />
Diagram for BigQuery query to an exported dataset table</p>
<p>We also use the <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/other-statements#export_data_statement">EXPORT DATA</a> statement in BigQuery to transfer tables to other GCP services, like exporting them to Google Cloud Storage (GCS) buckets in <a href="https://parquet.apache.org/">parquet file format</a>.</p>
<pre><code>EXPORT DATA
  OPTIONS (
    uri = 'gs://**/ep_behavior/*.parquet',
    format = 'parquet',
    overwrite = true
  )
AS (
SELECT * FROM `project.global_threat_report.2023_pre_norm_ep_behavior`
)
</code></pre>
<h3 id="colabnotebooksforloadingstageddatasets">Colab Notebooks for loading staged datasets</h3>
<p><a href="https://colab.research.google.com/">Colab Notebooks</a> are instrumental in organizing our data extraction process. They allow for easy access and management of data scripts stored in platforms like GitHub and Google Drive.</p>
<p>For authentication and authorization, we use Google Workspace credentials, simplifying access to various Google Cloud services, including BigQuery and Colab Notebooks. Here's a basic example of how authentication is handled:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5a37b9ce313be7d5/6a7d80e6ead8ec267cba7b32/image9.png" alt="Diagram for authentication and authorization between Google Cloud services" title="Diagram for authentication and authorization between Google Cloud services" />
Diagram for authentication and authorization between Google Cloud services</p>
<p>For those new to <a href="https://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/">Jupyter Notebooks</a> or dataframes, it's beneficial to spend time becoming familiar with these tools. They are fundamental in any data analyst's toolkit, allowing for efficient code management, data analysis, and structuring. Mastery of these tools is key to effective data analysis.</p>
<p>Upon creating a notebook in Google Colab, we're ready to extract our custom tables (such as project.global_threat_report.ep_behavior_raw) from BigQuery. This data is then loaded into Pandas Dataframes, a Python library that facilitates data manipulation and analysis. While handling large datasets with Python can be challenging, Google Colab provides robust virtual computing resources. If needed, these resources can be scaled up through the Google Cloud <a href="https://console.cloud.google.com/marketplace/product/colab-marketplace-image-public/colab">Marketplace</a> or the Google Cloud Console, ensuring that even large datasets can be processed efficiently.</p>
<h3 id="essentialpythonlibrariesfordataanalysis">Essential Python libraries for data analysis</h3>
<p>In our data analysis process, we utilize various Python libraries, each serving a specific purpose:</p>
<p>| Library | Description |
|-----------|---------------|
|<a href="https://docs.python.org/3/library/datetime.html">datetime</a> | Essential for handling all operations related to date and time in your data. It allows you to manipulate and format date and time information for analysis. |
| <a href="https://google-auth.readthedocs.io/en/master/">google.auth</a> | Manages authentication and access permissions, ensuring secure access to Google Cloud services. It's key for controlling who can access your data and services. |
| <a href="https://cloud.google.com/python/docs/reference/bigquery/latest">google.colab.auth</a> | Provides authentication for accessing Google Cloud services within Google Colab notebooks, enabling a secure connection to your cloud-based resources. |
| <a href="https://cloud.google.com/python/docs/reference/bigquery/latest">google.cloud.bigquery</a> | A tool for managing large datasets in Google Cloud's BigQuery service. It allows for efficient processing and analysis of massive amounts of data. |
| <a href="https://cloud.google.com/python/docs/reference/storage/latest">google.cloud.storage</a> | Used for storing and retrieving data in Google Cloud Storage. It's an ideal solution for handling various data files in the cloud. |
| <a href="https://docs.gspread.org/en/latest/">gspread</a> | Facilitates interaction with Google Spreadsheets, allowing for easy manipulation and analysis of spreadsheet data. |
| <a href="https://pypi.org/project/gspread-dataframe/">gspread.dataframe</a>.set_with_dataframe | Syncs data between Pandas dataframes and Google Spreadsheets, enabling seamless data transfer and updating between these formats. |
| <a href="https://pypi.org/project/matplotlib/">matplotlib</a>.pyplot.plt | A module in Matplotlib library for creating charts and graphs. It helps in visualizing data in a graphical format, making it easier to understand patterns and trends. |
| <a href="https://pandas.pydata.org/">pandas</a> | A fundamental tool for data manipulation and analysis in Python. It offers data structures and operations for manipulating numerical tables and time series. |
| <a href="https://pypi.org/project/pandas-gbq/">pandas.gbq</a>.to_gbq | Enables the transfer of data from Pandas dataframes directly into Google BigQuery, streamlining the process of moving data into this cloud-based analytics platform. |
| <a href="https://arrow.apache.org/docs/python/index.html">pyarrow</a>.parquet.pq | Allows for efficient storage and retrieval of data in the Parquet format, a columnar storage file format optimized for use with large datasets. |
| <a href="https://seaborn.pydata.org/">seaborn</a> | A Python visualization library based on Matplotlib that provides a high-level interface for drawing attractive and informative statistical graphics. |</p>
<p>Next, we authenticate with BigQuery, and receive authorization to access our datasets as demonstrated earlier. By using Google Workspace credentials, we can easily access BigQuery and other Google Cloud services. The process typically involves a simple code snippet for authentication:</p>
<pre><code>from google.colab import auth
from google.cloud import bigquery

auth.authenticate_user()
project_id = "PROJECT_FROM_GCP"
client = bigquery.Client(project=project_id)
</code></pre>
<p>With authentication complete, we can then proceed to access and manipulate our data. Google Colab's integration with Google Cloud services simplifies this process, making it efficient and secure.</p>
<h3 id="organizingcolabnotebooksbeforeanalysis">Organizing Colab Notebooks before analysis</h3>
<p>When working with Jupyter Notebooks, it's better to organize your notebook beforehand. Various stages of handling and manipulating data will be required, and staying organized will help you create a repeatable, comprehensive process. </p>
<p>In our notebooks, we use Jupyter Notebook headers to organize the code systematically. This structure allows for clear compartmentalization and the creation of collapsible sections, which is especially beneficial when dealing with complex data operations that require multiple steps. This methodical organization aids in navigating the notebook efficiently, ensuring that each step in the data extraction and analysis process is easily accessible and manageable.</p>
<p>Moreover, while the workflow in a notebook might seem linear, it's often more dynamic. Data analysts frequently engage in multitasking, jumping between different sections as needed based on the data or results they encounter. Furthermore, new insights discovered in one step may influence another step’s process, leading to some back and forth before finishing the notebook.
 | <img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt47623e85af603960/6a7d80e8448e4e2bb25bdb36/image3.png" alt="" /></p>
<h3 id="extractingourbigquerydatasetsintodataframes">Extracting Our BigQuery datasets into dataframes</h3>
<p>After establishing the structure of our notebook and successfully authenticating with BigQuery, our next step is to retrieve the required datasets. This process sets the foundation for the rest of the report, as the information from these sources will form the basis of our analysis, similar to selecting the key components required for a comprehensive study.</p>
<p>Here's an example of how we might fetch data from BigQuery:</p>
<pre><code>import datetime

current_year = datetime.datetime.now().year
reb_dataset_id = f'project.global_threat_report.{current_year}_raw_ep_behavior'
reb_table = client.list_rows(reb_dataset_id)
reb_df = reb_table.to_dataframe() 
</code></pre>
<p>This snippet demonstrates a typical data retrieval process. We first define the dataset we're interested in (with the Global Threat Report, <code>project.global_threat_report.ep_behavior_raw</code> for the current year). Then, we use a BigQuery query to select the data from this dataset and load it into a Pandas DataFrame. This DataFrame will serve as the foundation for our subsequent data analysis steps.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdab7bda6ecb2fb9d/6a7d80ebea068d2976f07223/image4.png" alt="Colab Notebook snippet for data extraction from BigQuery into Pandas dataframe" title="Colab Notebook snippet for data extraction from BigQuery into Pandas dataframe" />
Colab Notebook snippet for data extraction from BigQuery into Pandas dataframe</p>
<p>This process marks the completion of the extraction phase. We have successfully navigated BigQuery to select and retrieve the necessary datasets and load them in our notebooks within dataframes. The extraction phase is pivotal, as it not only involves gathering the data but also setting up the foundation for deeper analysis. It's the initial step in a larger journey of discovery, leading to the transformation phase, where we will uncover more detailed insights from the data.</p>
<p>In summary, this part of our data journey is about more than just collecting datasets; it's about structurally preparing them for the in-depth analysis that follows. This meticulous approach to organizing and executing the extraction phase sets the stage for the transformative insights that we aim to derive in the subsequent stages of our data analysis.</p>
<h2 id="preprocessingandtransformationthecriticalphaseofdataanalysis">Pre-processing and transformation: The critical phase of data analysis</h2>
<p>The transition from raw data to actionable insights involves a series of crucial steps in data processing. After extracting data, our focus shifts to refining it for analysis. Cybersecurity datasets often include various forms of noise, such as false positives and anomalies, which must be addressed to ensure accurate and relevant analysis.</p>
<p>Key stages in data pre-processing and transformation:</p>
<ul>
<li><strong>Data cleaning:</strong> This stage involves filling NULL values, correcting data misalignments, and validating data types to ensure the dataset's integrity.</li>
<li><strong>Data enrichment:</strong> In this step, additional context is added to the dataset. For example, incorporating third-party data, like malware reputations from sources such as VirusTotal, enhances the depth of analysis.</li>
<li><strong>Normalization:</strong> This process standardizes the data to ensure consistency, which is particularly important for varied datasets like endpoint malware alerts.</li>
<li><strong>Anomaly detection:</strong> Identifying and rectifying outliers or false positives is critical to maintain the accuracy of the dataset.</li>
<li><strong>Feature extraction:</strong> The process of identifying meaningful, consistent data points that can be further extracted for analysis.</li>
</ul>
<h3 id="embracingtheartofdatacleaning">Embracing the art of data cleaning</h3>
<p>Data cleaning is a fundamental step in preparing datasets for comprehensive analysis, especially in cybersecurity. This process involves a series of technical checks to ensure data integrity and reliability. Here are the specific steps:</p>
<ul>
<li><p><strong>Mapping to MITRE ATT&amp;CK framework:</strong> Verify that all detection and response rules in the dataset are accurately mapped to the corresponding tactics and techniques in the MITRE ATT&amp;CK framework. This check includes looking for NULL values or any inconsistencies in how the data aligns with the framework.</p></li>
<li><p><strong>Data type validation:</strong> Confirm that the data types within the dataset are appropriate and consistent. For example, timestamps should be in a standardized datetime format. This step may involve converting string formats to datetime objects or verifying that numerical values are in the correct format.</p></li>
<li><p><strong>Completeness of critical data:</strong> Ensure that no vital information is missing from the dataset. This includes checking for the presence of essential elements like SHA256 hashes or executable names in endpoint behavior logs. The absence of such data can lead to incomplete or biased analysis.</p></li>
<li><p><strong>Standardization across data formats:</strong> Assess and implement standardization of data formats across the dataset to ensure uniformity. This might involve normalizing text formats, ensuring consistent capitalization, or standardizing date and time representations.</p></li>
<li><p><strong>Duplicate entry identification:</strong> Identify and remove duplicate entries by examining unique identifiers such as XDR agent IDs or cluster IDs. This process might involve using functions to detect and remove duplicates, ensuring the uniqueness of each data entry.</p></li>
<li><p><strong>Exclusion of irrelevant internal data:</strong> Locate and remove any internal data that might have inadvertently been included in the dataset. This step is crucial to prevent internal biases or irrelevant information from affecting the analysis.</p>
<p>It is important to note that data cleaning or “scrubbing the data” is a continuous effort throughout our workflow. As we continue to peel back the layers of our data and wrangle it for various insights, it is expected that we identify additional changes.</p></li>
</ul>
<h3 id="utilizingpandasfordatacleaning">Utilizing Pandas for data cleaning</h3>
<p>The <a href="https://pandas.pydata.org/about/">Pandas</a> library in Python offers several functionalities that are particularly useful for data cleaning in cybersecurity contexts. Some of these methods include:</p>
<ul>
<li><code>DataFrame.isnull()</code> or <code>DataFrame.notnull()</code> to identify missing values.</li>
<li><code>DataFrame.drop_duplicates()</code> to remove duplicate rows.</li>
<li>Data type conversion methods like <code>pd.to_datetime()</code> for standardizing timestamp formats.</li>
<li>Utilizing boolean indexing to filter out irrelevant data based on specific criteria.</li>
</ul>
<p>A thorough understanding of the dataset is essential to determine the right cleaning methods. It may be necessary to explore the dataset preliminarily to identify specific areas requiring cleaning or transformation. Additional helpful methods and workflows can be found listed in <a href="https://realpython.com/python-data-cleaning-numpy-pandas/">this</a> Real Python blog.</p>
<h3 id="featureextractionandenrichment">Feature extraction and enrichment</h3>
<p>Feature extraction and enrichment are core steps in data analysis, particularly in the context of cybersecurity. These processes involve transforming and augmenting the dataset to enhance its usefulness for analysis. </p>
<ul>
<li><strong>Create new data from existing:</strong> This is where we modify or use existing data to add additional columns or rows.</li>
<li><strong>Add new data from 3rd-party:</strong> Here, we use existing data as a query reference for 3rd-party RESTful APIs which respond with additional data we can add to the datasets.</li>
</ul>
<h4 id="featureextraction">Feature extraction</h4>
<p>Let’s dig into a tangible example. Imagine we're presented with a bounty of publicly available YARA signatures that Elastic <a href="https://github.com/elastic/protections-artifacts/tree/main/yara/rules">shares</a> with its community. These signatures trigger some of the endpoint malware alerts in our dataset. A consistent naming convention has been observed based on the rule name that, of course, shows up in the raw data: <code>OperationsSystem_MalwareCategory_MalwareFamily</code>. These names can be deconstructed to provide more specific insights. Leveraging Pandas, we can expertly slice and dice the data. For those who prefer doing this during the dataset staging phase with BigQuery, the combination of <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#split">SPLIT</a> and <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#offset_and_ordinal">OFFSET</a> clauses can yield similar results:</p>
<pre><code>df[['OperatingSystem', 'MalwareCategory', 'MalwareFamily']] = df['yara_rule_name'].str.split('_', expand=True)
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9407bbafdb2f1e24/6a7d80eee3a219e36299c712/image2.png" alt="Feature extraction with our YARA data" title="Feature extraction with our YARA data" />
Feature extraction with our YARA data</p>
<p>There are additional approaches, methods, and processes to feature extraction in data analysis. We recommend consulting your stakeholder's wants/needs and exploring your data to help determine what is necessary for extraction and how.</p>
<h4 id="dataenrichment">Data enrichment</h4>
<p>Data enrichment enhances the depth and context of cybersecurity datasets. One effective approach involves integrating external data sources to provide additional perspectives on the existing data. This can be particularly valuable in understanding and interpreting cybersecurity alerts.</p>
<p><strong>Example of data enrichment: Integrating VirusTotal reputation data</strong>
A common method of data enrichment in cybersecurity involves incorporating reputation scores from external threat intelligence services like <a href="https://www.virustotal.com/gui/home/search">VirusTotal</a> (VT). This process typically includes:</p>
<ol>
<li><strong>Fetching reputation data:</strong> Using an API key from VT, we can query for reputational data based on unique identifiers in our dataset, such as SHA256 hashes of binaries.</li>
</ol>
<pre><code>import requests

def get_reputation(sha256, API_KEY, URL):
    params = {'apikey': API_KEY, 'resource': sha256}
    response = requests.get(URL, params=params)
    json_response = response.json()

    if json_response.get("response_code") == 1:
        positives = json_response.get("positives", 0)
        return classify_positives(positives)
    else:
        return "unknown"
</code></pre>
<p>In this function, <code>classify_positives</code> is a custom function that classifies the reputation based on the number of antivirus engines that flagged the file as malicious.</p>
<ol>
<li><strong>Adding reputation data to the dataset:</strong> The reputation data fetched from VirusTotal is then integrated into the existing dataset. This is done by applying the <code>get_reputation</code> function to each relevant entry in the DataFrame.</li>
</ol>
<pre><code>df['reputation'] = df['sha256'].apply(lambda x: get_reputation(x, API_KEY, URL))
</code></pre>
<p>Here, a new column named <code>reputation</code> is added to the dataframe, providing an additional layer of information about each binary based on its detection rate in VirusTotal.</p>
<p>This method of data enrichment is just one of many options available for enhancing cybersecurity threat data. By utilizing robust helper functions and tapping into external data repositories, analysts can significantly enrich their datasets. This enrichment allows for a more comprehensive understanding of the data, leading to a more informed and nuanced analysis. The techniques demonstrated here are part of a broader range of advanced data manipulation methods that can further refine cybersecurity data analysis.</p>
<h3 id="normalization">Normalization</h3>
<p>Especially when dealing with varied datasets in cybersecurity, such as endpoint alerts and cloud SIEM notifications, normalization may be required to get the most out of your data. </p>
<p><strong>Understanding normalization:</strong> At its core, normalization is about adjusting values measured on different scales to a common scale, ensuring that they are proportionally represented, and reducing redundancy. In the cybersecurity context, this means representing events or alerts in a manner that doesn't unintentionally amplify or reduce their significance.</p>
<p>Consider our endpoint malware dataset. When analyzing trends, say, infections based on malware families or categories, we aim for an accurate representation. However, a single malware infection on an endpoint could generate multiple alerts depending on the Extended Detection and Response (XDR) system. If left unchecked, this could significantly skew our understanding of the threat landscape. To counteract this, we consider the Elastic agents, which are deployed as part of the XDR solution. Each endpoint has a unique agent, representing a single infection instance if malware is detected. Therefore, to normalize this dataset, we would "flatten" or adjust it based on unique agent IDs. This means, for our analysis, we'd consider the number of unique agent IDs affected by a specific malware family or category rather than the raw number of alerts.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcde9263bdd8aea1f/6a7d80f1de23151bdefd4e3e/image6.png" alt="Example visualization of malware alert normalization by unique agents" title="Example visualization of malware alert normalization by unique agents" />
Example visualization of malware alert normalization by unique agents</p>
<p>As depicted in the image above, if we chose to not normalize the malware data in preparation for trend analysis, our key findings would depict inaccurate information. This inaccuracy could be sourced from a plethora of data inconsistencies such as generic YARA rules, programmatic operations that were flagged repeatedly on a single endpoint, and many more.</p>
<p><strong>Diversifying the approach:</strong> On the other hand, when dealing with endpoint behavior alerts or cloud alerts (from platforms like AWS, GCP, Azure, Google Workspace, and O365), our normalization approach might differ. These datasets could have their own nuances and may not require the same "flattening" technique used for malware alerts.</p>
<p><strong>Conceptualizing normalization options:</strong> Remember the goal of normalization is to reduce redundancy in your data. Make sure to keep your operations as atomic as possible in case you need to go back and tweak them later. This is especially true when performing both normalization and standardization. Sometimes these can be difficult to separate, and you may have to go back and forth between the two. Analysts have a wealth of options for these. From <a href="https://www.geeksforgeeks.org/data-pre-processing-wit-sklearn-using-standard-and-minmax-scaler/">Min-Max</a> scaling, where values are shifted and rescaled to range between 0 and 1, to <a href="https://www.statology.org/z-score-python/">Z-score</a> normalization (or standardization), where values are centered around zero and standard deviations from the mean. The choice of technique depends on the nature of the data and the specific requirements of the analysis. </p>
<p>In essence, normalization ensures that our cybersecurity analysis is based on a level playing field, giving stakeholders an accurate view of the threat environment without undue distortions. This is a critical step before trend analysis.</p>
<h3 id="anomalydetectionrefiningtheprocessofdataanalysis">Anomaly detection: Refining the process of data analysis</h3>
<p>In the realm of cybersecurity analytics, a one-size-fits-all approach to anomaly detection does not exist. The process is highly dependent on the specific characteristics of the data at hand. The primary goal is to identify and address outliers that could potentially distort the analysis. This requires a dynamic and adaptable methodology, where understanding the nuances of the dataset is crucial.</p>
<p>Anomaly detection in cybersecurity involves exploring various techniques and methodologies, each suited to different types of data irregularities. The strategy is not to rigidly apply a single method but rather to use a deep understanding of the data to select the most appropriate technique for each situation. The emphasis is on flexibility and adaptability, ensuring that the approach chosen provides the clearest and most accurate insights into the data.</p>
<h4 id="statisticalmethodsthebackboneofanalysis">Statistical methods – The backbone of analysis:</h4>
<p>Statistical analysis is always an optional approach to anomaly detection, especially for cyber security data. By understanding the inherent distribution and central tendencies of our data, we can highlight values that deviate from the norm. A simple yet powerful method, the Z-score, gauges the distance of a data point from the mean in terms of standard deviations.</p>
<pre><code>import numpy as np

# Derive Z-scores for data points in a feature
z_scores = np.abs((df['mitre_technique'] - df['mitre_technique'].mean()) / df['mitre_technique'].std())

outliers = df[z_scores &gt; 3]  # Conventionally, a Z-score above 3 signals an outlier
</code></pre>
<p><strong>Why this matters:</strong> This method allows us to quantitatively gauge the significance of a data point's deviation. Such outliers can heavily skew aggregate metrics like mean or even influence machine learning model training detrimentally. Remember, outliers should not always be removed; it is all about context! Sometimes you may even be looking for the outliers specifically.</p>
<p><strong>Key library:</strong> While we utilize <a href="https://numpy.org/">NumPy</a> above, <a href="https://scipy.org/">SciPy</a> can also be employed for intricate statistical operations.</p>
<h4 id="aggregationsandsortingunravelinglayers">Aggregations and sorting – unraveling layers:</h4>
<p>Data often presents itself in layers. By starting with a high-level view and gradually diving into specifics, we can locate inconsistencies or anomalies. When we aggregate by categories such as the MITRE ATT&amp;CK tactic, and then delve deeper, we gradually uncover the finer details and potential anomalies as we go from technique to rule logic and alert context.</p>
<pre><code># Aggregating by tactics first
tactic_agg = df.groupby('mitre_tactic').size().sort_values(ascending=False)
</code></pre>
<p>From here, we can identify the most common tactics and choose the tactic with the highest count. We then filter our data for this tactic to identify the most common technique associated with the most common tactic. Techniques often are more specific than tactics and thus add more explanation about what we may be observing. Following the same approach we can then filter for this specific technique, aggregate by rule and review that detection rule for more context. The goal here is to find “noisy” rules that may be skewing our dataset and thus related alerts need to be removed. This cycle can be repeated until outliers are removed and the percentages appear more accurate.</p>
<p><strong>Why this matters:</strong> This layered analysis approach ensures no stone is left unturned. By navigating from the general to the specific, we systematically weed out inconsistencies.</p>
<p><strong>Key library:</strong> Pandas remains the hero, equipped to handle data-wrangling chores with finesse.</p>
<h4 id="visualizationthelensofclarity">Visualization – The lens of clarity:</h4>
<p>Sometimes, the human eye, when aided with the right visual representation, can intuitively detect what even the most complex algorithms might miss. A boxplot, for instance, not only shows the central tendency and spread of data but distinctly marks outliers.</p>
<pre><code>import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(12, 8))
sns.boxplot(x='Malware Family', y='Malware Score', data=df)
plt.title('Distribution of Malware Scores by Family')
plt.show()
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9fc6a016f0cb6ce5/6a7d80f351156aa13b2bf87f/image10.png" alt="Example visualization of malware distribution scores by family from an example dataset" title="Example visualization of malware distribution scores by family from an example dataset" />
Example visualization of malware distribution scores by family from an example dataset</p>
<p><strong>Why this matters:</strong> Visualization transforms abstract data into tangible insights. It offers a perspective that's both holistic and granular, depending on the need.</p>
<p><strong>Key library:</strong> Seaborn, built atop Matplotlib, excels at turning data into visual stories.</p>
<h4 id="machinelearningtheadvancedguard">Machine learning – The advanced guard:</h4>
<p>When traditional methods are insufficient, machine learning steps in, offering a predictive lens to anomalies. While many algorithms are designed to classify known patterns, some, like autoencoders in deep learning, learn to recreate 'normal' data, marking any deviation as an anomaly.</p>
<p><strong>Why this matters:</strong> As data complexity grows, the boundaries of what constitutes an anomaly become blurrier. Machine learning offers adaptive solutions that evolve with the data.</p>
<p><strong>Key libraries:</strong> <a href="https://scikit-learn.org/stable/">Scikit-learn</a> is a treasure trove for user-friendly, classical machine learning techniques, while <a href="https://pytorch.org/">PyTorch</a> brings the power of deep learning to the table.</p>
<p>Perfecting anomaly detection in data analysis is similar to refining a complex skill through practice and iteration. The process often involves trial and error, with each iteration enhancing the analyst's familiarity with the dataset. This progressive understanding is key to ensuring that the final analysis is both robust and insightful. In data analysis, the journey of exploration and refinement is as valuable as the final outcome itself.</p>
<p>Before proceeding to in-depth trend analysis, it's very important to ensure that the data is thoroughly pre-processed and transformed. Just as precision and reliability are essential in any meticulous task, they are equally critical in data analysis. The steps of cleaning, normalizing, enriching, and removing anomalies from the groundwork for deriving meaningful insights. Without these careful preparations, the analysis could range from slightly inaccurate to significantly misleading. It's only when the data is properly refined and free of distortions that it can reveal its true value, leading to reliable and actionable insights in trend analysis.</p>
<h2 id="trendanalysisunveilingpatternsindata">Trend analysis: Unveiling patterns in data</h2>
<p>In the dynamic field of cybersecurity where threat actors continually evolve their tactics, techniques, and procedures (TTPs), staying ahead of emerging threats is critical. Trend analysis serves as a vital tool in this regard, offering a way to identify and understand patterns and behaviors in cyber threats over time.</p>
<p>By utilizing the MITRE ATT&amp;CK framework, cybersecurity professionals have a structured and standardized approach to analyzing and categorizing these evolving threats. This framework aids in systematically identifying patterns in attack methodologies, enabling defenders to anticipate and respond to changes in adversary behaviors effectively.</p>
<p>Trend analysis, through the lens of the MITRE ATT&amp;CK framework, transforms raw cybersecurity telemetry into actionable intelligence. It allows analysts to track the evolution of attack strategies and to adapt their defense mechanisms accordingly, ensuring a proactive stance in cybersecurity management.</p>
<h3 id="beginningwithabroadoverviewaggregationandsorting">Beginning with a broad overview: Aggregation and sorting</h3>
<p>Commencing our analysis with a bird's eye view is paramount. This panoramic perspective allows us to first pinpoint the broader tactics in play before delving into the more granular techniques and underlying detection rules.</p>
<p><strong>Top tactics:</strong> By aggregating our data based on MITRE ATT&amp;CK tactics, we can discern the overarching strategies adversaries lean toward. This paints a picture of their primary objectives, be it initial access, execution, or exfiltration.</p>
<pre><code>top_tactics = df.groupby('mitre_tactic').size()
 .sort_values(ascending=False)
</code></pre>
<p><strong>Zooming into techniques:</strong> Once we've identified a prominent tactic, we can then funnel our attention to the techniques linked to that tactic. This reveals the specific modus operandi of adversaries.</p>
<pre><code>chosen_tactic = 'Execution'

techniques_under_tactic = df[df['mitre_tactic'] == chosen_tactic]
top_techniques = techniques_under_tactic.groupby('mitre_technique').size()
 .sort_values(ascending=False)
</code></pre>
<p><strong>Detection rules and logic:</strong> With our spotlight on a specific technique, it's time to delve deeper, identifying the detection rules that triggered alerts. This not only showcases what was detected, but by reviewing the detection logic, we also gain an understanding of the precise behaviors and patterns that were flagged.</p>
<pre><code>chosen_technique = 'Scripting'

rules_for_technique = techniques_under_tactic[techniques_under_tactic['mitre_technique'] == chosen_technique]

top_rules = rules_for_technique
 .groupby('detection_rule').size().sort_values(ascending=False)
</code></pre>
<p>This hierarchical, cascading approach is akin to peeling an onion. With each layer, we expose more intricate details, refining our perspective and sharpening our insights.</p>
<h3 id="thepoweroftimetimeseriesanalysis">The power of time: Time series analysis</h3>
<p>In the realm of cybersecurity, time isn't just a metric; it's a narrative. Timestamps, often overlooked, are goldmines of insights. Time series analysis allows us to plot events over time, revealing patterns, spikes, or lulls that might be indicative of adversary campaigns, specific attack waves, or dormancy periods.</p>
<p>For instance, plotting endpoint malware alerts over time can unveil an adversary's operational hours or spotlight a synchronized, multi-vector attack:</p>
<pre><code>import matplotlib.pyplot as plt

# Extract and plot endpoint alerts over time
df.set_index('timestamp')['endpoint_alert'].resample('D').count().plot()
plt.title('Endpoint Malware Alerts Over Time')
plt.xlabel('Time')
plt.ylabel('Alert Count')
plt.show()
</code></pre>
<p>Time series analysis doesn't just highlight "when" but often provides insights into the "why" behind certain spikes or anomalies. It aids in correlating external events (like the release of a new exploit) to internal data trends.</p>
<h3 id="correlationanalysis">Correlation analysis</h3>
<p>Understanding relationships between different sets of data can offer valuable insights. For instance, a spike in one type of alert could correlate with another type of activity in the system, shedding light on multi-stage attack campaigns or diversion strategies.</p>
<pre><code># Finding correlation between an increase in login attempts and data exfiltration activities
correlation_value = df['login_attempts'].corr(df['data_exfil_activity'])
</code></pre>
<p>This analysis, with the help of pandas <a href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.corr.html">corr</a>, can help in discerning whether multiple seemingly isolated activities are part of a coordinated attack chain.</p>
<p>Correlation also does not have to be metric-driven either. When analyzing threats, it is easy to find value and new insights by comparing older findings to the new ones.</p>
<h3 id="machinelearninganomalydetection">Machine learning &amp; anomaly detection</h3>
<p>With the vast volume of data, manual analysis becomes impractical. Machine learning can assist in identifying patterns and anomalies that might escape the human eye. Algorithms like <a href="https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html">Isolation Forest</a> or <a href="https://scikit-learn.org/stable/modules/neighbors.html">K-nearest neighbor</a>(KNN) are commonly used to spot deviations or clusters of commonly related data.</p>
<pre><code>from sklearn.ensemble import IsolationForest

# Assuming 'feature_set' contains relevant metrics for analysis
clf = IsolationForest(contamination=0.05)
anomalies = clf.fit_predict(feature_set)
</code></pre>
<p>Here, the anomalies variable will flag data points that deviate from the norm, helping analysts pinpoint unusual behavior swiftly.</p>
<h3 id="behavioralpatternsendpointdataanalysis">Behavioral patterns &amp; endpoint data analysis</h3>
<p>Analyzing endpoint behavioral data collected from detection rules allows us to unearth overarching patterns and trends that can be indicative of broader threat landscapes, cyber campaigns, or evolving attacker TTPs.</p>
<p><strong>Tactic progression patterns:</strong> By monitoring the sequence of detected behaviors over time, we can spot patterns in how adversaries move through their attack chain. For instance, if there's a consistent trend where initial access techniques are followed by execution and then lateral movement, it's indicative of a common attacker playbook being employed.</p>
<p><strong>Command-line trend analysis:</strong> Even within malicious command-line arguments, certain patterns or sequences can emerge. Monitoring the most frequently detected malicious arguments can give insights into favored attack tools or scripts.</p>
<p>Example:</p>
<pre><code># Most frequently detected malicious command lines
top_malicious_commands = df.groupby('malicious_command_line').size()
 .sort_values(ascending=False).head(10)
</code></pre>
<p><strong>Process interaction trends:</strong> While individual parent-child process relationships can be malicious, spotting trends in these interactions can hint at widespread malware campaigns or attacker TTPs. For instance, if a large subset of endpoints is showing the same unusual process interaction, it might suggest a common threat.</p>
<p><strong>Temporal behavior patterns:</strong> Just as with other types of data, the temporal aspect of endpoint behavioral data can be enlightening. Analyzing the frequency and timing of certain malicious behaviors can hint at attacker operational hours or campaign durations.</p>
<p>Example:</p>
<pre><code># Analyzing frequency of a specific malicious behavior over time
monthly_data = df.pivot_table(index='timestamp', columns='tactic', values='count', aggfunc='sum').resample('M').sum()

ax = monthly_data[['execution', 'defense-evasion']].plot(kind='bar', stacked=False, figsize=(12,6))

plt.title("Frequency of 'execution' and 'defense-evasion' Tactics Over Time")

plt.ylabel("Count")
ax.set_xticklabels([x.strftime('%B-%Y') for x in monthly_data.index])
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb547a07a9f16aa12/6a7d80f6e3a21971e799c716/image11.png" alt="Note: This image is from example data and not from the Global Threat Report" title="Note: This image is from example data and not from the Global Threat Report" />
Note: This image is from example data and not from the Global Threat Report</p>
<p>By aggregating and analyzing endpoint behavioral data at a macro level, we don't just identify isolated threats but can spot waves, trends, and emerging patterns. This broader perspective empowers cybersecurity teams to anticipate, prepare for, and counter large-scale cyber threats more effectively.</p>
<p>While these are some examples of how to perform trend analysis, there is no right or wrong approach. Every analyst has their own preference or set of questions they or stakeholders may want to ask. Here are some additional questions or queries analysts may have for cybersecurity data when doing trend analysis.</p>
<ul>
<li>What are the top three tactics being leveraged by adversaries this quarter?</li>
<li>Which detection rules are triggering the most, and is there a common thread?</li>
<li>Are there any time-based patterns in endpoint alerts, possibly hinting at an adversary's timezone?</li>
<li>How have cloud alerts evolved with the migration of more services to the cloud?</li>
<li>Which malware families are becoming more prevalent, and what might be the cause?</li>
<li>Do the data patterns suggest any seasonality, like increased activities towards year-end?</li>
<li>Are there correlations between external events and spikes in cyber activities?</li>
<li>How does the weekday data differ from weekends in terms of alerts and attacks?</li>
<li>Which organizational assets are most targeted, and are their defenses up-to-date?</li>
<li>Are there any signs of internal threats or unusual behaviors among privileged accounts?</li>
</ul>
<p>Trend analysis in cybersecurity is a dynamic process. While we've laid down some foundational techniques and questions, there are myriad ways to approach this vast domain. Each analyst may have their preferences, tools, and methodologies, and that's perfectly fine. The essence lies in continuously evolving and adapting to our approach while cognizantly being aware of the ever-changing threat landscape for each ecosystem exposed to threats.</p>
<h2 id="reductionstreamliningforclarity">Reduction: Streamlining for clarity</h2>
<p>Having progressed through the initial stages of our data analysis, we now enter the next phase: reduction. This step is about refining and concentrating our comprehensive data into a more digestible and focused format.</p>
<p>Recap of the Analysis Journey So Far:</p>
<ul>
<li><strong>Extraction:</strong> The initial phase involved setting up our Google Cloud environment and selecting relevant datasets for our analysis.</li>
<li><strong>Pre-processing and transformation:</strong> At this stage, the data was extracted, processed, and transformed within our Colab notebooks, preparing it for detailed analysis.</li>
<li><strong>Trend analysis:</strong> This phase provided in-depth insights into cyber attack tactics, techniques, and malware, forming the core of our analysis.</li>
</ul>
<p>While the detailed data in our Colab Notebooks is extensive and informative for an analyst, it might be too complex for a broader audience. Therefore, the reduction phase focuses on distilling this information into a more concise and accessible form. The aim is to make the findings clear and understandable, ensuring that they can be effectively communicated and utilized across various departments or stakeholders.</p>
<h3 id="selectingandaggregatingkeydatapoints">Selecting and aggregating key data points</h3>
<p>In order to effectively communicate our findings, we must tailor the presentation to the audience's needs. Not every stakeholder requires the full depth of collected data; many prefer a summarized version that highlights the most actionable points. This is where data selection and aggregation come into play, focusing on the most vital elements and presenting them in an accessible format.</p>
<p>Here's an example of how to use Pandas to aggregate and condense a dataset, focusing on key aspects of endpoint behavior:</p>
<pre><code>required_endpoint_behavior_cols = ['rule_name','host_os_type','tactic_name','technique_name']


reduced_behavior_df = df.groupby(required_endpoint_behavior_cols).size()
 .reset_index(name='count')
 .sort_values(by="count", ascending=False)
 .reset_index(drop=True)

columns = {
    'rule_name': 'Rule Name', 
    'host_os_type': 'Host OS Type',
    'tactic_name': 'Tactic', 
    'technique_name': 'Technique', 
    'count': 'Alerts'
}

reduced_behavior_df = reduced_behavior_df.rename(columns=columns)
</code></pre>
<p>One remarkable aspect of this code and process is the flexibility it offers. For instance, we can group our data by various data points tailored to our needs. Interested in identifying popular tactics used by adversaries? Group by the MITRE ATT&amp;CK tactic. Want to shed light on masquerading malicious binaries? Revisit extraction to add more Elastic Common Schema (ECS) fields such as file path, filter on Defense Evasion, and aggregate to reveal the commonly trodden paths. This approach ensures we create datasets that are both enlightening and not overwhelmingly rich, tailor-made for stakeholders who wish to understand the origins of our analysis.</p>
<p>This process involves grouping the data by relevant categories such as rule name, host OS type, and MITRE ATT&amp;CK tactics and techniques and then counting the occurrences. This method helps in identifying the most prevalent patterns and trends in the data.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9625d74c7b5f2126/6a7d80f977b034f3123fc65e/image5.png" alt="Diagram example of data aggregation to obtain reduced dataset" title="Diagram example of data aggregation to obtain reduced dataset" />
Diagram example of data aggregation to obtain reduced dataset</p>
<h3 id="exportingreduceddatatogooglesheetsforaccessibility">Exporting reduced data to Google Sheets for accessibility</h3>
<p>The reduced data, now stored as a dataframe in memory, is ready to be exported. We use Google Sheets as the platform for sharing these insights because of its wide accessibility and user-friendly interface. The process of exporting data to Google Sheets is straightforward and efficient, thanks to the integration with Google Cloud services.</p>
<p>Here's an example of how the data can be uploaded to Google Sheets using Python from our Colab notebook:</p>
<pre><code>auth.authenticate_user()
credentials, project = google.auth.default()
gc = gspread.authorize(credentials)
workbook = gc.open_by_key("SHEET_ID")
behavior_sheet_name = 'NAME_OF_TARGET_SHEET'
endpoint_behavior_worksheet = workbook.worksheet(behavior_sheet_name)
set_with_dataframe(endpoint_behavior_worksheet, reduced_behavior_df)
</code></pre>
<p>With a few simple lines of code, we have effectively transferred our data analysis results to Google Sheets. This approach is widely used due to its accessibility and ease of use. However, there are multiple other methods to present data, each suited to different requirements and audiences. For instance, some might opt for a platform like <a href="https://cloud.google.com/looker?hl=en">Looker</a> to present the processed data in a more dynamic dashboard format. This method is particularly useful for creating interactive and visually engaging presentations of data. It ensures that even stakeholders who may not be familiar with the technical aspects of data analysis, such as those working in Jupyter Notebooks, can easily understand and derive value from the insights.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc2f9d97cf65c29a7/6a7d80fd63e959894473aea8/image7.png" alt="Results in Google Sheet" title="Results in Google Sheet" /></p>
<p>This streamlined process of data reduction and presentation can be applied to different types of datasets, such as cloud SIEM alerts, endpoint behavior alerts, or malware alerts. The objective remains the same: to simplify and concentrate the data for clear and actionable insights.</p>
<h2 id="presentationshowcasingtheinsights">Presentation: Showcasing the insights</h2>
<p>After meticulously refining our datasets, we now focus on the final stage: the presentation. Here we take our datasets, now neatly organized in platforms like Google Sheets or Looker, and transform them into a format that is both informative and engaging.</p>
<h3 id="pivottablesforindepthanalysis">Pivot tables for in-depth analysis</h3>
<p>Using pivot tables, we can create a comprehensive overview of our trend analysis findings. These tables allow us to display data in a multi-dimensional manner, offering insights into various aspects of cybersecurity, such as prevalent MITRE ATT&amp;CK tactics, chosen techniques, and preferred malware families.</p>
<p>Our approach to data visualization involves:</p>
<ul>
<li><strong>Broad overview with MITRE ATT&amp;CK tactics:</strong> Starting with a general perspective, we use pivot tables to overview the different tactics employed in cyber threats.</li>
<li><strong>Detailed breakdown:</strong> From this panoramic view, we delve deeper, creating separate pivot tables for each popular tactic and then branching out into detailed analyses for each technique and specific detection rule.</li>
</ul>
<p>This methodical process helps to uncover the intricacies of detection logic and alerts, effectively narrating the story of the cyber threat landscape.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt67ea738a1c534480/6a7d810042a1174cf4959127/image1.png" alt="Diagram showcasing aggregations funnel into contextual report information" title="Diagram showcasing aggregations funnel into contextual report information" />
Diagram showcasing aggregations funnel into contextual report information</p>
<p><strong>Accessibility across audiences:</strong> Our data presentations are designed to cater to a wide range of audiences, from those deeply versed in data science to those who prefer a more straightforward understanding. The Google Workspace ecosystem facilitates the sharing of these insights, allowing pivot tables, reduced datasets, and other elements to be easily accessible to all involved in the report-making process.</p>
<p><strong>Integrating visualizations into reports:</strong> When crafting a report, for example, in Google Docs, the integration of charts and tables from Google Sheets is seamless. This integration ensures that any modifications in the datasets or pivot tables are easily updated in the report, maintaining the efficiency and coherence of the presentation.</p>
<p><strong>Tailoring the presentation to the audience:</strong> The presentation of data insights is not just about conveying information; it's about doing so in a visually appealing and digestible manner. For a more tech-savvy audience, an interactive Colab Notebook with dynamic charts and functions may be ideal. In contrast, for marketing or design teams, a well-designed dashboard in Looker might be more appropriate. The key is to ensure that the presentation is clear, concise, and visually attractive, tailored to the specific preferences and needs of the audience.</p>
<h2 id="conclusionreflectingonthedataanalysisjourney">Conclusion: Reflecting on the data analysis journey</h2>
<p>As we conclude, it's valuable to reflect on the territory we've navigated in analyzing cyber threat data. This journey involved several key stages, each contributing significantly to our final insights.</p>
<h3 id="journeythroughgooglescloudecosystem">Journey through Google's Cloud ecosystem</h3>
<p>Our path took us through several Google Cloud services, including GCP, GCE, Colab Notebooks, and Google Workspace. Each played a pivotal role:</p>
<p><strong>Data exploration:</strong> We began with a set of cyber-related questions we wanted to answer and explored what vast datasets we had available to us. In this blog, we focused solely on telemetry being available in BigQuery.
<strong>Data extraction:</strong> We began by extracting raw data, utilizing BigQuery to efficiently handle large volumes of data. Extraction occurred in both BigQuery and from within our Colab notebooks.
<strong>Data wrangling and processing:</strong> The power of Python and the pandas library was leveraged to clean, aggregate, and refine this data, much like a chef skillfully preparing ingredients.
<strong>Trend analysis:</strong> We then performed trend analysis on our reformed datasets with several methodologies to glean valuable insights into adversary tactics, techniques, and procedures over time.
<strong>Reduction:</strong> Off the backbone of our trend analysis, we aggregated our different datasets by targeted data points in preparation for presentation to stakeholders and peers.
<strong>Transition to presentation:</strong> The ease of moving from data analytics to presentation within a web browser highlighted the agility of our tools, facilitating a seamless workflow.</p>
<h3 id="modularityandflexibilityinworkflow">Modularity and flexibility in workflow</h3>
<p>An essential aspect of our approach was the modular nature of our workflow. Each phase, from data extraction to presentation, featured interchangeable components in the Google Cloud ecosystem, allowing us to tailor the process to specific needs:</p>
<p><strong>Versatile tools:</strong> Google Cloud Platform offered a diverse range of tools and options, enabling flexibility in data storage, analysis, and presentation.
<strong>Customized analysis path:</strong> Depending on the specific requirements of our analysis, we could adapt and choose different tools and methods, ensuring a tailored approach to each dataset.
<strong>Authentication and authorization:</strong> Due to our entities being housed in the Google Cloud ecosystem, access to different tools, sites, data, and more was all painless, ensuring a smooth transition between services.</p>
<h3 id="orchestrationandtoolsynchronization">Orchestration and tool synchronization</h3>
<p>The synergy between our technical skills and the chosen tools was crucial. This harmonization ensured that the analytical process was not only effective for this project but also set the foundation for more efficient and insightful future analyses. The tools were used to augment our capabilities, keeping the focus on deriving meaningful insights rather than getting entangled in technical complexities.</p>
<p>In summary, this journey through data analysis emphasized the importance of a well-thought-out approach, leveraging the right tools and techniques, and the adaptability to meet the demands of cyber threat data analysis. The end result is not just a set of findings but a refined methodology that can be applied to future data analysis endeavors in the ever-evolving field of cybersecurity.</p>
<h2 id="calltoactionembarkingonyourowndataanalyticsjourney">Call to Action: Embarking on your own data analytics journey</h2>
<p>Your analytical workspace is ready! What innovative approaches or experiences with Google Cloud or other data analytics platforms can you bring to the table? The realm of data analytics is vast and varied, and although each analyst brings a unique touch, the underlying methods and principles are universal.</p>
<p>The objective is not solely to excel in your current analytical projects but to continually enhance and adapt your techniques. This ongoing refinement ensures that your future endeavors in data analysis will be even more productive, enlightening, and impactful. Dive in and explore the world of data analytics with Google Cloud!</p>
<p>We encourage any feedback and engagement for this topic! If you prefer to do so, feel free to engage us in Elastic’s public <a href="https://elasticstack.slack.com/archives/C018PDGK6JU">#security</a> Slack channel.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/google-cloud-for-cyber-data-analytics</link>
    <guid isPermaLink="false">google-cloud-for-cyber-data-analytics</guid>
    <category><![CDATA[Cloud Security]]></category>
    <dc:creator><![CDATA[Terrance DeJesus,Eric Forte]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt76c9f922dabd04da/6a7d81035588ad2bb7ee42fa/photo-edited-12.png" length="0" type="image/png"/>
    <pubDate>Thu, 14 Dec 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Security operations: Cloud monitoring and detection with Elastic Security]]></title>
    <description><![CDATA[As companies migrate to cloud, so too do opportunist adversaries. That's why our Elastic Security team members have created free detection rules for protecting users' cloud platforms like AWS and Okta. Learn more in this blog post.]]></description>
    <content:encoded><![CDATA[<p>As many organizations have migrated their infrastructure, applications, and data to cloud offerings, adversaries have extended their operational capabilities in cloud environments to achieve their mission — whether that means stealing intellectual property, disrupting business operations, or holding an organization's data for ransom. In order to protect our users' data from attack, the Elastic Security Intelligence &amp; Analytics Team researches and develops <a href="https://www.elastic.co/blog/elastic-security-opens-public-detection-rules-repo">rules</a> to detect attacker behavior in the cloud <em>and</em> on the endpoint.</p>
<p>In this post, we'll discuss cloud monitoring and detection-related challenges security operations teams face, and why attacks against cloud environments are often successful. We will share details on our free cloud detection rules (including many new ones released in <a href="https://www.elastic.co/blog/whats-new-elastic-security-7-9-0-free-endpoint-security">Elastic Security 7.9</a>) and show how they can help <a href="https://www.elastic.co/security">Elastic Security</a> users.</p>
<p>We'll also explain how Elastic can ingest logs from a wide variety of cloud platforms and how the Elastic Common Schema (ECS) makes searching, monitoring, and detection easy for defenders.</p>
<h2 id="cloudmonitoringanddetectionchallenges">Cloud monitoring and detection challenges</h2>
<p>Security teams typically encounter one or more of the following challenges when they're asked to monitor, detect, and respond to threats in their organization's cloud environments:</p>
<ul>
<li><strong>Resource constraints:</strong> It can take a considerable amount of time to learn and understand cloud technologies and their ever-changing data sources. Many security operations teams do not have the resources to allocate to this ongoing effort.</li>
<li><strong>Understanding of adversary tradecraft:</strong> Attacker behavior on well-known platforms such as Windows has been researched extensively and shared with the security community. Security teams may not have an in-depth understanding of how adversaries operate in cloud environments or the ability to provision a test environment to practice offensive and defensive techniques to protect their organization.</li>
<li><strong>Blind spots:</strong> For effective monitoring and detection, the data available to security practitioners must be relevant, accurate, and timely. Cloud logs shipped to a SIEM can be used for detection and response as long as the security team can depend on the quality of the data.</li>
<li><strong>Data normalization:</strong> Most cloud platforms have their own log categories and event schema. Normalizing logs into a common schema is not a trivial or one-off task. Some security teams, for example, have several different field names for a hostname across their data sources indexed in their SIEM. Without a normalized and documented schema, it can be difficult for analysts — especially less experienced ones — to write search queries and correlate events across data sources effectively.</li>
</ul>
<h2 id="ingestingandsearchingcloudlogswithelastic">Ingesting and searching cloud logs with Elastic</h2>
<p>Elastic has a large collection of Filebeat <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html">modules</a> that can be used to simplify the collection, parsing, and visualization of many diverse log formats into a common schema — including cloud platforms such as <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-aws.html">Amazon Web Services (AWS)</a>, <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-azure.html">Azure</a>, <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-okta.html">Okta</a>, and <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-o365.html">Office 365</a>. Rapid development of new Filebeat modules is an ongoing process.</p>
<p>The <a href="https://www.elastic.co/guide/en/ecs/current/ecs-reference.html">Elastic Common Schema</a> (ECS) defines a common set of fields for ingesting logs from a connected data source (e.g., AWS/Okta) into Elasticsearch. Log data is normalized into a format where the various field names can be used in queries to correlate behavior across data sources. This is useful to security and IT operations teams for a number of reasons.</p>
<p>Practitioners and administrators do not need to spend countless hours transforming or normalizing their ingested logs so that the field names follow their own common schema. Managing a schema like this yourself is no small undertaking and is a continuous effort. Elastic manages ECS (saving users time and resources) so that security teams can rely on a common set of field names to search their data quickly and efficiently.</p>
<p>End users can rely on using the same field names in their queries when searching across multiple data sources, which presents the following advantages:</p>
<ul>
<li>Having a consistent schema for searching saves security analysts time and lowers the barrier to entry for new analysts. Analysts don't have to learn or remember all of the different field names and their purpose for each data source.</li>
<li>Analysts can correlate events across data sources such as endpoint, proxy, and firewall, which helps them ask questions of their data more efficiently and make sound decisions during an investigation, incident, or hunt.</li>
<li>It's easy for analysts to produce a timeline or build a visualization of the activity that occurred.</li>
</ul>
<h2 id="detectingattackersoperatingincloudenvironments">Detecting attackers operating in cloud environments</h2>
<p>The Elastic Security Intelligence &amp; Analytics Team's research into adversary tradecraft leads to new detection features like rules and machine learning jobs — capabilities that enable small security teams to have an outsized impact. Security features like these increase the cost of an attack for adversaries. Elastic Security users can expect to see a continued focus on increasing the cost of cloud attacks.</p>
<p>In the remainder of this blog post, we'll simulate attack techniques against AWS and Okta cloud environments. We'll review the alerts that are generated by the suspicious activity and how an analyst can perform initial triage and complete their investigation using Elastic Security. We will also demonstrate how analysts can add exceptions to detection rules in order to filter benign events and continue to alert on suspicious behavior.</p>
<h2 id="monitoringawscloudtraillogstodetectsuspiciousbehavior">Monitoring AWS CloudTrail logs to detect suspicious behavior</h2>
<p>As organizations migrate to or provision new infrastructure in cloud platforms like AWS, they face the common challenges that we described earlier. Fortunately, Elastic Security has a <a href="https://github.com/elastic/detection-rules/tree/main/rules/aws">strong variety of AWS rules</a>, available for <a href="https://www.elastic.co/blog/whats-new-elastic-security-7-9-0-free-endpoint-security">free in 7.9</a> to detect suspicious behaviors in an AWS environment.</p>
<p>The Filebeat <a href="https://www.elastic.co/guide/en/beats/filebeat/master/filebeat-module-aws.html">module</a> for AWS helps you easily ship CloudTrail, Simple Storage Service (S3), Elastic Load Balancing (ELB), and virtual private cloud (VPC) flow logs to Elasticsearch for monitoring and detection in Elastic Security. Let's walk through an attack and defense scenario utilizing CloudTrail data. <a href="https://aws.amazon.com/cloudtrail/">CloudTrail</a> provides event history of your AWS account activity, including actions taken through the AWS Management Console, AWS software development kits (SDKs), command line tools, and other AWS services. This event history can help simplify security detection, analysis, and investigations.</p>
<p>Many attacks against AWS start with an attacker obtaining an access key and/or the secret access key details. These keys may be harvested in a variety of ways, including through phishing, a data breach, GitHub repositories, screenshots, error messages, snapshot data, or simply poor key management practices. By obtaining these keys, an attacker can take a variety of actions against your AWS infrastructure.</p>
<p>Let's walk through one of the many potential attack scenarios that could play out. In the following example, the adversary enumerates the trails and monitoring capabilities that have been configured for the AWS account. They follow up on this activity by disabling a trail and a configuration recorder in an attempt to evade detections and then proceed to harvest secrets.</p>
<h3 id="simulatingadversarybehaviorinaws">Simulating adversary behavior in AWS</h3>
<p>In this demonstration, we'll use <a href="https://github.com/RhinoSecurityLabs/pacu">Pacu</a> to perform our attack. Pacu is a popular framework for exploiting AWS infrastructure, developed and maintained by Rhino Security Labs. Pacu is modular, similar to other exploitation frameworks like Metasploit and Koadic, and enables attackers to exploit configuration flaws within an AWS account. Attackers can use Pacu to check if the required permissions are assigned to the compromised account before attempting to execute a module. This can be helpful from an attacker's perspective to not create unnecessary noise and logs, and draw additional attention from defenders by running modules that will ultimately fail.</p>
<p>The attacker begins by enumerating services using the detection__enum_services module to determine what logging and monitoring services are enabled for the AWS account.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2445da64c7f0c9aa/6a7d7e1f51156a014c2bf7e9/1-enumerating-services-blog-secops-cloud-platform-monitoring.jpg" alt="Figure 1 - Enumerating services using Pacu’s detection__enum_services module " title="Figure 1 - Enumerating services using Pacu’s detection__enum_services module" /></p>
<p>The attacker discovered eight trails, as well as ten configuration rules, a recorder, and a delivery channel. Essentially, the enumeration script is querying certain AWS API calls to list or describe relevant information about the environment. By reviewing the <a href="https://github.com/RhinoSecurityLabs/pacu/blob/master/modules/detection__enum_services/main.py">code</a> of the module, we can see the targeted APIs:</p>
<pre><code>DescribeSubscription
GetSubscriptionState
DescribeTrails
ListDetectors
DescribeConfigRules
DescribeConfigurationRecorders
DescribeConfigurationRecorderStatus
DescribeDeliveryChannels
DescribeDeliveryChannelStatus
DescribeConfigurationAggregators
DescribeAlarms
DescribeFlowLogs
</code></pre>
<p>After the attacker determines which services are running, their next logical step may be to interrupt logging and monitoring by disabling a trail, alarm, detector, or recorder in an attempt to evade detection. To accomplish this objective, we'll use a different module called detection__disruption to disable a trail called brentlog, and stop the configuration recorder named default.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta6c2c596809db5f7/6a7d7e228fc2d07bee3eb80b/2-disabling-trail-blog-secops-cloud-platform-monitoring.jpg" alt="Figure 2 - Disabling a trail and stopping a configuration recorder using Pacu’s detection__disruption module " title="Figure 2 - Disabling a trail and stopping a configuration recorder using Pacu’s detection__disruption module" /></p>
<p>At this point, with trail logging suspended and the configuration recorder turned off from tracking changes to resources, the attacker may want to check if there are any credentials, API keys, or tokens available in <a href="https://aws.amazon.com/about-aws/whats-new/2018/04/introducing-aws-secrets-manager/#:~:text=AWS%20Secrets%20Manager%20is%20a,other%20secrets%20throughout%20their%20lifecycle.">Secrets Manager</a> and if so, collect them. In this scenario, the attacker uses the enum_secrets module and finds one secret in the directory, /sessions/brent/downloads/secrets/secrets_manager. Harvesting these secrets could help the adversary achieve lateral movement and/or privilege escalation.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfa9228880b614597/6a7d7e242f00b24c1befbe3a/3-searching-aws-blog-secops-cloud-platform-monitoring.jpg" alt="Figure 3 - Searching for AWS secrets using Pacu's enum__secrets module" title="Figure 3 - Searching for AWS secrets using Pacu's enum__secrets module" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bde01ed27e6e784/6a7d7e27bdcff059f8c3ffd5/4-viewing-aws-blog-secops-cloud-platform-monitoring.jpg" alt="Figure 4 - Viewing the AWS secret after its discovery" title="Figure 4 - Viewing the AWS secret after its discovery" /></p>
<p>We'll stop our fictitious attack scenario here, but if you're curious to learn what the attacker could do next, the following Google search will return some examples: intitle:"AWS" intext:("attack" | "breach"). In the next section, we'll look at what this behavior looks like from a defender's perspective and how Elastic Security can be used to detect this behavior.</p>
<h3 id="detectingandinvestigatingthesuspiciousbehaviorinaws">Detecting and investigating the suspicious behavior in AWS</h3>
<p>While monitoring the usage of the previously mentioned APIs, it can be difficult to distinguish benign activity from suspicious behavior, such as an attacker enumerating an environment. In production environments, monitoring for calls to these APIs can be noisy, as the behavior is quite common. To help find this rare and potentially suspicious behavior, and in addition to the AWS detection rules we have available, we've released <a href="https://github.com/elastic/detection-rules/tree/main/rules/ml">machine learning</a> jobs in 7.9 specifically for AWS CloudTrail that help identify outliers, such as patterns of unusual activity that are hard to find using conventional detection rules.</p>
<p>Looking at our detections page from the previous attack, we can see multiple alerts were triggered. Our free built-in detection rules identified the techniques of <em>suspending a trail</em>, <em>stopping a configuration recorder</em>, and <em>grabbing sensitive information from the secrets manager</em>. The other alerts are from the machine learning jobs of <a href="https://www.elastic.co/guide/en/security/7.9/unusual-city-for-an-aws-command.html"><em>Unusual Country For an AWS Command</em></a> and <a href="https://www.elastic.co/guide/en/security/master/unusual-aws-command-for-a-user.html"><em>Unusual AWS Command for a User</em></a> which identify a geolocation (country) that is unusual for the command or a user context that does not normally use the command.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfbac51dab0c68105/6a7d7e2a51156a2a132bf7ed/5-viewing-detection-alerts-blog-secops-cloud-platform-monitoring.jpg" alt="Figure 5 - Viewing the detection alerts in Elastic Security" title="Figure 5 - Viewing the detection alerts in Elastic Security" /></p>
<p>If we pivot into one of the machine learning alerts, we can see a description of what it detected, along with a built-in investigation guide to walk an analyst through a potential workflow when analyzing an unusual CloudTrail event.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte502455b7c1f9453/6a7d7e2d4c4bfb30dfcca7bc/6-machine-learning-alert-blog-secops-cloud-platform-monitoring.jpg" alt="Figure 6 - Viewing the details of a machine learning alert" title="Figure 6 - Viewing the details of a machine learning alert" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd3c551015c7a5918/6a7d7e308fc2d030513eb811/7-viewing-investigation-notes-blog-secops-cloud-platform-monitoring.png" alt="Figure 7 - Viewing the investigation notes for an unusual CloudTrail event" title="Figure 7 - Viewing the investigation notes for an unusual CloudTrail event" /></p>
<p>Let's also take a look at the details in the Timeline view from the <a href="https://www.elastic.co/guide/en/security/master/aws-configuration-recorder-stopped.html"><em>AWS Configuration Recorder Stopped</em></a> alert. The fields I'm particularly interested in are the API call, user agent string, user identity type, request parameters, and the raw text of the entire event.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba913025b586065c/6a7d7e33e3a219631e99c69d/8-alert-details-timeline-blog-secops-cloud-platform-monitoring.png" alt="Figure 8 - Analyzing the alert details in the Timeline" title="Figure 8 - Analyzing the alert details in the Timeline" /></p>
<p>By analyzing the alert, we're able to quickly determine:</p>
<p>|                    |                                                                                                                                                                                                                                                      |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Field              | Description                                                                                                                                                                                                                                          |
| event.action       | Tells us the AWS API call that was made, StopConfigurationRecorder                                                                                                                                                                                   |
| request_parameters | Gives us the details about what was sent in the request, in our case, the configuration recorder name, default                                                                                                                                       |
| user.name          | Informs us as to who made the request, pacu                                                                                                                                                                                                          |
| user_identity.type | Contains details about the type of Identity and Access Management (IAM) identity. In our case, an IAMUser. Root is another user identity type we have built in rules for.                                                                            |
| user_agent         | The value of the HTTP User-Agent header. User agent strings can be easily modified, but if an account typically uses the AWS Java SDK for their API calls, and it changes, then the detection of the anomalous user agent string can be a quick win. |
| event.original     | Gives us the raw alert details                                                                                                                                                                                                                       |</p>
<p><em>Table 1 - Analysis of alert fields</em></p>
<p>After analyzing the alert, we can start to piece together the events and look at what actions the user took just before our alerts fired (and afterwards as applicable). Again, we can spot the attackers enumeration here as well.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt68aa0e610ebd993a/6a7d7e3696b5a66f1787859f/9-event-history-blog-secops-cloud-platform-monitoring.png" alt="Figure 9 - Viewing event history for the user Pacu in the Timeline " title="Figure 9 - Viewing event history for the user Pacu in the Timeline" /></p>
<p>We may also want to search our environment for specific API calls to see if they were invoked by other users or hosts, from different IPs, or at other time frames that would be suspicious in our environment.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcc259ce7764b007e/6a7d7e3abdcff074e5c3ffd9/10-api-history-blog-secops-cloud-platform-monitoring.png" alt="Figure 10 - Viewing API call history for the StopConfigurationRecorder API in the Timeline " title="Figure 10 - Viewing API call history for the StopConfigurationRecorder API in the Timeline" /></p>
<p>We can also create a visualization to look for the least common API calls in our environment and pivot from there. For AWS, the API calls are in the event.action field.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt084ac25f099dfa4b/6a7d7e3c96b5a6ef888785a3/11-visualization-api-calls-blog-secops-cloud-platform-monitoring.png" alt="Figure 11 - Using a visualization to look for least common API calls in our environment " title="Figure 11 - Using a visualization to look for least common API calls in our environment" /></p>
<p>As demonstrated, our free built-in rules for AWS can detect this activity as well as a number of other potential attack scenarios. We've opened up our <a href="https://github.com/elastic/detection-rules">rules repository</a> and encourage you to have a look and learn how to <a href="https://github.com/elastic/detection-rules#how-to-contribute">contribute</a> if interested.</p>
<h2 id="detectingsuspiciousbehaviorinoktalogs">Detecting suspicious behavior in Okta logs</h2>
<p><a href="https://www.okta.com/products/single-sign-on/">Okta single sign-on (SSO)</a> is a cloud solution that allows users to log into a variety of systems in their organization via a centralized process using a single user account. Informing end users that they only have to remember one username and password instead of ten or more reduces the risk that they'll adopt poor password hygiene and enables system administrators to enforce stronger password policies. Further, multi-factor authentication (MFA) policies can be configured in Okta, which raises the barriers to entry for attackers. Many attackers will simply move on to look for an easier target when they discover that MFA is enforced for their target's network or user account.</p>
<p>While SSO solutions can provide a convenient user experience and reduce cybersecurity risk for an organization, these centralized systems that offer a type of skeleton key to many systems and applications are often an attractive target for attackers. For example, if an adversary manages to harvest an Okta administrator's credentials or API token, they could attempt to perform any of the actions in the non-exhaustive list below:</p>
<ul>
<li>Modify or disable MFA policies for one or more applications in order to weaken their victim's security controls.</li>
<li>Create new user accounts or API tokens to maintain persistence in their target's environment and attempt to “blend in” and evade detection.</li>
<li>Modify, delete, or deactivate an Okta network zone to loosen the restrictions on which geolocation users or administrators can login from.</li>
<li>Delete or disable an application or other configuration to create a Denial-of-Service (DoS) condition and impact a company's business operations.</li>
</ul>
<p>To enable security teams to monitor their Okta environment for suspicious activity, our <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-okta.html">Okta Filebeat module</a> can pull <a href="https://developer.okta.com/docs/reference/api/system-log/">Okta System Log</a> events and ship them to Elasticsearch to be indexed. Okta's System Log records events related to an organization in order to provide an audit trail that can be used to understand platform activity. The Elastic Security Intelligence &amp; Analytics Team has <a href="https://github.com/elastic/detection-rules/tree/main/rules/okta">free rules</a> to detect suspicious activity in Okta logs and will continue adding more in future.</p>
<p>In the following example, imagine that an adversary has harvested an API token after gaining initial access to an organization's network. The API token has administrator privileges and the adversary executes some actions in their target's Oka environment:</p>
<ul>
<li>Create a new user account and assign administrative permissions to it in order to maintain a presence in the target environment should the security team discover that the current API token is compromised</li>
<li>Deactivate a sign-on policy in order to weaken the target's security controls</li>
<li>Disable a network zone to enable attackers to authenticate from any geographical location during their intrusion</li>
</ul>
<p>The Okta Filebeat module was configured to ship Okta System Log events to Elasticsearch and our Okta rules were activated in Elastic Security. The suspicious activity triggered three alerts shown in Figure 12 below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1be76b5bdf1f4fb8/6a7d7e3f5967e551cf5da497/12-okta-alerts-blog-secops-cloud-platform-monitoring.png" alt="Figure 12 - Okta alerts in Elastic Security generated by suspicious activity" title="Figure 12 - Okta alerts in Elastic Security generated by suspicious activity" /></p>
<p>Clicking on one of the alerts allows the analyst to review more information about the rule, including the description of the behavior that the rule detects, severity and risk scores, and the associated MITRE ATT&amp;CK® tactic and technique. The analyst can scroll further down the page and begin to investigate the alert in Timeline.</p>
<p>To learn more how Elastic supports ATT&amp;CK, see our presentation: <a href="https://youtu.be/2Hh5spqA6bw">How to Plan and Execute a Hunt</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcd233600fc5d2fee/6a7d7e436c6eac6aa3f112e2/13-rule-information-blog-secops-cloud-platform-monitoring.png" alt="Figure 13 - Viewing a rule's information and settings" title="Figure 13 - Viewing a rule's information and settings" /></p>
<p>Security practitioners know that every organization's network is different. Behavior that looks suspicious in one environment may be benign in another. To help security teams find the proverbial “signal in the noise,” users can add exceptions to their detection rules to filter benign events and continue to alert on suspicious events. Figure 14 shows an exception being added to an Okta rule.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt479de802d9fa2855/6a7d7e4651156a189b2bf7f1/14-adding-exception-blog-secops-cloud-platform-monitoring.jpg" alt="Figure 14 - Adding an exception to a rule in Elastic Security" title="Figure 14 - Adding an exception to a rule in Elastic Security" /></p>
<p>We've also introduced the "threshold" rule type. Threshold rules aggregate query results and generate an alert when the number of matched events exceeds a certain threshold. The example rule below will generate an alert when 25 Okta user authentication failures occur from a single source IP address. This can be indicative of a brute force or password spraying attack.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt547d925aa4b74189/6a7d7e49dd26d215602a7212/15-okta-brute-force-blog-secops-cloud-platform-monitoring.png" alt="Figure 15 - Reviewing a threshold rule configured to detect an Okta brute force attack" title="Figure 15 - Reviewing a threshold rule configured to detect an Okta brute force attack" /></p>
<p>Viewing an alert generated by a threshold rule in the Timeline allows an analyst to review the events that triggered the rule and begin their triage process or investigation.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltffa02066c6056b30/6a7d7e4cead8ec7746ba7ab1/16-reviewing-alert-blog-secops-cloud-platform-monitoring.png" alt="Figure 16 - Reviewing an alert from a failed Okta authentication threshold rule in Timeline" title="Figure 16 - Reviewing an alert from a failed Okta authentication threshold rule in Timeline" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>According to Verizon's latest <a href="https://enterprise.verizon.com/resources/reports/dbir/">Data Breach Investigations Report</a>, cloud assets were involved in 24% of the report's 3,950 data breaches reviewed last year. As organizations continue to migrate their data and business operations to the cloud, we can expect this number to increase.</p>
<p>In this blog post, we discussed some of the challenges that security teams face when attempting to monitor for, detect, and investigate suspicious behavior in their organization's cloud environments. We walked through some practical examples on how attackers operate in cloud environments and how Elastic Security can detect those techniques.</p>
<p>The Elastic Security Intelligence &amp; Analytics Team researches adversary tradecraft and develops new detection rules and machine learning jobs for multiple platforms including cloud. Our users can expect to see our continued focus on increasing the cost of cloud attacks.</p>
<p>Configuring our <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html">Filebeat modules</a> to ship logs to Elasticsearch and enable detection rules in Elastic Security is easy. Our <a href="https://github.com/elastic/detection-rules">free detection rules</a> help security teams monitor those logs and detect suspicious behavior, regardless of the size of their team. Elastic Security enables analysts to triage and investigate those alerts quickly and efficiently.</p>
<p>If you're interested in learning more about Elastic Security, you can <a href="https://www.elastic.co/security">download it for free</a> or sign up for a free 14-day trial of <a href="https://www.elastic.co/cloud/">Elastic Cloud</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/cloud-monitoring-and-detection-with-elastic-security</link>
    <guid isPermaLink="false">cloud-monitoring-and-detection-with-elastic-security</guid>
    <category><![CDATA[Cloud Security]]></category>
    <dc:creator><![CDATA[Brent Murphy,David French,Elastic Security Intelligence & Analytics Team]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt23836ecff5128248/6a7d7e4f448e4ec7495bdaad/blog-thumb-network-attack-map.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 30 Nov 2022 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>