Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
id: 8a3b5c7d-9e1f-4a2b-8c6d-3e5f7a9b1c2d
kind: Scheduled
name: BTP - Audit log service unavailable
description: |
Identifies SAP BTP subaccounts that have not reported audit logs for an unusual period.
This could indicate that the audit log service has been disabled or tampered with,
potentially by an attacker attempting to hide malicious activity. It may also indicate
service key expiry or SAP BTP service availability problems.
severity: High
status: Available
requiredDataConnectors:
- connectorId: SAPBTPAuditEvents
dataTypes:
- SAPBTPAuditLog_CL
queryFrequency: 1h
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1562.008
query: |
// Configure the detection threshold (in minutes) - adjust based on your environment
let detection_threshold_in_minutes = 60;
// Lookback period to identify known subaccounts
let lookback = 7d;
// Get all known subaccounts and their last log time
let last_activity = SAPBTPAuditLog_CL
| where TimeGenerated > ago(lookback)
| summarize LastLogTime = max(TimeGenerated) by SubaccountName, Tenant;
// Identify subaccounts with no recent activity exceeding the threshold
last_activity
| where datetime_diff('minute', now(), LastLogTime) > detection_threshold_in_minutes
| extend TimeSinceLastLog = datetime_diff('minute', now(), LastLogTime)
| project
SubaccountName,
Tenant,
LastLogTime,
TimeSinceLastLog,
CloudApp = "SAP BTP"
eventGroupingSettings:
aggregationKind: AlertPerResult
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: CloudApp
alertDetailsOverride:
alertDisplayNameFormat: 'SAP BTP: No audit logs received from {{SubaccountName}} for {{TimeSinceLastLog}} minutes'
alertDescriptionFormat: |
The SAP BTP subaccount '{{SubaccountName}}' has not reported any audit logs since {{LastLogTime}}.

Time without logs: {{TimeSinceLastLog}} minutes

This could indicate:
- Audit log service has been disabled (potential compromise to hide malicious activity)
- Data connector authentication or connectivity issues
- SAP BTP service availability problems

Recommended actions:
1. Verify the audit log service status in SAP BTP cockpit
2. Check the data connector health in Microsoft Sentinel
3. Review any recent administrative changes to the subaccount
4. Investigate for potential unauthorized access or configuration changes
customDetails:
SubaccountName: SubaccountName
Tenant: Tenant
LastLogTime: LastLogTime
TimeSinceLastLog: TimeSinceLastLog
version: 1.0.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
id: 3f8a2c5e-7b9d-4e1a-8f6c-2d4b9a1e3c7f
kind: Scheduled
name: BTP - Cloud Identity Service application configuration monitor
description: |
Identifies CRUD operations on Application (SSO Domain/Service Provider) configurations
within SAP Cloud Identity Service. This includes both SAML 2.0 and OpenID Connect applications.
Unauthorized application creation could indicate an attacker establishing persistent access
through a rogue federated application.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SAPBTPAuditEvents
dataTypes:
- SAPBTPAuditLog_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
- PrivilegeEscalation
relevantTechniques:
- T1606
- T1556
- T1134
query: |
SAPBTPAuditLog_CL
| extend data_s = tostring(Message.data)
| extend action = extract(@"action=""([^""]+)""", 1, data_s)
| extend state = extract(@"state=""([^""]+)""", 1, data_s)
| extend objectType = extract(@"objectType=""([^""]+)""", 1, data_s)
| extend serviceProviderName = extract(@"serviceProviderName=""([^""]+)""", 1, data_s)
| extend ipAddress = extract(@"ipAddress=""([^""]+)""", 1, data_s)
// Extract payload JSON for federation type
| extend payloadJson = extract(@"\{""payload"":\{([^}]+)\}\}", 1, data_s)
| extend federationType = extract(@"""type"":""([^""]+)""", 1, payloadJson)
| where objectType == "ssoDomain"
| where state == "successful"
| where action in ("create", "update", "delete")
| extend MessageText = case(
action == "create", strcat("Application '", serviceProviderName, "' (", federationType, ") was created"),
action == "update", strcat("Application '", serviceProviderName, "' (", federationType, ") was updated"),
action == "delete", strcat("Application '", serviceProviderName, "' was deleted"),
"Unclassified operation on application"
)
| project
UpdatedOn,
UserName,
MessageText,
ServiceProviderName = serviceProviderName,
FederationType = federationType,
Action = action,
Tenant,
ipAddress,
CloudApp = "SAP Cloud Identity Service"
| extend AccountName = split(UserName, "@")[0], UPNSuffix = split(UserName, "@")[1]
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ipAddress
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: CloudApp
alertDetailsOverride:
alertDisplayNameFormat: 'SAP Cloud Identity Service: {{MessageText}}'
alertDescriptionFormat: |
{{MessageText}} by {{UserName}}. Identity provider name: {{ServiceProviderName}}

This could indicate:
- Legitimate administrative change to federated applications
- Unauthorized application registration for persistent access
- Rogue SAML/OIDC application added by attacker
customDetails:
ServiceProviderName: ServiceProviderName
FederationType: FederationType
Action: Action
SourceIP: ipAddress
version: 1.0.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
id: a3b8e7c4-5f2d-4a1e-9c6b-8d7f3e2a1b0c
kind: Scheduled
name: BTP - Mass user deletion in SAP Cloud Identity Service
description: Identifies mass user deletion activity in SAP Cloud Identity Service
where the amount of deleted users exceeds a predefined threshold.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SAPBTPAuditEvents
dataTypes:
- SAPBTPAuditLog_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1531
- T1485
- T1489
- T0813
- T0826
- T0827
query: |
let bulk_delete_threshold = 10;
SAPBTPAuditLog_CL
| extend data_s = tostring(Message.data)
| extend action = extract(@"action=""([^""]+)""", 1, data_s)
| extend objectType = extract(@"objectType=""([^""]+)""", 1, data_s)
| extend impactedUser = extract(@"serviceProviderName=""([^""]+)""", 1, data_s)
| where action == "delete"
| where objectType == "authorization"
| where isnotempty(impactedUser)
| summarize
Start = min(UpdatedOn),
End = max(UpdatedOn),
DeleteCount = count(),
DeletedUsers = make_set(impactedUser, 100)
by UserName, Tenant, SpaceId
| where array_length(DeletedUsers) > bulk_delete_threshold
| project Start, End, UserName, DeletedUsers, DeleteCount, Tenant, SpaceId, CloudApp = "SAP BTP"
| extend AccountName = split(UserName, "@")[0], UPNSuffix = split(UserName, "@")[1]
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: CloudApp
version: 3.0.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
id: 7d4e9f2a-8b1c-4a5d-9e3f-6c2b1a0d8e7f
kind: Scheduled
name: BTP - User added to Cloud Identity Service privileged Administrators list
description: Identifies when a user is granted privileged administrator permissions
in SAP Cloud Identity Service. These permissions include managing Identity Providers,
Service Providers, Users, Groups, and Access controls.
severity: High
status: Available
requiredDataConnectors:
- connectorId: SAPBTPAuditEvents
dataTypes:
- SAPBTPAuditLog_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- LateralMovement
- PrivilegeEscalation
relevantTechniques:
- T0859
- T1078
query: |
let monitored_permissions = dynamic(["ManageIdP", "ManageSP", "ManageUsers", "ReadUsers", "ManageAccess", "ManageGroups"]);
SAPBTPAuditLog_CL
| extend data_s = tostring(Message.data)
| extend action = extract(@"action=""([^""]+)""", 1, data_s)
| extend state = extract(@"state=""([^""]+)""", 1, data_s)
| extend changedAttribute = extract(@"changedAttribute=""([^""]+)""", 1, data_s)
| extend newValue = extract(@"newValue=""([^""]+)""", 1, data_s)
| extend targetUser = extract(@"userIdentifier=""([^""]+)""", 1, data_s)
| extend callerMail = extract(@"callerMail=""([^""]+)""", 1, data_s)
| extend ipAddress = extract(@"ipAddress=""([^""]+)""", 1, data_s)
| where action == "grantPermissions"
| where state == "successful"
| where changedAttribute == "authorizations"
| where isnotempty(newValue)
| mv-expand permission = monitored_permissions
| where newValue contains tostring(permission)
| summarize
GrantedPermissions = make_set(newValue, 10),
MatchedPermissions = make_set(tostring(permission), 10)
by UpdatedOn, UserName, callerMail, targetUser, Tenant, ipAddress
| project UpdatedOn, UserName, callerMail, targetUser, GrantedPermissions, MatchedPermissions, Tenant, ipAddress, CloudApp = "SAP Cloud Identity Service"
| extend AccountName = split(UserName, "@")[0], UPNSuffix = split(UserName, "@")[1]
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: CloudApp
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ipAddress
version: 1.0.0
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,33 @@
}
}
]
},
{
"title": "Advanced",
"instructions": [
{
"type": "Textbox",
"parameters": {
"label": "Polling Frequency (minutes, 1-15)",
"placeholder": "1",
"type": "text",
"description": "Frequency to poll for new BTP audit logs.",
"name": "pollingFrequencyMinutes",
"defaultValue": "1"
}
},
{
"type": "Textbox",
"parameters": {
"label": "Log Ingest Delay (minutes, 1-120)",
"placeholder": "20",
"type": "text",
"description": "Delay to account for SAP BTP audit logs published late.",
"name": "ingestDelayMinutes",
"defaultValue": "20"
}
}
]
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"request": {
"apiEndpoint": "[[concat(parameters('auditHost'), '/auditlog/v2/auditlogrecords')]",
"httpMethod": "Get",
"queryWindowInMin": 5,
"queryWindowInMin": "[[int(parameters('pollingFrequencyMinutes'))]",
"queryWindowDelayInMin": "[[int(parameters('ingestDelayMinutes'))]",
"queryTimeFormat": "yyyy-MM-ddTHH:mm:ss.fff",
"retryCount": 3,
"timeoutInSeconds": 120,
Expand Down
Binary file added Solutions/SAP BTP/Package/3.0.11.zip
Binary file not shown.
Loading
Loading