Back
Id06360572-94a7-42a4-add7-58fb933b2353
RulenameCanary alerts to incidents
DescriptionCreates Microsoft Sentinel incidents from Thinkst Canary alerts.
SeverityHigh
TacticsLateralMovement
Exfiltration
TechniquesT1021
T1041
Required data connectorsThinkstCanary
KindNRT
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/ThinkstCanary/Analytic%20Rules/SentinelIncidentsFromThinkstCanaryAlerts.yaml
Version1.0.2
Arm template06360572-94a7-42a4-add7-58fb933b2353.json
Deploy To Azure
ThinkstCanaryIncidents_CL
| where Description != "Canary Disconnected"
| where Description != "Canary Reconnected"
| where Description != "Canary Settings Changed"
| where Description != "Fake Location"
| where Description != "Network Settings Roll-back"
| extend EventData = todynamic(RawEvent[0])
| extend IsCanarytoken = Description contains "Canarytoken"
    or LogType startswith "16"
    or LogType startswith "17"
    or isnotempty(tostring(EventData.canarytoken))
| extend PhysicalCanaryName = coalesce(tostring(Host.name), NodeId),
    PhysicalCanaryIP = coalesce(tostring(Host.ip_address), DestinationIP, IpAddress),
    TokenMemo = iff(IsCanarytoken, substring(Memo, 0, 256), ""),
    TokenType = coalesce(tostring(EventData.kind), tostring(EventData.type)),
    TokenHostname = tostring(EventData.hostname),
    TokenTarget = substring(coalesce(tostring(EventData.url), tostring(EventData.hostname), tostring(EventData.cloned_site), tostring(EventData.original_site), tostring(EventData.generic_data), tostring(EventData.location)), 0, 512),
    TokenUsername = coalesce(tostring(EventData.windows_desktopini_access_username), tostring(EventData.ms_macro_username), tostring(EventData.cmd_user_name)),
    TokenDomain = coalesce(tostring(EventData.windows_desktopini_access_domain), tostring(EventData.cmd_machine_name)),
    TokenHost = coalesce(tostring(EventData.windows_desktopini_computer_name), tostring(EventData.cmd_computer_name), tostring(EventData.cmd_workstation), tostring(EventData.cmd_machine_name)),
    TokenSourceIP = coalesce(tostring(EventData.cmd_resolved_ip), tostring(EventData.ms_macro_ip)),
    TokenCity = coalesce(tostring(EventData.geoip.city), tostring(EventData.geoip.City), tostring(EventData.City)),
    TokenCountry = coalesce(tostring(EventData.geoip.country), tostring(EventData.geoip.country_name), tostring(EventData.geoip.Country), tostring(EventData.Country)),
    TokenContext = case(
      isnotempty(tostring(EventData.client_public_key)), strcat("WireGuard public key: ", substring(tostring(EventData.client_public_key), 0, 128), "; session: ", tostring(EventData.client_session_index)),
      isnotempty(tostring(EventData.masked_card_number)), strcat("Masked card: ", tostring(EventData.masked_card_number), "; transaction: ", tostring(EventData.transaction_amount), " ", tostring(EventData.transaction_currency), "; merchant: ", tostring(EventData.merchant)),
      isnotempty(tostring(EventData.referer)), strcat("Referrer: ", substring(tostring(EventData.referer), 0, 256)),
      ""),
    UserAgent = substring(coalesce(tostring(EventData.USERAGENT), tostring(EventData.HEADERS['user-agent']), tostring(EventData.headers['User-Agent']), tostring(EventData.headers['user-agent'])), 0, 512)
| extend ActorUsername = coalesce(tostring(EventData.USERNAME), tostring(EventData.USER), tostring(EventData.FORMDATA.username), tostring(EventData.POSTDATA.username), TokenUsername),
    ActorDomain = coalesce(tostring(EventData.DOMAIN), tostring(EventData.DOMAINNAME), TokenDomain),
    ActorHost = coalesce(TokenHost, tostring(EventData.HOSTNAME)),
    Activity = coalesce(TokenContext, TokenType, tostring(EventData.INSTANCE_NAME), tostring(EventData.FUNC_NAME), tostring(EventData.METHOD), tostring(EventData.OPCODE), tostring(EventData.COMMAND), tostring(EventData.FUNCTION), Description)
| extend SourceIP = coalesce(SourceIP, tostring(EventData.src_host), TokenSourceIP),
    SourceGeo = case(isnotempty(TokenCity) and isnotempty(TokenCountry), strcat(TokenCity, ", ", TokenCountry), isnotempty(TokenCity), TokenCity, TokenCountry),
    AssetType = iff(IsCanarytoken, "Canarytoken", "Canary"),
    AssetName = iff(IsCanarytoken, coalesce(TokenMemo, TokenTarget, TokenType, NodeId), PhysicalCanaryName),
    AssetNode = NodeId,
    AssetIP = iff(IsCanarytoken, "", PhysicalCanaryIP),
    AssetLocation = iff(IsCanarytoken, "", tostring(Host.description)),
    CanaryEntityName = iff(IsCanarytoken, "", PhysicalCanaryName),
    CanaryEntityIP = iff(IsCanarytoken, "", PhysicalCanaryIP)
| extend SourceDisplay = coalesce(SourceIP, SrcHostReverse, "unknown source")
| project TimeGenerated, Description, IncidentId, AssetType, AssetName, AssetNode,
    AssetIP, AssetLocation, FlockName, TokenMemo, TokenType, TokenTarget,
    TokenHostname, ActorUsername, ActorDomain, ActorHost, SourceGeo, SourceIP,
    SourceDisplay, SrcHostReverse, DestinationPort, Activity, UserAgent, LogType,
    EventsCount, CanaryEntityName, CanaryEntityIP
suppressionDuration: 1h
name: Canary alerts to incidents
suppressionEnabled: false
query: |
  ThinkstCanaryIncidents_CL
  | where Description != "Canary Disconnected"
  | where Description != "Canary Reconnected"
  | where Description != "Canary Settings Changed"
  | where Description != "Fake Location"
  | where Description != "Network Settings Roll-back"
  | extend EventData = todynamic(RawEvent[0])
  | extend IsCanarytoken = Description contains "Canarytoken"
      or LogType startswith "16"
      or LogType startswith "17"
      or isnotempty(tostring(EventData.canarytoken))
  | extend PhysicalCanaryName = coalesce(tostring(Host.name), NodeId),
      PhysicalCanaryIP = coalesce(tostring(Host.ip_address), DestinationIP, IpAddress),
      TokenMemo = iff(IsCanarytoken, substring(Memo, 0, 256), ""),
      TokenType = coalesce(tostring(EventData.kind), tostring(EventData.type)),
      TokenHostname = tostring(EventData.hostname),
      TokenTarget = substring(coalesce(tostring(EventData.url), tostring(EventData.hostname), tostring(EventData.cloned_site), tostring(EventData.original_site), tostring(EventData.generic_data), tostring(EventData.location)), 0, 512),
      TokenUsername = coalesce(tostring(EventData.windows_desktopini_access_username), tostring(EventData.ms_macro_username), tostring(EventData.cmd_user_name)),
      TokenDomain = coalesce(tostring(EventData.windows_desktopini_access_domain), tostring(EventData.cmd_machine_name)),
      TokenHost = coalesce(tostring(EventData.windows_desktopini_computer_name), tostring(EventData.cmd_computer_name), tostring(EventData.cmd_workstation), tostring(EventData.cmd_machine_name)),
      TokenSourceIP = coalesce(tostring(EventData.cmd_resolved_ip), tostring(EventData.ms_macro_ip)),
      TokenCity = coalesce(tostring(EventData.geoip.city), tostring(EventData.geoip.City), tostring(EventData.City)),
      TokenCountry = coalesce(tostring(EventData.geoip.country), tostring(EventData.geoip.country_name), tostring(EventData.geoip.Country), tostring(EventData.Country)),
      TokenContext = case(
        isnotempty(tostring(EventData.client_public_key)), strcat("WireGuard public key: ", substring(tostring(EventData.client_public_key), 0, 128), "; session: ", tostring(EventData.client_session_index)),
        isnotempty(tostring(EventData.masked_card_number)), strcat("Masked card: ", tostring(EventData.masked_card_number), "; transaction: ", tostring(EventData.transaction_amount), " ", tostring(EventData.transaction_currency), "; merchant: ", tostring(EventData.merchant)),
        isnotempty(tostring(EventData.referer)), strcat("Referrer: ", substring(tostring(EventData.referer), 0, 256)),
        ""),
      UserAgent = substring(coalesce(tostring(EventData.USERAGENT), tostring(EventData.HEADERS['user-agent']), tostring(EventData.headers['User-Agent']), tostring(EventData.headers['user-agent'])), 0, 512)
  | extend ActorUsername = coalesce(tostring(EventData.USERNAME), tostring(EventData.USER), tostring(EventData.FORMDATA.username), tostring(EventData.POSTDATA.username), TokenUsername),
      ActorDomain = coalesce(tostring(EventData.DOMAIN), tostring(EventData.DOMAINNAME), TokenDomain),
      ActorHost = coalesce(TokenHost, tostring(EventData.HOSTNAME)),
      Activity = coalesce(TokenContext, TokenType, tostring(EventData.INSTANCE_NAME), tostring(EventData.FUNC_NAME), tostring(EventData.METHOD), tostring(EventData.OPCODE), tostring(EventData.COMMAND), tostring(EventData.FUNCTION), Description)
  | extend SourceIP = coalesce(SourceIP, tostring(EventData.src_host), TokenSourceIP),
      SourceGeo = case(isnotempty(TokenCity) and isnotempty(TokenCountry), strcat(TokenCity, ", ", TokenCountry), isnotempty(TokenCity), TokenCity, TokenCountry),
      AssetType = iff(IsCanarytoken, "Canarytoken", "Canary"),
      AssetName = iff(IsCanarytoken, coalesce(TokenMemo, TokenTarget, TokenType, NodeId), PhysicalCanaryName),
      AssetNode = NodeId,
      AssetIP = iff(IsCanarytoken, "", PhysicalCanaryIP),
      AssetLocation = iff(IsCanarytoken, "", tostring(Host.description)),
      CanaryEntityName = iff(IsCanarytoken, "", PhysicalCanaryName),
      CanaryEntityIP = iff(IsCanarytoken, "", PhysicalCanaryIP)
  | extend SourceDisplay = coalesce(SourceIP, SrcHostReverse, "unknown source")
  | project TimeGenerated, Description, IncidentId, AssetType, AssetName, AssetNode,
      AssetIP, AssetLocation, FlockName, TokenMemo, TokenType, TokenTarget,
      TokenHostname, ActorUsername, ActorDomain, ActorHost, SourceGeo, SourceIP,
      SourceDisplay, SrcHostReverse, DestinationPort, Activity, UserAgent, LogType,
      EventsCount, CanaryEntityName, CanaryEntityIP
description: Creates Microsoft Sentinel incidents from Thinkst Canary alerts.
id: 06360572-94a7-42a4-add7-58fb933b2353
kind: NRT
version: 1.0.2
status: Available
customDetails:
  TokenType: TokenType
  LogType: LogType
  ActorUsername: ActorUsername
  AssetIP: AssetIP
  TokenTarget: TokenTarget
  DestinationPort: DestinationPort
  SourceGeo: SourceGeo
  AssetLocation: AssetLocation
  AssetNode: AssetNode
  AssetType: AssetType
  Activity: Activity
  IncidentKey: IncidentId
  EventsCount: EventsCount
  ActorDomain: ActorDomain
  ActorHost: ActorHost
  AssetName: AssetName
  UserAgent: UserAgent
  TokenMemo: TokenMemo
  FlockName: FlockName
  SourceIP: SourceIP
relevantTechniques:
- T1021
- T1041
eventGroupingSettings:
  aggregationKind: AlertPerResult
severity: High
requiredDataConnectors:
- connectorId: ThinkstCanary
  dataTypes:
  - ThinkstCanaryIncidents_CL
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/ThinkstCanary/Analytic%20Rules/SentinelIncidentsFromThinkstCanaryAlerts.yaml
incidentConfiguration:
  groupingConfiguration:
    lookbackDuration: PT5H
    reopenClosedIncident: false
    matchingMethod: AllEntities
    enabled: false
  createIncident: true
alertDetailsOverride:
  alertDescriptionFormat: Thinkst {{AssetType}} {{AssetName}} recorded this activity from {{SourceDisplay}}. Review the mapped entities and custom details for asset, actor, and activity context.
  alertDisplayNameFormat: '{{Description}} - {{AssetName}} from {{SourceDisplay}}'
tactics:
- LateralMovement
- Exfiltration
entityMappings:
- fieldMappings:
  - identifier: Address
    columnName: SourceIP
  entityType: IP
- fieldMappings:
  - identifier: Address
    columnName: CanaryEntityIP
  entityType: IP
- fieldMappings:
  - identifier: HostName
    columnName: CanaryEntityName
  entityType: Host
- fieldMappings:
  - identifier: Name
    columnName: ActorUsername
  entityType: Account
- fieldMappings:
  - identifier: DomainName
    columnName: TokenHostname
  entityType: DNS
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/06360572-94a7-42a4-add7-58fb933b2353')]",
      "kind": "NRT",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/06360572-94a7-42a4-add7-58fb933b2353')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "Thinkst {{AssetType}} {{AssetName}} recorded this activity from {{SourceDisplay}}. Review the mapped entities and custom details for asset, actor, and activity context.",
          "alertDisplayNameFormat": "{{Description}} - {{AssetName}} from {{SourceDisplay}}"
        },
        "alertRuleTemplateName": "06360572-94a7-42a4-add7-58fb933b2353",
        "customDetails": {
          "Activity": "Activity",
          "ActorDomain": "ActorDomain",
          "ActorHost": "ActorHost",
          "ActorUsername": "ActorUsername",
          "AssetIP": "AssetIP",
          "AssetLocation": "AssetLocation",
          "AssetName": "AssetName",
          "AssetNode": "AssetNode",
          "AssetType": "AssetType",
          "DestinationPort": "DestinationPort",
          "EventsCount": "EventsCount",
          "FlockName": "FlockName",
          "IncidentKey": "IncidentId",
          "LogType": "LogType",
          "SourceGeo": "SourceGeo",
          "SourceIP": "SourceIP",
          "TokenMemo": "TokenMemo",
          "TokenTarget": "TokenTarget",
          "TokenType": "TokenType",
          "UserAgent": "UserAgent"
        },
        "description": "Creates Microsoft Sentinel incidents from Thinkst Canary alerts.",
        "displayName": "Canary alerts to incidents",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIP",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "CanaryEntityIP",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "Host",
            "fieldMappings": [
              {
                "columnName": "CanaryEntityName",
                "identifier": "HostName"
              }
            ]
          },
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "ActorUsername",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "DNS",
            "fieldMappings": [
              {
                "columnName": "TokenHostname",
                "identifier": "DomainName"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": false,
            "lookbackDuration": "PT5H",
            "matchingMethod": "AllEntities",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/ThinkstCanary/Analytic%20Rules/SentinelIncidentsFromThinkstCanaryAlerts.yaml",
        "query": "ThinkstCanaryIncidents_CL\n| where Description != \"Canary Disconnected\"\n| where Description != \"Canary Reconnected\"\n| where Description != \"Canary Settings Changed\"\n| where Description != \"Fake Location\"\n| where Description != \"Network Settings Roll-back\"\n| extend EventData = todynamic(RawEvent[0])\n| extend IsCanarytoken = Description contains \"Canarytoken\"\n    or LogType startswith \"16\"\n    or LogType startswith \"17\"\n    or isnotempty(tostring(EventData.canarytoken))\n| extend PhysicalCanaryName = coalesce(tostring(Host.name), NodeId),\n    PhysicalCanaryIP = coalesce(tostring(Host.ip_address), DestinationIP, IpAddress),\n    TokenMemo = iff(IsCanarytoken, substring(Memo, 0, 256), \"\"),\n    TokenType = coalesce(tostring(EventData.kind), tostring(EventData.type)),\n    TokenHostname = tostring(EventData.hostname),\n    TokenTarget = substring(coalesce(tostring(EventData.url), tostring(EventData.hostname), tostring(EventData.cloned_site), tostring(EventData.original_site), tostring(EventData.generic_data), tostring(EventData.location)), 0, 512),\n    TokenUsername = coalesce(tostring(EventData.windows_desktopini_access_username), tostring(EventData.ms_macro_username), tostring(EventData.cmd_user_name)),\n    TokenDomain = coalesce(tostring(EventData.windows_desktopini_access_domain), tostring(EventData.cmd_machine_name)),\n    TokenHost = coalesce(tostring(EventData.windows_desktopini_computer_name), tostring(EventData.cmd_computer_name), tostring(EventData.cmd_workstation), tostring(EventData.cmd_machine_name)),\n    TokenSourceIP = coalesce(tostring(EventData.cmd_resolved_ip), tostring(EventData.ms_macro_ip)),\n    TokenCity = coalesce(tostring(EventData.geoip.city), tostring(EventData.geoip.City), tostring(EventData.City)),\n    TokenCountry = coalesce(tostring(EventData.geoip.country), tostring(EventData.geoip.country_name), tostring(EventData.geoip.Country), tostring(EventData.Country)),\n    TokenContext = case(\n      isnotempty(tostring(EventData.client_public_key)), strcat(\"WireGuard public key: \", substring(tostring(EventData.client_public_key), 0, 128), \"; session: \", tostring(EventData.client_session_index)),\n      isnotempty(tostring(EventData.masked_card_number)), strcat(\"Masked card: \", tostring(EventData.masked_card_number), \"; transaction: \", tostring(EventData.transaction_amount), \" \", tostring(EventData.transaction_currency), \"; merchant: \", tostring(EventData.merchant)),\n      isnotempty(tostring(EventData.referer)), strcat(\"Referrer: \", substring(tostring(EventData.referer), 0, 256)),\n      \"\"),\n    UserAgent = substring(coalesce(tostring(EventData.USERAGENT), tostring(EventData.HEADERS['user-agent']), tostring(EventData.headers['User-Agent']), tostring(EventData.headers['user-agent'])), 0, 512)\n| extend ActorUsername = coalesce(tostring(EventData.USERNAME), tostring(EventData.USER), tostring(EventData.FORMDATA.username), tostring(EventData.POSTDATA.username), TokenUsername),\n    ActorDomain = coalesce(tostring(EventData.DOMAIN), tostring(EventData.DOMAINNAME), TokenDomain),\n    ActorHost = coalesce(TokenHost, tostring(EventData.HOSTNAME)),\n    Activity = coalesce(TokenContext, TokenType, tostring(EventData.INSTANCE_NAME), tostring(EventData.FUNC_NAME), tostring(EventData.METHOD), tostring(EventData.OPCODE), tostring(EventData.COMMAND), tostring(EventData.FUNCTION), Description)\n| extend SourceIP = coalesce(SourceIP, tostring(EventData.src_host), TokenSourceIP),\n    SourceGeo = case(isnotempty(TokenCity) and isnotempty(TokenCountry), strcat(TokenCity, \", \", TokenCountry), isnotempty(TokenCity), TokenCity, TokenCountry),\n    AssetType = iff(IsCanarytoken, \"Canarytoken\", \"Canary\"),\n    AssetName = iff(IsCanarytoken, coalesce(TokenMemo, TokenTarget, TokenType, NodeId), PhysicalCanaryName),\n    AssetNode = NodeId,\n    AssetIP = iff(IsCanarytoken, \"\", PhysicalCanaryIP),\n    AssetLocation = iff(IsCanarytoken, \"\", tostring(Host.description)),\n    CanaryEntityName = iff(IsCanarytoken, \"\", PhysicalCanaryName),\n    CanaryEntityIP = iff(IsCanarytoken, \"\", PhysicalCanaryIP)\n| extend SourceDisplay = coalesce(SourceIP, SrcHostReverse, \"unknown source\")\n| project TimeGenerated, Description, IncidentId, AssetType, AssetName, AssetNode,\n    AssetIP, AssetLocation, FlockName, TokenMemo, TokenType, TokenTarget,\n    TokenHostname, ActorUsername, ActorDomain, ActorHost, SourceGeo, SourceIP,\n    SourceDisplay, SrcHostReverse, DestinationPort, Activity, UserAgent, LogType,\n    EventsCount, CanaryEntityName, CanaryEntityIP\n",
        "severity": "High",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Exfiltration",
          "LateralMovement"
        ],
        "techniques": [
          "T1021",
          "T1041"
        ],
        "templateVersion": "1.0.2"
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}