Detection rules › Kusto

SlackAudit - Public link created for file which can contain sensitive information.

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

'Detects public links created for files that may contain sensitive data such as passwords, authentication tokens, secret keys, or private configuration files. Tune exclusions using the SlackAuditSensitiveFile_Allowlist_File and SlackAuditSensitiveFile_Allowlist_Account watchlists when known benign files or accounts generate expected public-link activity.'

MITRE ATT&CK coverage

Rule body

id: 279316e8-8965-47d2-9788-b94dc352c853
name: SlackAudit - Public link created for file which can contain sensitive information.
description: |
  'Detects public links created for files that may contain sensitive data such as passwords, authentication tokens,
  secret keys, or private configuration files. Tune exclusions using the SlackAuditSensitiveFile_Allowlist_File and SlackAuditSensitiveFile_Allowlist_Account
  watchlists when known benign files or accounts generate expected public-link activity.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SlackAuditAPI
    dataTypes:
      - SlackAudit_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
relevantTechniques:
  - T1048
  - T1567.002
query: |
  let AllowedFiles = toscalar(_GetWatchlist('SlackAuditSensitiveFile_Allowlist_File') | summarize make_set(tostring(SearchKey)));
  let AllowedUsers = toscalar(_GetWatchlist('SlackAuditSensitiveFile_Allowlist_Account') | summarize make_set(tostring(SearchKey)));
  SlackAudit
  | where Action =~ 'file_public_link_created'
  | extend FileNameLower = tolower(EntityFileName), UserLower = tolower(SrcUserName)
  | where EntityFileName in~ ('id_rsa')
      or FileNameLower has_any ('password', 'secret', 'token', 'credential', 'private key', 'api key')
      or FileNameLower has_any ('.ssh', '.npmrc', '.muttrc', '.gitconfig', '.netrc', 'package.json', 'Gemfile', 'bower.json', 'config.gypi', 'travis.yml', 'config.json')
  | where isempty(AllowedFiles) or EntityFileName !in~ (AllowedFiles)
  | where isempty(AllowedUsers) or UserLower !in~ (AllowedUsers)
  | extend AccountCustomEntity = SrcUserName
  | extend IPCustomEntity = SrcIpAddr
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountCustomEntity
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
alertDetailsOverride:
  alertDisplayNameFormat: Slack public link created for sensitive file {{EntityFileName}} by {{SrcUserName}}
  alertDescriptionFormat: Public link created for {{EntityFileName}} by {{SrcUserName}} from {{SrcIpAddr}}
customDetails:
  FileName: EntityFileName
  Action: Action
  SourceUser: SrcUserName
  SourceIP: SrcIpAddr
  ActorEntity: AccountCustomEntity
  IpEntity: IPCustomEntity
version: 1.0.1
kind: Scheduled

Stages and Predicates

Let binding: AllowedFiles used in Stage 5

let AllowedFiles = toscalar(_GetWatchlist('SlackAuditSensitiveFile_Allowlist_File') | summarize make_set(tostring(SearchKey)));

Let binding: AllowedUsers used in Stage 6

let AllowedUsers = toscalar(_GetWatchlist('SlackAuditSensitiveFile_Allowlist_Account') | summarize make_set(tostring(SearchKey)));

Stage 1: source

SlackAudit

Stage 2: where

| where Action =~ 'file_public_link_created'

Stage 3: extend

| extend FileNameLower = tolower(EntityFileName), UserLower = tolower(SrcUserName)

Stage 4: where

| where EntityFileName in~ ('id_rsa')
    or FileNameLower has_any ('password', 'secret', 'token', 'credential', 'private key', 'api key')
    or FileNameLower has_any ('.ssh', '.npmrc', '.muttrc', '.gitconfig', '.netrc', 'package.json', 'Gemfile', 'bower.json', 'config.gypi', 'travis.yml', 'config.json')

Stage 5: where

| where isempty(AllowedFiles) or EntityFileName !in~ (AllowedFiles)

Stage 6: where

| where isempty(AllowedUsers) or UserLower !in~ (AllowedUsers)

Stage 7: extend

| extend AccountCustomEntity = SrcUserName

Stage 8: extend

| extend IPCustomEntity = SrcIpAddr

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Actioneq
  • file_public_link_created
field:"Action" kind:eq value:"file_public_link_created"
AllowedFilesis_null
  • (no value, null check)
field:"AllowedFiles" kind:is_null
AllowedUsersis_null
  • (no value, null check)
field:"AllowedUsers" kind:is_null
EntityFileNamein
  • id_rsa
field:"EntityFileName" kind:in value:"id_rsa"
FileNameLowermatch
  • .gitconfig transforms: term
  • .muttrc transforms: term
  • .netrc transforms: term
  • .npmrc transforms: term
  • .ssh transforms: term
  • Gemfile transforms: term
  • api key transforms: term
  • bower.json transforms: term
  • config.gypi transforms: term
  • config.json transforms: term
  • credential transforms: term
  • package.json transforms: term
  • password transforms: term
  • private key transforms: term
  • secret transforms: term
  • token transforms: term
  • travis.yml transforms: term
field:"FileNameLower" kind:match

Output fields

These fields are emitted when the rule matches.

FieldSource
FileNameLowerextend
UserLowerextend
AccountCustomEntityextend
IPCustomEntityextend