Detection rules › Kusto

1Password - Non-privileged vault user permission change

Severity
medium
Time window
5m
Source
github.com/Azure/Azure-Sentinel

This will alert when user permissions have changed within a non-privileged vault which have been implemented by an actor that was not the target user account. Once this analytics rule is triggered it will group all related future alerts for upto an hour when all related entities are the same. Ref: https://1password.com/ Ref: https://github.com/securehats/

MITRE ATT&CK coverage

TacticTechniques
Persistence

Telemetry coverage

Rule body

id: 327e0579-7c03-4ec7-acf5-a29dcc4a12b6
name: 1Password - Non-privileged vault user permission change
version: 1.0.0
kind: Scheduled
description: |-
  This will alert when user permissions have changed within a non-privileged vault which have been implemented by an actor that was not the target user account. Once this analytics rule is triggered it will group all related future alerts for upto an hour when all related entities are the same.

  Ref: https://1password.com/
  Ref: https://github.com/securehats/
severity: Medium
requiredDataConnectors:
  - connectorId: 1Password
    dataTypes:
      - OnePasswordEventLogs_CL
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1098
query: |-
  let watchlist =
      _GetWatchlist("PV1PW")
      | project SearchKey
  ;
  // Insert the vault UUIDs below when using the dynamic vaults list within the analytics rule itself
  let vaults = dynamic([""]);
  OnePasswordEventLogs_CL
  | where log_source == "auditevents"
  | where action has_any("grant", "revoke", "update")
  | where object_type == "uva"
  | where tostring(actor_details.email) != tostring(aux_details.email)
  // Enable the line below when using the "Privileged Vaults - 1PW" watchlist
  | where object_uuid !in (watchlist)
  // Enable the line below when using the dynamic vaults list within the analytics rule itself
  // | where object_uuid !in (vaults)
  | extend
      TargetUsername = aux_details.email
      , ActorUsername = actor_details.email
      , SrcIpAddr = session.ip
suppressionEnabled: false
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 1h
    matchingMethod: AllEntities
suppressionDuration: 5h
eventGroupingSettings:
  aggregationKind: SingleAlert
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: FullName
    columnName: ActorUsername
- entityType: Account
  fieldMappings:
  - identifier: FullName
    columnName: TargetUsername
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SrcIpAddr

Stages and Predicates

Parameters

let vaults = dynamic([""]);

Let binding: watchlist used in Stage 6

let watchlist = _GetWatchlist("PV1PW")
    | project SearchKey;

Stage 1: source

OnePasswordEventLogs_CL

Stage 2: where

| where log_source == "auditevents"

Stage 3: where

| where action has_any("grant", "revoke", "update")

Stage 4: where

| where object_type == "uva"

Stage 5: where

| where tostring(actor_details.email) != tostring(aux_details.email)

Stage 6: where

| where object_uuid !in (watchlist)

Stage 7: extend

| extend
    TargetUsername = aux_details.email
    , ActorUsername = actor_details.email
    , SrcIpAddr = session.ip

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
object_uuideqwatchlistexcludes:object_uuid field:"object_uuid" value:"watchlist"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actionmatch
  • grant transforms: term
  • revoke transforms: term
  • update transforms: term
field:"action" kind:match
log_sourceeq
  • auditevents
field:"log_source" kind:eq value:"auditevents"
object_typeeq
  • uva
field:"object_type" kind:eq value:"uva"

Output fields

These fields are emitted when the rule matches.

FieldSource
ActorUsernameextend
SrcIpAddrextend
TargetUsernameextend