Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shainw entity map fix 5 [last few AuditLogs] #9694

Merged
merged 3 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Expand Up @@ -21,42 +21,72 @@ relevantTechniques:
tags:
- AADSecOpsGuide
query: |
// Add other permissions to this list as needed
let permissions = dynamic(["Mail.Read", "offline_access", "Files.Read", "Notes.Read", "ChannelMessage.Read", "Chat.Read", "TeamsActivity.Read",
// Add other permissions to this list as needed
let permissions = dynamic([".All", "ReadWrite", "Mail.", "offline_access", "Files.Read", "Notes.Read", "ChannelMessage.Read", "Chat.Read", "TeamsActivity.Read",
"Group.Read", "EWS.AccessAsUser.All", "EAS.AccessAsUser.All"]);
let auditList =
AuditLogs
| where OperationName =~ "Add app role assignment to service principal"
| mv-expand TargetResources[0].modifiedProperties
| extend TargetResources_0_modifiedProperties = column_ifexists("TargetResources_0_modifiedProperties", '')
| where isnotempty(TargetResources_0_modifiedProperties)
;
let detailsList = auditList
| where TargetResources_0_modifiedProperties.displayName =~ "AppRole.Value" or TargetResources_0_modifiedProperties.displayName =~ "DelegatedPermissionGrant.Scope"
| extend Permissions = split((parse_json(tostring(TargetResources_0_modifiedProperties.newValue))), " ")
| where Permissions has_any (permissions)
| summarize AddedPermissions=make_set(Permissions,200) by CorrelationId
| join kind=inner (AuditLogs
| where OperationName =~ "Add app role assignment to service principal") on CorrelationId
| extend InitiatedBy = tostring(iff(isnotempty(InitiatedBy.user.userPrincipalName),InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName))
| extend ServicePrincipal = tostring(parse_json(tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[4].newValue)))
| extend SPID = tostring(parse_json(tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[6].newValue)))
| extend InitiatedBy = pack("User", InitiatedBy, "UA", column_ifexists("UserAgent",''), "IPAddress", column_ifexists("IpAddress",''))
| mv-expand kind=array AddedPermissions
| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), make_set(InitiatedBy,200), make_set(AddedPermissions,200) by SPID, ServicePrincipal
| join kind=inner auditList on CorrelationId
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| extend displayName = tostring(TargetResources_0_modifiedProperties.displayName), newValue = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))
| where displayName == "ServicePrincipal.ObjectID" or displayName == "ServicePrincipal.DisplayName"
| extend displayName = case(displayName == "ServicePrincipal.ObjectID", "ServicePrincipalObjectID", displayName == "ServicePrincipal.DisplayName", "ServicePrincipalDisplayName", displayName)
| project TimeGenerated, CorrelationId, Id, AddedPermissions = tostring(AddedPermissions), InitiatingAadUserId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingIPAddress, InitiatingUserPrincipalName, InitiatedBy, displayName, newValue
;
detailsList | project Id, displayName, newValue
| evaluate pivot(displayName, make_set(newValue))
| join kind=inner detailsList on Id
| extend ServicePrincipalObjectID = todynamic(column_ifexists("ServicePrincipalObjectID", "")), ServicePrincipalDisplayName = todynamic(column_ifexists("ServicePrincipalDisplayName", ""))
| mv-expand ServicePrincipalObjectID, ServicePrincipalDisplayName
| project-away Id1, displayName, newValue
| extend ServicePrincipalObjectID = tostring(ServicePrincipalObjectID), ServicePrincipalDisplayName = tostring(ServicePrincipalDisplayName)
| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), EventIds = make_set(Id,200) by CorrelationId, AddedPermissions, InitiatingAadUserId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingIPAddress, InitiatingUserPrincipalName, InitiatedBy, ServicePrincipalDisplayName, ServicePrincipalObjectID
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: ServicePrincipal
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: SPID
version: 1.0.3
columnName: InitiatingAadUserId
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAppServicePrincipalId
- identifier: ObjectGuid
columnName: ServicePrincipalObjectID
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIPAddress
version: 2.0.0
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Pete Bryan
name: Microsoft Security Research
support:
tier: Community
categories:
Expand Down
55 changes: 36 additions & 19 deletions Detections/AuditLogs/ServicePrincipalAssignedPrivilegedRole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,57 @@ query: |
| extend type_ = tostring(TargetResources[0].type)
| where type_ =~ "ServicePrincipal"
| where isnotempty(TargetResources)
| extend ServicePrincipal = tostring(TargetResources[0].displayName)
| extend SPID = tostring(TargetResources[0].id)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| extend ServicePrincipalName = tostring(TargetResources[0].displayName)
| extend ServicePrincipalId = tostring(TargetResources[0].id)
| mv-expand TargetResources[0].modifiedProperties
| extend TargetResources_0_modifiedProperties = columnifexists("TargetResources_0_modifiedProperties", '')
| where isnotempty(TargetResources_0_modifiedProperties)
| where TargetResources_0_modifiedProperties.displayName =~ "Role.DisplayName"
| extend TargetRole = parse_json(tostring(TargetResources_0_modifiedProperties.newValue))
| where TargetRole contains "admin"
| extend AddedByApp = iif(
isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName)),
tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName),
tostring(parse_json(tostring(InitiatedBy.app)).displayName)
)
| extend AddedByUser = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
| extend AddedBy = iif(isnotempty(AddedByApp), AddedByApp, AddedByUser)
| extend IpAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
| project-reorder TimeGenerated, ServicePrincipal, SPID, TargetRole, AddedBy, IpAddress
| project-away AddedByApp, AddedByUser
| extend displayName = tostring(TargetResources_0_modifiedProperties.displayName), newValue = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))
| where displayName == "Role.DisplayName" and newValue contains "admin"
| extend TargetRole = newValue
| project-reorder TimeGenerated, ServicePrincipalName, ServicePrincipalId, InitiatedBy, TargetRole, InitiatingIPAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatingAppName
- identifier: AadUserId
columnName: SPID
columnName: InitiatingAppServicePrincipalId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AddedBy
version: 1.0.1
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: Account
fieldMappings:
- identifier: Name
columnName: ServicePrincipalName
- identifier: AadUserId
columnName: ServicePrincipalId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIPAddress
version: 1.1.0
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Pete Bryan
name: Microsoft Security Research
support:
tier: Community
categories:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,63 @@ relevantTechniques:
tags:
- GuestorExternalIdentities
query: |
let lookback = 1d;
AuditLogs
| where TimeGenerated > ago(lookback)
AuditLogs
| where OperationName=~ "Update user"
| where Result =~ "success"
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName) , oldValue_ = tostring(TargetResources_modifiedProperties.oldValue), newValue_ = tostring(TargetResources_modifiedProperties.newValue)
| where displayName_ == "UserPrincipalName" and oldValue_ !has "#EXT" and newValue_ has "#EXT"
| extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) , IPAddress = tostring(InitiatedBy.["user"].["ipAddress"])
| project TimeGenerated, AADTenantId, IPAddress, Initiator, displayName_, oldValue_, newValue_
| extend displayName = tostring(TargetResources_modifiedProperties.displayName),
TargetUPN_oldValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.oldValue))[0]),
TargetUPN_newValue = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue))[0])
| where displayName == "UserPrincipalName" and TargetUPN_oldValue !has "#EXT" and TargetUPN_newValue has "#EXT"
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| summarize arg_max(TimeGenerated, *) by CorrelationId
| project-reorder TimeGenerated, InitiatedBy, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, TargetUPN_oldValue, TargetUPN_newValue
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend TargetAccountName = tostring(split(TargetUPN_oldValue, "@")[0]), TargetUPNSuffix = tostring(split(TargetUPN_oldValue, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatingAppName
- identifier: AadUserId
columnName: InitiatingAppServicePrincipalId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Initiator
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: displayName_
columnName: TargetUPN_oldValue
- identifier: Name
columnName: TargetAccountName
- identifier: UPNSuffix
columnName: TargetUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
version: 1.0.2
columnName: InitiatingIPAddress
version: 1.1.0
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Ashwin Patil
name: Microsoft Security Research
support:
tier: Community
categories:
Expand Down
36 changes: 26 additions & 10 deletions Detections/AuditLogs/URLAddedtoApplicationfromUnknownDomain.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,40 +45,56 @@ query: |
| extend AddedUrls = set_difference(NewUrls, OldUrls)
| where array_length(AddedUrls) > 0
| extend UserAgent = iif(tostring(AdditionalDetails[0].key) == "User-Agent", tostring(AdditionalDetails[0].value), "")
| extend AddingUser = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)) , tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), "")
| extend AddingApp = iif(isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName)) , tostring(parse_json(tostring(InitiatedBy.app)).servicePrincipalName), "")
| extend AddedBy = iif(isnotempty(AddingUser), AddingUser, AddingApp)
| project-away AddingApp, AddingUser
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| extend AppDisplayName = tostring(TargetResources.displayName)
| extend ipAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
| where isnotempty(AddedUrls)
| mv-expand AddedUrls
| extend AddedUrls = trim(@'"', tostring(AddedUrls))
| extend Domain = extract("^(?:https?:\\/\\/)?(?:[^@\\/\\n]+@)?(?:www\\.)?([^:\\/?\\n]+)/", 1, replace_string(tolower(AddedUrls), '"', ""))
| where isnotempty(Domain)
| extend Domain = strcat(split(Domain, ".")[-2], ".", split(Domain, ".")[-1])
| where Domain !in (domains)
| project-reorder TimeGenerated, AppDisplayName, AddedUrls, AddedBy, UserAgent, ipAddress
| project-reorder TimeGenerated, AppDisplayName, AddedUrls, InitiatedBy, UserAgent, InitiatingIPAddress
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: AddedUrls
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatingAppName
- identifier: AadUserId
columnName: InitiatingAppServicePrincipalId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AddedBy
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ipAddress
version: 1.0.3
columnName: InitiatingIPAddress
version: 1.1.0
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Pete Bryan
name: Microsoft Security Research
support:
tier: Community
categories:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,59 @@ tags:
- AADSecOpsGuide
query: |
// Add the environments expected username format regex below before deploying
let user_regex = "";
AuditLogs
| where OperationName =~ "Add user"
| where Result =~ "success"
| extend userAgent = tostring(AdditionalDetails[0].value)
| extend addingUser = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
| extend addingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
| extend AddedBy = iif(isnotempty(addingUser), addingUser, addingApp)
| extend ipAddress = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
| extend AddedUser = tostring(TargetResources[0].userPrincipalName)
| where AddedUser matches regex user_regex
let user_regex = "";
AuditLogs
| where OperationName =~ "Add user"
| where Result =~ "success"
| extend userAgent = tostring(AdditionalDetails[0].value)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| extend AddedUser = tostring(TargetResources[0].userPrincipalName)
| where AddedUser matches regex user_regex
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend TargetAccountName = tostring(split(AddedUser, "@")[0]), TargetAccountUPNSuffix = tostring(split(AddedUser, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatingAppName
- identifier: AadUserId
columnName: InitiatingAppServicePrincipalId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AddedBy
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AddedUser
version: 1.0.1
- identifier: Name
columnName: TargetAccountName
- identifier: UPNSuffix
columnName: TargetAccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIPAddress
version: 1.1.0
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Pete Bryan
name: Microsoft Security Research
support:
tier: Community
categories:
Expand Down
Loading