Detection rules › Kusto

Azure DevOps Personal Access Token (PAT) misuse

Status
available
Severity
high
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'This Alert detects whenever a PAT is used in ways that PATs are not normally used. May require an allow list and baselining. Reference - https://docs.microsoft.com/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page Use this query for baselining: ADOAuditLogs | distinct OperationName'

MITRE ATT&CK coverage

Rule body

id: ac891683-53c3-4f86-86b4-c361708e2b2b
name: Azure DevOps Personal Access Token (PAT) misuse
description: |
  'This Alert detects whenever a PAT is used in ways that PATs are not normally used. May require an allow list and baselining.
  Reference - https://docs.microsoft.com/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
  Use this query for baselining:
  ADOAuditLogs
  | distinct OperationName'
severity: High
status: Available
requiredDataConnectors: []
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Execution
  - Impact
relevantTechniques:
  - T1496
  - T1559
query: |
  // Allowlisted UPNs should likely stay empty
  let AllowlistedUpns = datatable(UPN:string)['foo@bar.com', 'test@foo.com'];
  // Operation Name parts that will alert
  let HasAnyBlocklist = datatable(OperationNamePart:string)['Security.','Project.','AuditLog.','Extension.'];
  // Distinct Operation Names that will flag
  let HasExactBlocklist = datatable(OperationName:string)['Group.UpdateGroupMembership.Add','Library.ServiceConnectionExecuted','Pipelines.PipelineModified',
  'Release.ReleasePipelineModified', 'Git.RefUpdatePoliciesBypassed'];
  ADOAuditLogs
  | where AuthenticationMechanism startswith "PAT" and (OperationName has_any (HasAnyBlocklist) or OperationName in (HasExactBlocklist))
    and ActorUPN !in (AllowlistedUpns)
  | project TimeGenerated, AuthenticationMechanism, ProjectName, ActorUPN, ActorDisplayName, IpAddress, UserAgent, OperationName, Details, Data
  | extend timestamp = TimeGenerated
  | extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: ActorUPN
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IpAddress
version: 1.0.6
kind: Scheduled

Stages and Predicates

Let binding: AllowlistedUpns used in Stage 2

let AllowlistedUpns = datatable(UPN:string)['foo@bar.com', 'test@foo.com'];

Let binding: HasAnyBlocklist used in Stage 2

let HasAnyBlocklist = datatable(OperationNamePart:string)['Security.','Project.','AuditLog.','Extension.'];

Let binding: HasExactBlocklist used in Stage 2

let HasExactBlocklist = datatable(OperationName:string)['Group.UpdateGroupMembership.Add','Library.ServiceConnectionExecuted','Pipelines.PipelineModified',
'Release.ReleasePipelineModified', 'Git.RefUpdatePoliciesBypassed'];

Stage 1: source

ADOAuditLogs

Stage 2: where

| where AuthenticationMechanism startswith "PAT" and (OperationName has_any (HasAnyBlocklist) or OperationName in (HasExactBlocklist))
  and ActorUPN !in (AllowlistedUpns)

Stage 3: project

| project TimeGenerated, AuthenticationMechanism, ProjectName, ActorUPN, ActorDisplayName, IpAddress, UserAgent, OperationName, Details, Data

Stage 4: extend

| extend timestamp = TimeGenerated

Stage 5: extend

| extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
ActorUPNeqAllowlistedUpnsexcludes:ActorUPN field:"ActorUPN" value:"AllowlistedUpns"

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
ActorDisplayNameproject
ActorUPNproject
AuthenticationMechanismproject
Dataproject
Detailsproject
IpAddressproject
OperationNameproject
ProjectNameproject
TimeGeneratedproject
UserAgentproject
timestampextend
AccountNameextend
AccountUPNSuffixextend