Credential Access
T1539 — Steal Web Session Cookie
An adversary may steal web application or service session cookies and use them to gain access to web applications or Internet services as an authenticated user without needing credentials. Web applications and services often use session cookies as an authentication token after a user has authenticated to a website. Cookies are often valid for an extended period of time, even if the web application is not actively used...
Investigate Steal Web Session Cookie activity in the context of Credential Access: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.
Platforms
Linux, macOS, Office Suite, SaaS, Windows
Priority / status
high / complete
Evidence to collect
- Host or resource affected
- Account or identity involved
- Timestamp of the activity
- Related process, file, or network artifact
- Any preceding or follow-on alerts
D3-CCSA · detect
Credential Compromise Scope Analysis
Monitor for Credential Compromise Scope Analysis indicators relevant to this technique.
Tooling: Entra ID
D3-CH · harden
Credential Hardening
Apply Credential Hardening to reduce this technique's viability before an incident occurs.
Tooling: Entra ID
D3-CR · evict
Credential Revocation
Use Credential Revocation to remove the adversary's foothold once this technique is confirmed.
Tooling: Entra ID
D3-CTS · isolate
Credential Transmission Scoping
Apply Credential Transmission Scoping to contain the blast radius once this technique is observed.
Tooling: Entra ID
| ATT&CK Technique | D3FEND Technique | Practical SOC Action | Tooling |
|---|---|---|---|
| T1539 Steal Web Session Cookie | Credential Compromise Scope Analysis | Monitor for Credential Compromise Scope Analysis indicators relevant to this technique. | Entra ID |
| T1539 Steal Web Session Cookie | Credential Hardening | Apply Credential Hardening to reduce this technique's viability before an incident occurs. | Entra ID |
| T1539 Steal Web Session Cookie | Credential Revocation | Use Credential Revocation to remove the adversary's foothold once this technique is confirmed. | Entra ID |
| T1539 Steal Web Session Cookie | Credential Transmission Scoping | Apply Credential Transmission Scoping to contain the blast radius once this technique is observed. | Entra ID |
T1539 Steal Web Session Cookie → D3FEND → SOC action
Investigation steps — Microsoft
- Review Defender for Endpoint / Defender XDR alerts and timeline for the affected host or identity.
- Check Sentinel analytics rules and incidents correlated with this technique.
- Review Entra ID sign-in and audit logs if the technique involves an identity or cloud resource.
Investigation steps — generic
- Confirm whether the observed steal web session cookie activity matches expected administrative or application behaviour.
- Identify the host, account, or resource where the activity occurred and its business criticality.
- Check for related alerts before and after this activity to reconstruct the broader intrusion timeline.
- Real detection reference: "AiTM Session Cookie Theft" -- Flags the Adversary-in-the-Middle signature: a user completes MFA from one IP, then the same session authenticates single-factor from a different, distant IP shortly after - indicating a stolen session cookie.
Response actions
| Action | Risk | Automation safe | Approval required |
|---|---|---|---|
| Revoke ALL active sessions — Entra ID | Medium | No | Yes |
| Reset password + force MFA re-enrolment | Medium | No | Yes |
| Review and delete any inbox forwarding rules created | Low | Yes | No |
| Review and revoke any OAuth app consents granted | Medium | No | Yes |
| Deploy or verify: Conditional Access policy requiring compli | Low | No | Yes |
KQL
GEN-CA-004 — AiTM Session Cookie Theft
let TrustedRanges =
_GetWatchlist('TrustedVPNRanges')
| extend VPNRange = tostring(column_ifexists("SearchKey", column_ifexists("Subnet", "")))
| where isnotempty(VPNRange)
| summarize by VPNRange;
let MfaSignins = SigninLogs
| where TimeGenerated >= ago(1h)
| where ResultType == "0"
| where IPAddress !in (TrustedRanges)
| where tostring(AuthenticationRequirement) == "multiFactorAuthentication"
| extend Lat = todouble(LocationDetails.geoCoordinates.latitude), Lon = todouble(LocationDetails.geoCoordinates.longitude), City = tostring(LocationDetails.city)
| project TimeGenerated, UserPrincipalName, IPAddress, Lat, Lon, City, AppDisplayName;
MfaSignins
| join kind=inner (
SigninLogs
| where TimeGenerated >= ago(1h) and ResultType == "0"
| where IPAddress !in (TrustedRanges)
| where tostring(AuthenticationRequirement) == "singleFactorAuthentication"
| extend Lat2 = todouble(LocationDetails.geoCoordinates.latitude), Lon2 = todouble(LocationDetails.geoCoordinates.longitude), City2 = tostring(LocationDetails.city)
| project TimeGenerated2 = TimeGenerated, UserPrincipalName, IPAddress2 = IPAddress, Lat2, Lon2, City2, AppDisplayName2 = AppDisplayName
) on UserPrincipalName
| where TimeGenerated2 > TimeGenerated and IPAddress != IPAddress2
| where datetime_diff('minute', TimeGenerated2, TimeGenerated) <= 30
| extend DistKm = round(6371.0 * 2 * asin(sqrt(pow(sin((Lat2 - Lat) * pi() / 360), 2) + cos(Lat * pi() / 180) * cos(Lat2 * pi() / 180) * pow(sin((Lon2 - Lon) * pi() / 360), 2))), 0)
| where DistKm > 50
| distinct TimeGenerated2, UserPrincipalName, IPAddress, IPAddress2, City, City2, DistKm, AppDisplayName2
| extend timestamp = TimeGenerated2, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress2
| order by DistKm desc 33B07EAA-F451-4C38-AC9F-8AF3F7E99F0E — Cyble Vision Alerts Compromised Endpoint Cookies
Alerts_compromised_endpoints_cookies
| where Service == "compromised_endpoints_cookies"
| extend MappedSeverity = Severity Escalation criteria
- Steal Web Session Cookie activity observed on a privileged account or critical system.
- Activity follows or precedes other suspicious behaviour in the same investigation.
- Automated triage cannot confidently rule out malicious intent.
False positive considerations
- Legitimate administrative or maintenance activity matching this pattern.
- Approved security testing or red team exercise.
- Known benign software producing similar telemetry.
# T1539 - Steal Web Session Cookie
## SOC Recommendation
Investigate Steal Web Session Cookie activity in the context of Credential Access: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.
## D3FEND Mappings
| D3FEND Technique | Relationship | Practical SOC Action |
|---|---|---|
| Credential Compromise Scope Analysis | Detect | Monitor for Credential Compromise Scope Analysis indicators relevant to this technique. |
| Credential Hardening | Harden | Apply Credential Hardening to reduce this technique's viability before an incident occurs. |
| Credential Revocation | Evict | Use Credential Revocation to remove the adversary's foothold once this technique is confirmed. |
| Credential Transmission Scoping | Isolate | Apply Credential Transmission Scoping to contain the blast radius once this technique is observed. |
## Investigation Steps
1. Review Defender for Endpoint / Defender XDR alerts and timeline for the affected host or identity.
2. Check Sentinel analytics rules and incidents correlated with this technique.
3. Review Entra ID sign-in and audit logs if the technique involves an identity or cloud resource.
## Evidence to Collect
- Host or resource affected
- Account or identity involved
- Timestamp of the activity
- Related process, file, or network artifact
- Any preceding or follow-on alerts
## Response Actions
| Action | Risk | Automation Safe | Approval Required |
|---|---|---|---|
| Revoke ALL active sessions — Entra ID | Medium | No | Yes |
| Reset password + force MFA re-enrolment | Medium | No | Yes |
| Review and delete any inbox forwarding rules created | Low | Yes | No |
| Review and revoke any OAuth app consents granted | Medium | No | Yes |
| Deploy or verify: Conditional Access policy requiring compli | Low | No | Yes |
## KQL
```kql
let TrustedRanges =
_GetWatchlist('TrustedVPNRanges')
| extend VPNRange = tostring(column_ifexists("SearchKey", column_ifexists("Subnet", "")))
| where isnotempty(VPNRange)
| summarize by VPNRange;
let MfaSignins = SigninLogs
| where TimeGenerated >= ago(1h)
| where ResultType == "0"
| where IPAddress !in (TrustedRanges)
| where tostring(AuthenticationRequirement) == "multiFactorAuthentication"
| extend Lat = todouble(LocationDetails.geoCoordinates.latitude), Lon = todouble(LocationDetails.geoCoordinates.longitude), City = tostring(LocationDetails.city)
| project TimeGenerated, UserPrincipalName, IPAddress, Lat, Lon, City, AppDisplayName;
MfaSignins
| join kind=inner (
SigninLogs
| where TimeGenerated >= ago(1h) and ResultType == "0"
| where IPAddress !in (TrustedRanges)
| where tostring(AuthenticationRequirement) == "singleFactorAuthentication"
| extend Lat2 = todouble(LocationDetails.geoCoordinates.latitude), Lon2 = todouble(LocationDetails.geoCoordinates.longitude), City2 = tostring(LocationDetails.city)
| project TimeGenerated2 = TimeGenerated, UserPrincipalName, IPAddress2 = IPAddress, Lat2, Lon2, City2, AppDisplayName2 = AppDisplayName
) on UserPrincipalName
| where TimeGenerated2 > TimeGenerated and IPAddress != IPAddress2
| where datetime_diff('minute', TimeGenerated2, TimeGenerated) <= 30
| extend DistKm = round(6371.0 * 2 * asin(sqrt(pow(sin((Lat2 - Lat) * pi() / 360), 2) + cos(Lat * pi() / 180) * cos(Lat2 * pi() / 180) * pow(sin((Lon2 - Lon) * pi() / 360), 2))), 0)
| where DistKm > 50
| distinct TimeGenerated2, UserPrincipalName, IPAddress, IPAddress2, City, City2, DistKm, AppDisplayName2
| extend timestamp = TimeGenerated2, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress2
| order by DistKm desc
```
```kql
Alerts_compromised_endpoints_cookies
| where Service == "compromised_endpoints_cookies"
| extend MappedSeverity = Severity
```
## Escalation Criteria
- Steal Web Session Cookie activity observed on a privileged account or critical system.
- Activity follows or precedes other suspicious behaviour in the same investigation.
- Automated triage cannot confidently rule out malicious intent.
## False Positive Considerations
- Legitimate administrative or maintenance activity matching this pattern.
- Approved security testing or red team exercise.
- Known benign software producing similar telemetry.
Generated by SOC Response Atlas by Basyrix.
Want to push this directly to Confluence? Upgrade to Basyrix Pro.
- /api/techniques/T1539.json
- /api/recommendations/T1539.json
- /api/d3fend/T1539.json
- /api/mappings/T1539.json
- /api/confluence/T1539.md
Example curl:
curl https://atlas.basyrix.com/api/recommendations/T1539.json Response:
{
"technique_id": "T1539",
"name": "Steal Web Session Cookie",
"priority": "high",
"status": "complete",
"version": "0.1.0",
"last_reviewed": "2026-07-23",
"generated_by": "SOC Response Atlas by Basyrix",
"tactics": [
"Credential Access"
],
"platforms": [
"Linux",
"macOS",
"Office Suite",
"SaaS",
"Windows"
],
"summary": "An adversary may steal web application or service session cookies and use them to gain access to web applications or Internet services as an authenticated user without needing credentials. Web applications and services often use session cookies as an authentication token after a user has authenticated to a website. Cookies are often valid for an extended period of time, even if the web application is not actively used...",
"soc_recommendation": "Investigate Steal Web Session Cookie activity in the context of Credential Access: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.",
"d3fend_mappings": [
{
"id": "D3-CCSA",
"name": "Credential Compromise Scope Analysis",
"relationship": "detect",
"practical_action": "Monitor for Credential Compromise Scope Analysis indicators relevant to this technique.",
"tooling": [
"Entra ID"
]
},
{
"id": "D3-CH",
"name": "Credential Hardening",
"relationship": "harden",
"practical_action": "Apply Credential Hardening to reduce this technique's viability before an incident occurs.",
"tooling": [
"Entra ID"
]
},
{
"id": "D3-CR",
"name": "Credential Revocation",
"relationship": "evict",
"practical_action": "Use Credential Revocation to remove the adversary's foothold once this technique is confirmed.",
"tooling": [
"Entra ID"
]
},
{
"id": "D3-CTS",
"name": "Credential Transmission Scoping",
"relationship": "isolate",
"practical_action": "Apply Credential Transmission Scoping to contain the blast radius once this technique is observed.",
"tooling": [
"Entra ID"
]
}
],
"investigation_steps": {
"microsoft": [
"Review Defender for Endpoint / Defender XDR alerts and timeline for the affected host or identity.",
"Check Sentinel analytics rules and incidents correlated with this technique.",
"Review Entra ID sign-in and audit logs if the technique involves an identity or cloud resource."
],
"generic": [
"Confirm whether the observed steal web session cookie activity matches expected administrative or application behaviour.",
"Identify the host, account, or resource where the activity occurred and its business criticality.",
"Check for related alerts before and after this activity to reconstruct the broader intrusion timeline.",
"Real detection reference: \"AiTM Session Cookie Theft\" -- Flags the Adversary-in-the-Middle signature: a user completes MFA from one IP, then the same session authenticates single-factor from a different, distant IP shortly after - indicating a stolen session cookie."
]
},
"evidence_to_collect": [
"Host or resource affected",
"Account or identity involved",
"Timestamp of the activity",
"Related process, file, or network artifact",
"Any preceding or follow-on alerts"
],
"response_actions": [
{
"name": "Revoke ALL active sessions — Entra ID",
"category": "Response",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "Entra ID"
},
{
"name": "Reset password + force MFA re-enrolment",
"category": "Response",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide"
},
{
"name": "Review and delete any inbox forwarding rules created",
"category": "Response",
"risk": "Low",
"automation_safe": true,
"approval_required": false,
"tool": "See investigation guide"
},
{
"name": "Review and revoke any OAuth app consents granted",
"category": "Response",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide"
},
{
"name": "Deploy or verify: Conditional Access policy requiring compli",
"category": "Response",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide",
"notes": "Deploy or verify: Conditional Access policy requiring compliant device AND location-based restrictions"
}
],
"queries": {
"kql": [
{
"name": "GEN-CA-004 — AiTM Session Cookie Theft",
"description": "Flags the Adversary-in-the-Middle signature: a user completes MFA from one IP, then the same session authenticates single-factor from a different, distant IP shortly after - indicating a stolen session cookie. (Source: Bell Integration baseline detection library.)",
"query": "let TrustedRanges =\n _GetWatchlist('TrustedVPNRanges')\n | extend VPNRange = tostring(column_ifexists(\"SearchKey\", column_ifexists(\"Subnet\", \"\")))\n | where isnotempty(VPNRange)\n | summarize by VPNRange;\nlet MfaSignins = SigninLogs\n | where TimeGenerated >= ago(1h)\n | where ResultType == \"0\"\n | where IPAddress !in (TrustedRanges)\n | where tostring(AuthenticationRequirement) == \"multiFactorAuthentication\"\n | extend Lat = todouble(LocationDetails.geoCoordinates.latitude), Lon = todouble(LocationDetails.geoCoordinates.longitude), City = tostring(LocationDetails.city)\n | project TimeGenerated, UserPrincipalName, IPAddress, Lat, Lon, City, AppDisplayName;\nMfaSignins\n| join kind=inner (\n SigninLogs\n | where TimeGenerated >= ago(1h) and ResultType == \"0\"\n | where IPAddress !in (TrustedRanges)\n | where tostring(AuthenticationRequirement) == \"singleFactorAuthentication\"\n | extend Lat2 = todouble(LocationDetails.geoCoordinates.latitude), Lon2 = todouble(LocationDetails.geoCoordinates.longitude), City2 = tostring(LocationDetails.city)\n | project TimeGenerated2 = TimeGenerated, UserPrincipalName, IPAddress2 = IPAddress, Lat2, Lon2, City2, AppDisplayName2 = AppDisplayName\n) on UserPrincipalName\n| where TimeGenerated2 > TimeGenerated and IPAddress != IPAddress2\n| where datetime_diff('minute', TimeGenerated2, TimeGenerated) <= 30\n| extend DistKm = round(6371.0 * 2 * asin(sqrt(pow(sin((Lat2 - Lat) * pi() / 360), 2) + cos(Lat * pi() / 180) * cos(Lat2 * pi() / 180) * pow(sin((Lon2 - Lon) * pi() / 360), 2))), 0)\n| where DistKm > 50\n| distinct TimeGenerated2, UserPrincipalName, IPAddress, IPAddress2, City, City2, DistKm, AppDisplayName2\n| extend timestamp = TimeGenerated2, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress2\n| order by DistKm desc"
},
{
"name": "33B07EAA-F451-4C38-AC9F-8AF3F7E99F0E — Cyble Vision Alerts Compromised Endpoint Cookies",
"description": "Detects compromised browser cookies associated with monitored entities. Identifies exposed authentication cookies with future expiry, enabling potential session hijacking or persistent unauthorized access.' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
"query": "Alerts_compromised_endpoints_cookies\n| where Service == \"compromised_endpoints_cookies\"\n| extend MappedSeverity = Severity"
}
],
"spl": [],
"esql": [
{
"name": "9ed5d08f-aad6-4c03-838c-d686da887c2c — Okta AiTM Session Cookie Replay",
"description": "(ESQL) Detects potential Adversary-in-the-Middle (AiTM) session cookie replay attacks against Okta. This rule identifies when an Okta session is used from multiple IP addresses or with suspicious non-browser user agents after initial authentication. AiTM attacks capture session cookies via phishing proxies (e.g., Evilginx, Modlishka) and replay them from attacker infrastructure, bypassing MFA... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
"query": "FROM logs-okta.system-*\n\n// Filter to relevant event types for AiTM detection\n| WHERE\n okta.event_type IN (\"user.session.start\", \"policy.evaluate_sign_on\", \"user.authentication.sso\") AND\n okta.authentication_context.root_session_id IS NOT NULL AND\n okta.actor.alternate_id != \"system@okta.com\"\n\n// Create event type flags\n| EVAL Esql.is_session_start = okta.event_type == \"user.session.start\"\n| EVAL Esql.is_policy_eval = okta.event_type == \"policy.evaluate_sign_on\"\n| EVAL Esql.is_sso = okta.event_type == \"user.authentication.sso\"\n| EVAL Esql.is_replay_event = Esql.is_policy_eval OR Esql.is_sso\n\n// Flag suspicious non-browser user agents\n| EVAL Esql.is_suspicious_ua =\n user_agent.original LIKE \"python-requests*\" OR\n user_agent.original LIKE \"curl/*\" OR\n user_agent.original LIKE \"httpx*\" OR\n user_agent.original LIKE \"aiohttp*\" OR\n user_agent.original LIKE \"Go-http-client*\" OR\n user_agent.original LIKE \"*Headless*\" OR\n user_agent.original LIKE \"Java/*\" OR\n user_agent.original LIKE \"okhttp*\"\n\n// Aggregate by session\n| STATS\n Esql.session_start_count = SUM(CASE(Esql.is_session_start, 1, 0)),\n Esql.replay_event_count = SUM(CASE(Esql.is_replay_event, 1, 0)),\n Esql.session_start_time = MIN(CASE(Esql.is_session_start, @timestamp, null)),\n Esql.first_replay_time = MIN(CASE(Esql.is_replay_event, @timestamp, null)),\n Esql.last_replay_time = MAX(CASE(Esql.is_replay_event, @timestamp, null)),\n Esql.session_start_ip = MAX(CASE(Esql.is_session_start, okta.client.ip, null)),\n Esql.session_start_ua = MAX(CASE(Esql.is_session_start, user_agent.original, null)),\n Esql.suspicious_ua_count = SUM(CASE(Esql.is_suspicious_ua, 1, 0)),\n Esql.okta_client_ip_count_distinct = COUNT_DISTINCT(okta.client.ip),\n Esql.user_agent_count_distinct = COUNT_DISTINCT(user_agent.original),\n Esql.okta_client_ip_values = VALUES(okta.client.ip),\n Esql.user_agent_values = VALUES(user_agent.original),\n Esql.okta_event_type_values = VALUES(okta.event_type),\n Esql.okta_outcome_result_values = VALUES(okta.outcome.result),\n Esql.source_geo_country_name_values = VALUES(source.geo.country_name),\n Esql.source_geo_city_name_values = VALUES(source.geo.city_name),\n Esql.okta_debug_context_debug_data_risk_level_values = VALUES(okta.debug_context.debug_data.risk_level),\n Esql.okta_debug_context_debug_data_risk_reasons_values = VALUES(okta.debug_context.debug_data.risk_reasons)\n BY okta.authentication_context.root_session_id, okta.actor.alternate_id\n\n// Detection conditions\n| WHERE\n Esql.session_start_count >= 1\n AND Esql.replay_event_count >= 1\n AND Esql.first_replay_time > Esql.session_start_time\n AND (\n (\n Esql.okta_client_ip_count_distinct > 1 OR Esql.user_agent_count_distinct > 1\n ) AND Esql.suspicious_ua_count > 0\n )\n\n| SORT Esql.session_start_time DESC\n| KEEP Esql.*, okta.authentication_context.root_session_id, okta.actor.alternate_id"
},
{
"name": "5301ac83-7a43-4c92-95e7-c372afea807d — AWS IAM User Console Login from Multiple Geolocations",
"description": "(ESQL) Identifies an IAM user that successfully signs in to the AWS Management Console from two or more distinct countries within a short window. A single user authenticating from multiple geographic locations in a brief period is physically implausible and indicates that the account's credentials or console session are being used from more than one place at once... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
"query": "FROM logs-aws.cloudtrail-*\n| WHERE event.provider == \"signin.amazonaws.com\"\n AND event.action == \"ConsoleLogin\"\n AND event.outcome == \"success\"\n AND aws.cloudtrail.user_identity.type == \"IAMUser\"\n AND source.geo.country_iso_code IS NOT NULL\n| STATS\n Esql.source_geo_country_iso_code_count_distinct = COUNT_DISTINCT(source.geo.country_iso_code),\n Esql.source_as_organization_name_count_distinct = COUNT_DISTINCT(source.as.organization.name),\n Esql.source_ip_values = VALUES(source.ip),\n Esql.source_geo_country_iso_code_values = VALUES(source.geo.country_iso_code),\n Esql.timestamp_min = MIN(@timestamp),\n Esql.timestamp_max = MAX(@timestamp)\n BY aws.cloudtrail.user_identity.arn, cloud.account.id\n| WHERE Esql.source_geo_country_iso_code_count_distinct >= 2\n| KEEP aws.cloudtrail.user_identity.arn, cloud.account.id, Esql.source_geo_country_iso_code_count_distinct, Esql.source_as_organization_name_count_distinct, Esql.source_ip_values, Esql.source_geo_country_iso_code_values, Esql.timestamp_min, Esql.timestamp_max"
}
]
},
"automation": {
"safe": [
"Add recommendation as Sentinel incident comment.",
"Run enrichment queries.",
"Create ServiceNow SecOps task."
],
"approval_required": [
"Contain or disable the affected host/account.",
"Any change to production configuration."
]
},
"escalation_criteria": [
"Steal Web Session Cookie activity observed on a privileged account or critical system.",
"Activity follows or precedes other suspicious behaviour in the same investigation.",
"Automated triage cannot confidently rule out malicious intent."
],
"false_positive_considerations": [
"Legitimate administrative or maintenance activity matching this pattern.",
"Approved security testing or red team exercise.",
"Known benign software producing similar telemetry."
],
"confluence": {
"title": "T1539 - Steal Web Session Cookie Response Guidance",
"labels": [
"mitre",
"attack",
"d3fend",
"secops",
"basyrix"
],
"sections": [
"summary",
"d3fend_mappings",
"investigation_steps",
"response_actions",
"queries",
"automation",
"escalation_criteria",
"false_positive_considerations"
]
}
}