Azure-Sentinel/Hunting Queries/MultipleDataSources/UserGrantedAccess_CreatesRe...

78 строки
4.8 KiB
YAML

id: b6baa3bb-a231-4e50-8ad1-4e28a958a0d3
name: User Granted Access and created resources
description: |
'Identifies when a new user is granted access and starts creating resources in Azure. This can help you identify rogue or malicious user behavior.'
requiredDataConnectors:
- connectorId: AzureActivity
dataTypes:
- AuditLogs
- connectorId: AzureActivity
dataTypes:
- AzureActivity
tactics:
- Persistence
- PrivilegeEscalation
- Impact
relevantTechniques:
- T1098
- T1078
- T1496
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let auditLookback = starttime-14d;
let opName = dynamic(["Add user", "Invite external user"]);
// Helper function to extract relevant fields from AuditLog events
let auditLogEvents = view (startTimeSpan:timespan, operation:dynamic) {
AuditLogs | where TimeGenerated >= auditLookback
| where OperationName in~ (operation)
| extend ModProps = iff(TargetResources.[0].modifiedProperties != "[]", TargetResources.[0].modifiedProperties, todynamic("NoValues"))
| extend IpAddress = iff(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)),
tostring(parse_json(tostring(InitiatedBy.user)).ipAddress), tostring(parse_json(tostring(InitiatedBy.app)).ipAddress))
| extend InitiatedByFull = iff(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)),
tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), tostring(parse_json(tostring(InitiatedBy.app)).displayName))
| extend InitiatedBy = replace("_","@",tostring(split(InitiatedByFull, "#")[0]))
| extend TargetUserPrincipalName = tostring(TargetResources[0].userPrincipalName)
| extend TargetUserName = replace("_","@",tostring(split(TargetUserPrincipalName, "#")[0]))
| extend TargetResourceName = case(
isempty(tostring(TargetResources.[0].displayName)), TargetUserPrincipalName,
isnotempty(tostring(TargetResources.[0].displayName)) and tostring(TargetResources.[0].displayName) startswith "upn:", tolower(tostring(TargetResources.[0].displayName)),
tolower(tostring(TargetResources.[0].displayName))
)
| extend TargetUserName = replace("_","@",tostring(split(TargetUserPrincipalName, "#")[0]))
| extend TargetUserName = iff(isempty(TargetUserName), tostring(split(split(TargetResourceName, ",")[0], " ")[1]), TargetUserName )
| mvexpand ModProps
| extend PropertyName = tostring(ModProps.displayName), newValue = replace("\"","",tostring(ModProps.newValue));
};
let UserAdd = auditLogEvents(auditLookback, opName)
| project Action = "User Added", TimeGenerated, Type, InitiatedBy_Caller = InitiatedBy, IpAddress, TargetUserName = tolower(TargetUserName), OperationName, PropertyName_ResourceId = PropertyName, Value = newValue;
// Get the simple list of creatd users so we can use later to get just the associated resource creation events
let SimpleUserList = UserAdd | project TimeGenerated, TargetUserName;
let ResourceCreation = AzureActivity
| where TimeGenerated >= auditLookback
// We look for any Operation that created and then succeeded where ActivityStatus has a value so that we can provide context
| where OperationName has "Create"
| where ActivityStatus has "Succeeded"
| project Action = "Resource Created", ResourceCreationTimeGenerated = TimeGenerated, Type, InitiatedBy_Caller = tolower(Caller), IpAddress = CallerIpAddress, OperationName, Value = OperationNameValue, PropertyName_ResourceId = ResourceId;
// Get just the Resources added by the new user
let ResourceMatch = SimpleUserList | join kind= innerunique (
ResourceCreation
) on $left.TargetUserName == $right.InitiatedBy_Caller
// where the resource creation is after (greater than) the user addition
| where TimeGenerated < ResourceCreationTimeGenerated
| project-away TimeGenerated
| project-rename TimeGenerated = ResourceCreationTimeGenerated
;
let SimpleResourceMatch = ResourceMatch | project InitiatedBy_Caller;
// Get only resource add, remove, change by the new user
let UserAddWithResource = SimpleResourceMatch | join kind= rightsemi (
UserAdd
) on $left.InitiatedBy_Caller == $right.TargetUserName;
// union the user addition events and resource addition events and provide common column names, additionally pack the value, property and resource info to reduce result set.
UserAddWithResource
| union isfuzzy=true(ResourceMatch
| extend PropertySet = pack("Value", Value, "PropertyName_ResourceId", PropertyName_ResourceId)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), makeset(PropertySet) by Action, Type, TargetUserName, InitiatedBy_Caller, IpAddress, OperationName
| order by StartTimeUtc asc)
| extend timestamp = StartTimeUtc, AccountCustomEntity = TargetUserName, IPCustomEntity = IpAddress