// Change to true to monitor for Project Administrator adds to *any* project
let MonitorAllProjects = false;
// If MonitorAllProjects is false, trigger only on Project Administrator add for the following projects
let ProjectsToMonitor = dynamic(['<project_X>','<project_Y>']);
ADOAuditLogs
| where Area == "Group" and OperationName == "Group.UpdateGroupMembership.Add"
| where Details has 'Administrators'
| where Details has "was added as a member of group" and (Details endswith '\\Project Administrators' or Details endswith '\\Project Collection Administrators')
| parse Details with AddedIdentity ' was added as a member of group [' EntityName ']\\' GroupName
| extend Level = iif(GroupName == 'Project Collection Administrators', 'Organization', 'Project'), AddedIdentityId = Data.MemberId
| extend Severity = iif(Level == 'Organization', 'High', 'Medium'), AlertDetails = strcat('At ', TimeGenerated, ' UTC ', ActorUPN, '/', ActorDisplayName, ' added ', AddedIdentity, ' to the ', EntityName, ' ', Level)
| where MonitorAllProjects == true or EntityName in (ProjectsToMonitor) or Level == 'Organization'
| project TimeGenerated, Severity, Adder = ActorUPN, AddedIdentity, AddedIdentityId, AlertDetails, Level, EntityName, GroupName, ActorAuthType = AuthenticationMechanism,
ActorIpAddress = IpAddress, ActorUserAgent = UserAgent, RawDetails = Details
| extend timestamp = TimeGenerated
| extend AccountName = tostring(split(Adder, "@")[0]), AccountUPNSuffix = tostring(split(Adder, "@")[1])
description: |
'This detection monitors for additions to projects or project collection administration groups in an Azure DevOps Organization.'
kind: Scheduled
tactics:
- Persistence
requiredDataConnectors: []
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AzureDevOpsAuditing/Analytic Rules/AzDOAdminGroupAdditions.yaml
severity: Medium
name: Azure DevOps Administrator Group Monitoring
triggerThreshold: 0
queryPeriod: 4h
query: |
// Change to true to monitor for Project Administrator adds to *any* project
let MonitorAllProjects = false;
// If MonitorAllProjects is false, trigger only on Project Administrator add for the following projects
let ProjectsToMonitor = dynamic(['<project_X>','<project_Y>']);
ADOAuditLogs
| where Area == "Group" and OperationName == "Group.UpdateGroupMembership.Add"
| where Details has 'Administrators'
| where Details has "was added as a member of group" and (Details endswith '\\Project Administrators' or Details endswith '\\Project Collection Administrators')
| parse Details with AddedIdentity ' was added as a member of group [' EntityName ']\\' GroupName
| extend Level = iif(GroupName == 'Project Collection Administrators', 'Organization', 'Project'), AddedIdentityId = Data.MemberId
| extend Severity = iif(Level == 'Organization', 'High', 'Medium'), AlertDetails = strcat('At ', TimeGenerated, ' UTC ', ActorUPN, '/', ActorDisplayName, ' added ', AddedIdentity, ' to the ', EntityName, ' ', Level)
| where MonitorAllProjects == true or EntityName in (ProjectsToMonitor) or Level == 'Organization'
| project TimeGenerated, Severity, Adder = ActorUPN, AddedIdentity, AddedIdentityId, AlertDetails, Level, EntityName, GroupName, ActorAuthType = AuthenticationMechanism,
ActorIpAddress = IpAddress, ActorUserAgent = UserAgent, RawDetails = Details
| extend timestamp = TimeGenerated
| extend AccountName = tostring(split(Adder, "@")[0]), AccountUPNSuffix = tostring(split(Adder, "@")[1])
relevantTechniques:
- T1098
id: 89e6adbd-612c-4fbe-bc3d-32f81baf3b6c
queryFrequency: 4h
status: Available
triggerOperator: gt
version: 1.0.5
entityMappings:
- entityType: Account
fieldMappings:
- columnName: Adder
identifier: FullName
- columnName: AccountName
identifier: Name
- columnName: AccountUPNSuffix
identifier: UPNSuffix
- entityType: IP
fieldMappings:
- columnName: ActorIpAddress
identifier: Address