Credential Access
T1606 — Forge Web Credentials
Adversaries may forge credential materials that can be used to gain access to web applications or Internet services. Web applications and services (hosted in cloud SaaS environments or on-premise servers) often use session cookies, tokens, or other materials to authenticate and authorize user access. Adversaries may generate these credential materials in order to gain access to web resources...
Investigate Forge Web Credentials 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
SaaS, Windows, macOS, Linux, IaaS, Office Suite, Identity Provider
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 |
|---|---|---|---|
| T1606 Forge Web Credentials | Credential Compromise Scope Analysis | Monitor for Credential Compromise Scope Analysis indicators relevant to this technique. | Entra ID |
| T1606 Forge Web Credentials | Credential Hardening | Apply Credential Hardening to reduce this technique's viability before an incident occurs. | Entra ID |
| T1606 Forge Web Credentials | Credential Revocation | Use Credential Revocation to remove the adversary's foothold once this technique is confirmed. | Entra ID |
| T1606 Forge Web Credentials | Credential Transmission Scoping | Apply Credential Transmission Scoping to contain the blast radius once this technique is observed. | Entra ID |
T1606 Forge Web Credentials → 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 forge web credentials 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: "Golden SAML Token Forgery" -- Flags SAML/federated authentication with no registered device and elevated Entra ID risk signals, consistent with a forged SAML token (Golden SAML) using a stolen ADFS token-signing certificate.
Response actions
| Action | Risk | Automation safe | Approval required |
|---|---|---|---|
| Revoke all sessions for affected accounts | Medium | No | Yes |
| If ADFS compromise confirmed: rotate ADFS token signing and | Medium | No | Yes |
| Enable "Protect all users" in Entra ID Protection | Low | No | Yes |
| Consider migrating from ADFS to Entra ID native authenticati | Low | No | Yes |
KQL
GEN-CA-005 — Golden SAML Token Forgery
SigninLogs
| where TimeGenerated >= ago(1h)
| where ResultType == "0"
| where AuthenticationProtocol == "SAML20" or TokenIssuerType == "AzureAD"
| where DeviceDetail == "{}" or tostring(DeviceDetail) == ""
| where RiskLevelAggregated in ("high", "medium")
or RiskEventTypes has_any ("unfamiliarFeatures", "anomalousToken", "tokenIssuerAnomaly", "suspiciousInboxManipulation")
| project
TimeGenerated,
UserPrincipalName,
IPAddress,
AuthenticationProtocol,
RiskLevelAggregated,
RiskEventTypes,
AppDisplayName,
TokenIssuerName,
ConditionalAccessStatus
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
| order by TimeGenerated desc 42e6f16a-7773-44cc-8668-8f648bd1aa4f — CYFIRMA - Social and Public Exposure - Source Code Exposure on Public Repositories Rule
// High severity - Social and Public Exposure - Source Code Exposure on Public Repositories
let timeFrame = 5m;
CyfirmaSPESourceCodeAlerts_CL
| where severity == 'Critical' and TimeGenerated between (ago(timeFrame) .. now())
| extend
Description=description,
FirstSeen=first_seen,
LastSeen=last_seen,
RiskScore=risk_score,
AlertUID=alert_uid,
UID=uid,
AssetType=asset_type,
AssetValue=signature,
Source=source,
Impact=impact,
Recommendation=recommendation,
ProviderName='CYFIRMA',
ProductName='DeCYFIR/DeTCT',
AlertTitle=Alert_title
| project
TimeGenerated,
Description,
RiskScore,
FirstSeen,
LastSeen,
AlertUID,
UID,
AssetType,
AssetValue,
Impact,
ProductName,
ProviderName,
AlertTitle 67802748-435b-4f80-9f61-b9a9ac6ea15c — [Entra ID] Suspicious Continuous OAuth Token Usage
// =====================
// Low-noise Token Reuse Detector (fixed timespan calc)
// =====================
let GapDays = 1;
let MinIPChanges = 2;
let MinLocChanges = 2;
let ExcludeApps = dynamic([
"Microsoft Authentication Broker",
"Microsoft Teams",
"Office 365"
]);
let Src =
union isfuzzy=true
AADNonInteractiveUserSignInLogs,
SigninLogs
| where ResultType == 0
| where isnotempty(UniqueTokenIdentifier);
let Past =
Src
| where TimeGenerated between (ago(14d) .. ago(1d))
| summarize
PastLastSeen = max(TimeGenerated),
PastUPNs = make_set(UserPrincipalName, 20),
PastIPs = make_set(IPAddress, 50),
PastLocs = make_set(tostring(Location), 50),
PastApps = make_set(AppDisplayName, 50)
by UniqueTokenIdentifier;
let Last24h =
Src
| where TimeGenerated >= ago(1d)
//| where AppDisplayName !in (ExcludeApps)
| summarize
CurrentFirstSeen = min(TimeGenerated),
CurrentLastSeen = max(TimeGenerated),
CurrentUPNs = make_set(UserPrincipalName, 20),
CurrentIPs = make_set(IPAddress, 50),
CurrentLocs = make_set(tostring(Location), 50),
CurrentApps = make_set(AppDisplayName, 50),
IPCount = dcount(IPAddress),
LocCount = dcount(tostring(Location))
by UniqueTokenIdentifier, ResultType;
Last24h
| join kind=inner Past on UniqueTokenIdentifier
| extend Gap = CurrentFirstSeen - PastLastSeen
| extend GapThreshold = totimespan(strcat(GapDays, "d"))
| where Gap >= GapThreshold
| where IPCount >= MinIPChanges or LocCount >= MinLocChanges
| extend NewIPs = set_difference(CurrentIPs, PastIPs)
| extend NewLocs = set_difference(CurrentLocs, PastLocs)
| where array_length(NewIPs) > 0 or array_length(NewLocs) > 0
| extend
CurrentUPNCount = array_length(CurrentUPNs),
PastUPNCount = array_length(PastUPNs)
| project
UniqueTokenIdentifier,
PastLastSeen,
CurrentFirstSeen,
CurrentLastSeen,
Gap,
GapThreshold,
CurrentUPNs,
CurrentUPNCount,
CurrentIPs,
IPCount,
NewIPs,
CurrentLocs,
LocCount,
NewLocs,
CurrentApps,
PastApps,
PastUPNs,
ResultType
| order by Gap desc, CurrentLastSeen desc
| extend UserNames = strcat_array(CurrentUPNs, ",")
| extend NewIP = strcat_array(NewIPs, ",")
| extend FirstNewIP = tostring(NewIPs[0])
| extend NewLoc = strcat_array(NewLocs, ",")
| extend PastUPN = strcat_array(PastUPNs, ",")
| extend Source_Network_IPLocation = ""
| project
Alert_Time_TW = datetime_utc_to_local(CurrentLastSeen, 'Asia/Taipei'),
Alert_Time_UTC0 = CurrentLastSeen,
Alert_Category_en = "Entra ID",
Alert_SubCategory_en = "Anomaly Network Access User",
Alert_Name_en = "Abnormal Sign-in Token Reuse",
Alert_Description_en=strcat(
"At Taiwan time: ",
format_datetime(datetime_utc_to_local(CurrentLastSeen, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
", detected suspected Token Reuse behavior (UniqueTokenIdentifier appeared repeatedly and the interval reached the threshold).",
"Token:",
iff(isnotempty(UniqueTokenIdentifier), UniqueTokenIdentifier, "<NoTokenId>"),
", users (last 2 days): ",
iff(isnotempty(tostring(UserNames)), tostring(UserNames), "<NoUserNames>"),
", previous last seen: ",
format_datetime(datetime_utc_to_local(PastLastSeen, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
", current first seen: ",
format_datetime(datetime_utc_to_local(CurrentFirstSeen, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
", gap: ",
tostring(Gap),
" days",
", IP count: ",
tostring(IPCount),
", current sign-in IP: ",
iff(isnotempty(tostring(NewIP)), tostring(NewIP), "<NoNewIP>"),
", location count: ",
tostring(LocCount),
", current sign-in location: ",
iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), "<NoNewLoc>"),
"."
),
Alert_TriageStep_en=strcat(
" 1. Check whether this is truly token reuse. The reused IP is: ",
iff(isnotempty(tostring(NewIP)), tostring(NewIP), "<NoNewIPs>"),
", current sign-in location: ",
iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), "<NoNewLocs>"),
" to determine whether it is an uncommon source, cross-country/cross-region, or anonymous cloud egress.",
" 2. Check whether multiple accounts share the same token. Current triggering account count: ",
tostring(CurrentUPNCount),
", accounts that previously triggered this token: ",
tostring(PastUPN),
"; if the UPN count is greater than 1, prioritize suspicion of token leakage or proxy/automation abuse.",
" 3. Check the applications currently involved in sign-in: ",
iff(isnotempty(tostring(CurrentApps)), tostring(CurrentApps), "<NoCurrentApps>"),
"previous sign-in applications: ",
iff(isnotempty(tostring(PastApps)), tostring(PastApps), "<NoPastApps>"),
" to determine whether they include administrative/highly sensitive applications or abnormally newly added apps."
),
Alert_Containment_en=strcat(
"1. Immediately revoke sign-in tokens/sessions and force re-sign-in for users (last 2 days): ",
iff(isnotempty(tostring(UserNames)), tostring(UserNames), "<NoUserNames>"),
" to block continued access using the reused token. ",
"2. If the current sign-in IP or location is abnormal, immediately block the current sign-in IP: ",
iff(isnotempty(tostring(NewIP)), tostring(NewIP), "<NoNewIP>"),
", current sign-in location: ",
iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), "<NoNewLoc>"),
", and tighten Conditional Access (MFA/compliant device/named location). ",
"3. Immediately require account security recovery: reset the password, re-register MFA, and check for suspicious devices or added authentication methods. "
),
Alert_Remediation_en=strcat(
"1. Strengthen risk-based access: establish Conditional Access policies to block new IPs/new locations. ",
"2. Implement token protection and endpoint governance: promote compliant devices, reduce long-lived token risk, and restrict access from unmanaged devices or legacy clients. ",
"3. Inventory automation and applications: regularly check for abnormally added applications and high-privilege applications, and remove unnecessary permissions and old credentials. ",
"4. Establish automated response: automatically revoke tokens, block IPs, notify users for confirmation, and create incident tickets for follow-up investigation when alerts trigger."
),
Event_Code = ResultType,
//Event_Description = ResultDescription,
Event_TimeRange_Start_UTC0 = CurrentFirstSeen,
Event_TimeRange_End_UTC0 = CurrentLastSeen,
Event_TimeRange_Start_TW = datetime_utc_to_local(CurrentFirstSeen, 'Asia/Taipei'),
Event_TimeRange_End_TW = datetime_utc_to_local(CurrentFirstSeen, 'Asia/Taipei'),
Source_Identity_FullName = UserNames,
Source_Network_IPAddress = NewIP,
Source_Network_IPLocation = Source_Network_IPLocation,
Target_Identity_FullName = UniqueTokenIdentifier,
//Target_Network_IPAddress = UniqueTokenIdentifier,
//Target_Resource_ID = "",
Target_Resource_Name = "Microsoft Entra ID",
Target_Resource_Type = "Microsoft Entra ID" Escalation criteria
- Forge Web Credentials 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.
# T1606 - Forge Web Credentials
## SOC Recommendation
Investigate Forge Web Credentials 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 sessions for affected accounts | Medium | No | Yes |
| If ADFS compromise confirmed: rotate ADFS token signing and | Medium | No | Yes |
| Enable "Protect all users" in Entra ID Protection | Low | No | Yes |
| Consider migrating from ADFS to Entra ID native authenticati | Low | No | Yes |
## KQL
```kql
SigninLogs
| where TimeGenerated >= ago(1h)
| where ResultType == "0"
| where AuthenticationProtocol == "SAML20" or TokenIssuerType == "AzureAD"
| where DeviceDetail == "{}" or tostring(DeviceDetail) == ""
| where RiskLevelAggregated in ("high", "medium")
or RiskEventTypes has_any ("unfamiliarFeatures", "anomalousToken", "tokenIssuerAnomaly", "suspiciousInboxManipulation")
| project
TimeGenerated,
UserPrincipalName,
IPAddress,
AuthenticationProtocol,
RiskLevelAggregated,
RiskEventTypes,
AppDisplayName,
TokenIssuerName,
ConditionalAccessStatus
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
| order by TimeGenerated desc
```
```kql
// High severity - Social and Public Exposure - Source Code Exposure on Public Repositories
let timeFrame = 5m;
CyfirmaSPESourceCodeAlerts_CL
| where severity == 'Critical' and TimeGenerated between (ago(timeFrame) .. now())
| extend
Description=description,
FirstSeen=first_seen,
LastSeen=last_seen,
RiskScore=risk_score,
AlertUID=alert_uid,
UID=uid,
AssetType=asset_type,
AssetValue=signature,
Source=source,
Impact=impact,
Recommendation=recommendation,
ProviderName='CYFIRMA',
ProductName='DeCYFIR/DeTCT',
AlertTitle=Alert_title
| project
TimeGenerated,
Description,
RiskScore,
FirstSeen,
LastSeen,
AlertUID,
UID,
AssetType,
AssetValue,
Impact,
ProductName,
ProviderName,
AlertTitle
```
```kql
// =====================
// Low-noise Token Reuse Detector (fixed timespan calc)
// =====================
let GapDays = 1;
let MinIPChanges = 2;
let MinLocChanges = 2;
let ExcludeApps = dynamic([
"Microsoft Authentication Broker",
"Microsoft Teams",
"Office 365"
]);
let Src =
union isfuzzy=true
AADNonInteractiveUserSignInLogs,
SigninLogs
| where ResultType == 0
| where isnotempty(UniqueTokenIdentifier);
let Past =
Src
| where TimeGenerated between (ago(14d) .. ago(1d))
| summarize
PastLastSeen = max(TimeGenerated),
PastUPNs = make_set(UserPrincipalName, 20),
PastIPs = make_set(IPAddress, 50),
PastLocs = make_set(tostring(Location), 50),
PastApps = make_set(AppDisplayName, 50)
by UniqueTokenIdentifier;
let Last24h =
Src
| where TimeGenerated >= ago(1d)
//| where AppDisplayName !in (ExcludeApps)
| summarize
CurrentFirstSeen = min(TimeGenerated),
CurrentLastSeen = max(TimeGenerated),
CurrentUPNs = make_set(UserPrincipalName, 20),
CurrentIPs = make_set(IPAddress, 50),
CurrentLocs = make_set(tostring(Location), 50),
CurrentApps = make_set(AppDisplayName, 50),
IPCount = dcount(IPAddress),
LocCount = dcount(tostring(Location))
by UniqueTokenIdentifier, ResultType;
Last24h
| join kind=inner Past on UniqueTokenIdentifier
| extend Gap = CurrentFirstSeen - PastLastSeen
| extend GapThreshold = totimespan(strcat(GapDays, "d"))
| where Gap >= GapThreshold
| where IPCount >= MinIPChanges or LocCount >= MinLocChanges
| extend NewIPs = set_difference(CurrentIPs, PastIPs)
| extend NewLocs = set_difference(CurrentLocs, PastLocs)
| where array_length(NewIPs) > 0 or array_length(NewLocs) > 0
| extend
CurrentUPNCount = array_length(CurrentUPNs),
PastUPNCount = array_length(PastUPNs)
| project
UniqueTokenIdentifier,
PastLastSeen,
CurrentFirstSeen,
CurrentLastSeen,
Gap,
GapThreshold,
CurrentUPNs,
CurrentUPNCount,
CurrentIPs,
IPCount,
NewIPs,
CurrentLocs,
LocCount,
NewLocs,
CurrentApps,
PastApps,
PastUPNs,
ResultType
| order by Gap desc, CurrentLastSeen desc
| extend UserNames = strcat_array(CurrentUPNs, ",")
| extend NewIP = strcat_array(NewIPs, ",")
| extend FirstNewIP = tostring(NewIPs[0])
| extend NewLoc = strcat_array(NewLocs, ",")
| extend PastUPN = strcat_array(PastUPNs, ",")
| extend Source_Network_IPLocation = ""
| project
Alert_Time_TW = datetime_utc_to_local(CurrentLastSeen, 'Asia/Taipei'),
Alert_Time_UTC0 = CurrentLastSeen,
Alert_Category_en = "Entra ID",
Alert_SubCategory_en = "Anomaly Network Access User",
Alert_Name_en = "Abnormal Sign-in Token Reuse",
Alert_Description_en=strcat(
"At Taiwan time: ",
format_datetime(datetime_utc_to_local(CurrentLastSeen, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
", detected suspected Token Reuse behavior (UniqueTokenIdentifier appeared repeatedly and the interval reached the threshold).",
"Token:",
iff(isnotempty(UniqueTokenIdentifier), UniqueTokenIdentifier, "<NoTokenId>"),
", users (last 2 days): ",
iff(isnotempty(tostring(UserNames)), tostring(UserNames), "<NoUserNames>"),
", previous last seen: ",
format_datetime(datetime_utc_to_local(PastLastSeen, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
", current first seen: ",
format_datetime(datetime_utc_to_local(CurrentFirstSeen, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
", gap: ",
tostring(Gap),
" days",
", IP count: ",
tostring(IPCount),
", current sign-in IP: ",
iff(isnotempty(tostring(NewIP)), tostring(NewIP), "<NoNewIP>"),
", location count: ",
tostring(LocCount),
", current sign-in location: ",
iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), "<NoNewLoc>"),
"."
),
Alert_TriageStep_en=strcat(
" 1. Check whether this is truly token reuse. The reused IP is: ",
iff(isnotempty(tostring(NewIP)), tostring(NewIP), "<NoNewIPs>"),
", current sign-in location: ",
iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), "<NoNewLocs>"),
" to determine whether it is an uncommon source, cross-country/cross-region, or anonymous cloud egress.",
" 2. Check whether multiple accounts share the same token. Current triggering account count: ",
tostring(CurrentUPNCount),
", accounts that previously triggered this token: ",
tostring(PastUPN),
"; if the UPN count is greater than 1, prioritize suspicion of token leakage or proxy/automation abuse.",
" 3. Check the applications currently involved in sign-in: ",
iff(isnotempty(tostring(CurrentApps)), tostring(CurrentApps), "<NoCurrentApps>"),
"previous sign-in applications: ",
iff(isnotempty(tostring(PastApps)), tostring(PastApps), "<NoPastApps>"),
" to determine whether they include administrative/highly sensitive applications or abnormally newly added apps."
),
Alert_Containment_en=strcat(
"1. Immediately revoke sign-in tokens/sessions and force re-sign-in for users (last 2 days): ",
iff(isnotempty(tostring(UserNames)), tostring(UserNames), "<NoUserNames>"),
" to block continued access using the reused token. ",
"2. If the current sign-in IP or location is abnormal, immediately block the current sign-in IP: ",
iff(isnotempty(tostring(NewIP)), tostring(NewIP), "<NoNewIP>"),
", current sign-in location: ",
iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), "<NoNewLoc>"),
", and tighten Conditional Access (MFA/compliant device/named location). ",
"3. Immediately require account security recovery: reset the password, re-register MFA, and check for suspicious devices or added authentication methods. "
),
Alert_Remediation_en=strcat(
"1. Strengthen risk-based access: establish Conditional Access policies to block new IPs/new locations. ",
"2. Implement token protection and endpoint governance: promote compliant devices, reduce long-lived token risk, and restrict access from unmanaged devices or legacy clients. ",
"3. Inventory automation and applications: regularly check for abnormally added applications and high-privilege applications, and remove unnecessary permissions and old credentials. ",
"4. Establish automated response: automatically revoke tokens, block IPs, notify users for confirmation, and create incident tickets for follow-up investigation when alerts trigger."
),
Event_Code = ResultType,
//Event_Description = ResultDescription,
Event_TimeRange_Start_UTC0 = CurrentFirstSeen,
Event_TimeRange_End_UTC0 = CurrentLastSeen,
Event_TimeRange_Start_TW = datetime_utc_to_local(CurrentFirstSeen, 'Asia/Taipei'),
Event_TimeRange_End_TW = datetime_utc_to_local(CurrentFirstSeen, 'Asia/Taipei'),
Source_Identity_FullName = UserNames,
Source_Network_IPAddress = NewIP,
Source_Network_IPLocation = Source_Network_IPLocation,
Target_Identity_FullName = UniqueTokenIdentifier,
//Target_Network_IPAddress = UniqueTokenIdentifier,
//Target_Resource_ID = "",
Target_Resource_Name = "Microsoft Entra ID",
Target_Resource_Type = "Microsoft Entra ID"
```
## Escalation Criteria
- Forge Web Credentials 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/T1606.json
- /api/recommendations/T1606.json
- /api/d3fend/T1606.json
- /api/mappings/T1606.json
- /api/confluence/T1606.md
Example curl:
curl https://atlas.basyrix.com/api/recommendations/T1606.json Response:
{
"technique_id": "T1606",
"name": "Forge Web Credentials",
"priority": "high",
"status": "complete",
"version": "0.1.0",
"last_reviewed": "2026-07-23",
"generated_by": "SOC Response Atlas by Basyrix",
"tactics": [
"Credential Access"
],
"platforms": [
"SaaS",
"Windows",
"macOS",
"Linux",
"IaaS",
"Office Suite",
"Identity Provider"
],
"summary": "Adversaries may forge credential materials that can be used to gain access to web applications or Internet services. Web applications and services (hosted in cloud SaaS environments or on-premise servers) often use session cookies, tokens, or other materials to authenticate and authorize user access. Adversaries may generate these credential materials in order to gain access to web resources...",
"soc_recommendation": "Investigate Forge Web Credentials 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 forge web credentials 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: \"Golden SAML Token Forgery\" -- Flags SAML/federated authentication with no registered device and elevated Entra ID risk signals, consistent with a forged SAML token (Golden SAML) using a stolen ADFS token-signing certificate."
]
},
"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 sessions for affected accounts",
"category": "Response",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide"
},
{
"name": "If ADFS compromise confirmed: rotate ADFS token signing and",
"category": "Response",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide",
"notes": "If ADFS compromise confirmed: rotate ADFS token signing and encryption certificates"
},
{
"name": "Enable \"Protect all users\" in Entra ID Protection",
"category": "Response",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "Entra ID"
},
{
"name": "Consider migrating from ADFS to Entra ID native authenticati",
"category": "Response",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "Entra ID",
"notes": "Consider migrating from ADFS to Entra ID native authentication"
}
],
"queries": {
"kql": [
{
"name": "GEN-CA-005 — Golden SAML Token Forgery",
"description": "Flags SAML/federated authentication with no registered device and elevated Entra ID risk signals, consistent with a forged SAML token (Golden SAML) using a stolen ADFS token-signing certificate. (Source: Bell Integration baseline detection library, mapped via sub-technique T1606.002.)",
"query": "SigninLogs\n| where TimeGenerated >= ago(1h)\n| where ResultType == \"0\"\n| where AuthenticationProtocol == \"SAML20\" or TokenIssuerType == \"AzureAD\"\n| where DeviceDetail == \"{}\" or tostring(DeviceDetail) == \"\"\n| where RiskLevelAggregated in (\"high\", \"medium\")\n or RiskEventTypes has_any (\"unfamiliarFeatures\", \"anomalousToken\", \"tokenIssuerAnomaly\", \"suspiciousInboxManipulation\")\n| project\n TimeGenerated,\n UserPrincipalName,\n IPAddress,\n AuthenticationProtocol,\n RiskLevelAggregated,\n RiskEventTypes,\n AppDisplayName,\n TokenIssuerName,\n ConditionalAccessStatus\n| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress\n| order by TimeGenerated desc"
},
{
"name": "42e6f16a-7773-44cc-8668-8f648bd1aa4f — CYFIRMA - Social and Public Exposure - Source Code Exposure on Public Repositories Rule",
"description": "\"This rule triggers when CYFIRMA detects source code related to internal or enterprise domains exposed on public platforms like GitHub. Such exposure may lead to intellectual property leakage or help adversaries understand internal systems, increasing the risk of targeted attacks.\" (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed), mapped via sub-technique T1606.001.)",
"query": "// High severity - Social and Public Exposure - Source Code Exposure on Public Repositories\nlet timeFrame = 5m;\nCyfirmaSPESourceCodeAlerts_CL\n| where severity == 'Critical' and TimeGenerated between (ago(timeFrame) .. now())\n| extend\n Description=description,\n FirstSeen=first_seen,\n LastSeen=last_seen,\n RiskScore=risk_score,\n AlertUID=alert_uid,\n UID=uid,\n AssetType=asset_type,\n AssetValue=signature,\n Source=source,\n Impact=impact,\n Recommendation=recommendation,\n ProviderName='CYFIRMA',\n ProductName='DeCYFIR/DeTCT',\n AlertTitle=Alert_title\n| project\n TimeGenerated,\n Description,\n RiskScore,\n FirstSeen,\n LastSeen,\n AlertUID,\n UID,\n AssetType,\n AssetValue,\n Impact,\n ProductName,\n ProviderName,\n AlertTitle"
},
{
"name": "67802748-435b-4f80-9f61-b9a9ac6ea15c — [Entra ID] Suspicious Continuous OAuth Token Usage",
"description": "Detects repeated use of the same OAuth token across different IPs or locations over time. This can indicate token theft or session abuse. (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
"query": "// =====================\n// Low-noise Token Reuse Detector (fixed timespan calc)\n// =====================\nlet GapDays = 1;\nlet MinIPChanges = 2;\nlet MinLocChanges = 2;\nlet ExcludeApps = dynamic([\n \"Microsoft Authentication Broker\",\n \"Microsoft Teams\",\n \"Office 365\"\n ]);\nlet Src =\n union isfuzzy=true\n AADNonInteractiveUserSignInLogs,\n SigninLogs\n | where ResultType == 0\n | where isnotempty(UniqueTokenIdentifier);\nlet Past =\n Src\n | where TimeGenerated between (ago(14d) .. ago(1d))\n | summarize\n PastLastSeen = max(TimeGenerated),\n PastUPNs = make_set(UserPrincipalName, 20),\n PastIPs = make_set(IPAddress, 50),\n PastLocs = make_set(tostring(Location), 50),\n PastApps = make_set(AppDisplayName, 50)\n by UniqueTokenIdentifier;\nlet Last24h =\n Src\n | where TimeGenerated >= ago(1d)\n //| where AppDisplayName !in (ExcludeApps)\n | summarize\n CurrentFirstSeen = min(TimeGenerated),\n CurrentLastSeen = max(TimeGenerated),\n CurrentUPNs = make_set(UserPrincipalName, 20),\n CurrentIPs = make_set(IPAddress, 50),\n CurrentLocs = make_set(tostring(Location), 50),\n CurrentApps = make_set(AppDisplayName, 50),\n IPCount = dcount(IPAddress),\n LocCount = dcount(tostring(Location))\n by UniqueTokenIdentifier, ResultType;\nLast24h\n| join kind=inner Past on UniqueTokenIdentifier\n| extend Gap = CurrentFirstSeen - PastLastSeen\n| extend GapThreshold = totimespan(strcat(GapDays, \"d\"))\n| where Gap >= GapThreshold\n| where IPCount >= MinIPChanges or LocCount >= MinLocChanges\n| extend NewIPs = set_difference(CurrentIPs, PastIPs)\n| extend NewLocs = set_difference(CurrentLocs, PastLocs)\n| where array_length(NewIPs) > 0 or array_length(NewLocs) > 0\n| extend\n CurrentUPNCount = array_length(CurrentUPNs),\n PastUPNCount = array_length(PastUPNs)\n| project\n UniqueTokenIdentifier,\n PastLastSeen,\n CurrentFirstSeen,\n CurrentLastSeen,\n Gap,\n GapThreshold,\n CurrentUPNs,\n CurrentUPNCount,\n CurrentIPs,\n IPCount,\n NewIPs,\n CurrentLocs,\n LocCount,\n NewLocs,\n CurrentApps,\n PastApps,\n PastUPNs,\n ResultType\n| order by Gap desc, CurrentLastSeen desc\n| extend UserNames = strcat_array(CurrentUPNs, \",\")\n| extend NewIP = strcat_array(NewIPs, \",\")\n| extend FirstNewIP = tostring(NewIPs[0])\n| extend NewLoc = strcat_array(NewLocs, \",\")\n| extend PastUPN = strcat_array(PastUPNs, \",\")\n| extend Source_Network_IPLocation = \"\"\n| project\n Alert_Time_TW = datetime_utc_to_local(CurrentLastSeen, 'Asia/Taipei'),\n Alert_Time_UTC0 = CurrentLastSeen,\n Alert_Category_en = \"Entra ID\",\n Alert_SubCategory_en = \"Anomaly Network Access User\",\n Alert_Name_en = \"Abnormal Sign-in Token Reuse\",\n Alert_Description_en=strcat(\n \"At Taiwan time: \",\n format_datetime(datetime_utc_to_local(CurrentLastSeen, \"Asia/Taipei\"), \"yyyy-MM-dd HH:mm:ss\"),\n \", detected suspected Token Reuse behavior (UniqueTokenIdentifier appeared repeatedly and the interval reached the threshold).\",\n \"Token:\",\n iff(isnotempty(UniqueTokenIdentifier), UniqueTokenIdentifier, \"<NoTokenId>\"),\n \", users (last 2 days): \",\n iff(isnotempty(tostring(UserNames)), tostring(UserNames), \"<NoUserNames>\"),\n \", previous last seen: \",\n format_datetime(datetime_utc_to_local(PastLastSeen, \"Asia/Taipei\"), \"yyyy-MM-dd HH:mm:ss\"),\n \", current first seen: \",\n format_datetime(datetime_utc_to_local(CurrentFirstSeen, \"Asia/Taipei\"), \"yyyy-MM-dd HH:mm:ss\"),\n \", gap: \",\n tostring(Gap),\n \" days\",\n \", IP count: \",\n tostring(IPCount),\n \", current sign-in IP: \",\n iff(isnotempty(tostring(NewIP)), tostring(NewIP), \"<NoNewIP>\"),\n \", location count: \",\n tostring(LocCount),\n \", current sign-in location: \",\n iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), \"<NoNewLoc>\"),\n \".\"\n ),\n Alert_TriageStep_en=strcat(\n \" 1. Check whether this is truly token reuse. The reused IP is: \",\n iff(isnotempty(tostring(NewIP)), tostring(NewIP), \"<NoNewIPs>\"),\n \", current sign-in location: \",\n iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), \"<NoNewLocs>\"),\n \" to determine whether it is an uncommon source, cross-country/cross-region, or anonymous cloud egress.\",\n \" 2. Check whether multiple accounts share the same token. Current triggering account count: \",\n tostring(CurrentUPNCount),\n \", accounts that previously triggered this token: \",\n tostring(PastUPN),\n \"; if the UPN count is greater than 1, prioritize suspicion of token leakage or proxy/automation abuse.\",\n \" 3. Check the applications currently involved in sign-in: \",\n iff(isnotempty(tostring(CurrentApps)), tostring(CurrentApps), \"<NoCurrentApps>\"),\n \"previous sign-in applications: \",\n iff(isnotempty(tostring(PastApps)), tostring(PastApps), \"<NoPastApps>\"),\n \" to determine whether they include administrative/highly sensitive applications or abnormally newly added apps.\"\n ),\n Alert_Containment_en=strcat(\n \"1. Immediately revoke sign-in tokens/sessions and force re-sign-in for users (last 2 days): \",\n iff(isnotempty(tostring(UserNames)), tostring(UserNames), \"<NoUserNames>\"),\n \" to block continued access using the reused token. \",\n \"2. If the current sign-in IP or location is abnormal, immediately block the current sign-in IP: \",\n iff(isnotempty(tostring(NewIP)), tostring(NewIP), \"<NoNewIP>\"),\n \", current sign-in location: \",\n iff(isnotempty(tostring(NewLoc)), tostring(NewLoc), \"<NoNewLoc>\"),\n \", and tighten Conditional Access (MFA/compliant device/named location). \",\n \"3. Immediately require account security recovery: reset the password, re-register MFA, and check for suspicious devices or added authentication methods. \"\n ),\n Alert_Remediation_en=strcat(\n \"1. Strengthen risk-based access: establish Conditional Access policies to block new IPs/new locations. \",\n \"2. Implement token protection and endpoint governance: promote compliant devices, reduce long-lived token risk, and restrict access from unmanaged devices or legacy clients. \",\n \"3. Inventory automation and applications: regularly check for abnormally added applications and high-privilege applications, and remove unnecessary permissions and old credentials. \",\n \"4. Establish automated response: automatically revoke tokens, block IPs, notify users for confirmation, and create incident tickets for follow-up investigation when alerts trigger.\"\n ),\n Event_Code = ResultType,\n //Event_Description = ResultDescription,\n Event_TimeRange_Start_UTC0 = CurrentFirstSeen,\n Event_TimeRange_End_UTC0 = CurrentLastSeen,\n Event_TimeRange_Start_TW = datetime_utc_to_local(CurrentFirstSeen, 'Asia/Taipei'),\n Event_TimeRange_End_TW = datetime_utc_to_local(CurrentFirstSeen, 'Asia/Taipei'),\n Source_Identity_FullName = UserNames,\n Source_Network_IPAddress = NewIP,\n Source_Network_IPLocation = Source_Network_IPLocation,\n Target_Identity_FullName = UniqueTokenIdentifier,\n //Target_Network_IPAddress = UniqueTokenIdentifier,\n //Target_Resource_ID = \"\",\n Target_Resource_Name = \"Microsoft Entra ID\",\n Target_Resource_Type = \"Microsoft Entra ID\""
}
],
"spl": [],
"esql": [
{
"name": "618a219d-a363-4ab1-ba30-870d7c22facd — FortiGate FortiCloud SSO Login from Unusual Source",
"description": "(ESQL) This rule detects the first successful FortiCloud SSO login from a previously unseen source IP address to a FortiGate device within the last 5 days. FortiCloud SSO logins from new source IPs may indicate exploitation of SAML-based authentication bypass vulnerabilities such as CVE-2026-24858, where crafted SAML assertions allow unauthorized access to FortiGate devices registered to other accounts... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
"query": "FROM logs-fortinet_fortigate.* metadata _id, _version, _index\n\n| WHERE data_stream.dataset == \"fortinet_fortigate.log\" and\n event.category == \"authentication\" and event.action == \"login\" and\n event.outcome == \"success\" and\n (fortinet.firewall.method == \"sso\" or fortinet.firewall.ui like \"sso*\") and\n source.ip is not null\n| STATS Esql.logon_count = COUNT(*),\n Esql.first_time_seen = MIN(@timestamp),\n Esql.user_values = VALUES(source.user.name),\n Esql.observer_name_values = VALUES(observer.name),\n Esql.message_values = VALUES(message) BY source.ip\n\n// first time seen is within 6m of the rule execution time and for the last 5d of events history\n| EVAL Esql.recent = DATE_DIFF(\"minute\", Esql.first_time_seen, now())\n| WHERE Esql.recent <= 6 AND Esql.logon_count == 1\n\n// move dynamic fields to ECS equivalent for rule exceptions\n| EVAL source.user.name = MV_FIRST(Esql.user_values)\n\n| KEEP source.ip, source.user.name, Esql.*"
},
{
"name": "2de10e77-c144-4e69-afb7-344e7127abd0 — M365 Identity Unusual SSO Authentication Errors for User",
"description": "(KUERY) Identifies the first occurrence of SSO, SAML, or federated authentication errors for a user. These errors may indicate token manipulation, SAML assertion tampering, or OAuth phishing attempts. Modern adversaries often target SSO mechanisms through token theft, SAML response manipulation, or exploiting federated authentication weaknesses rather than traditional brute force attacks. (Source: Elastic's official detection-rules repository (Elastic License v2).)",
"query": "data_stream.dataset:o365.audit\n and event.provider:AzureActiveDirectory\n and event.category:authentication\n and o365.audit.ErrorNumber:(\n 20001 or 20012 or 20033 or 40008 or 40009 or 40015 or\n 50006 or 50008 or 50012 or 50013 or 50027 or 50048 or\n 50099 or 50132 or 75005 or 75008 or 75011 or 75016 or\n 81004 or 81009 or 81010 or 399284 or 500212 or 500213 or\n 700005 or 5000819\n )"
}
]
},
"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": [
"Forge Web Credentials 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": "T1606 - Forge Web Credentials Response Guidance",
"labels": [
"mitre",
"attack",
"d3fend",
"secops",
"basyrix"
],
"sections": [
"summary",
"d3fend_mappings",
"investigation_steps",
"response_actions",
"queries",
"automation",
"escalation_criteria",
"false_positive_considerations"
]
}
}