Back
Ide3a8b2f1-5c7d-4d89-9b6e-0f1a2c3d4e5f
RulenameStealthTalk - After hours work
DescriptionIdentifies systematic off-hours activity for a single StealthTalk user - repeated authentications

outside the user’s configured working hours OR on weekends, observed across at least two

distinct calendar days within a 48-hour window. The pattern is a common indicator of credential

misuse, insider threat, or compromise of the account by an attacker operating in a different

timezone.



An “off-hours event” is one where IsWeekend=true OR DeviationMinutes >= 180 (i.e. >= 3 hours

after the configured working-hours end). Three or more such events on at least two distinct

days are required for an incident to fire - a single late-evening login is not enough.
SeverityLow
TacticsInitialAccess
DefenseEvasion
Persistence
TechniquesT1078
Required data connectorsStealthTalkAnomalousAuth
KindScheduled
Query frequency1h
Query period2d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/StealthTalk/Analytic%20Rules/AfterHoursWork.yaml
Version1.0.0
Arm templatee3a8b2f1-5c7d-4d89-9b6e-0f1a2c3d4e5f.json
Deploy To Azure
let LookbackPeriod    = 48h;
let MinAttempts       = 3;
let MinDistinctDays   = 2;
let OffHoursThreshold = 180;
StealthTalkAnomalousAuth_CL
| where TimeGenerated >= ago(LookbackPeriod)
| where EventType == "OffHoursLogin"
| where IsWeekend == true or DeviationMinutes >= OffHoursThreshold
| summarize
    AttemptCount   = count(),
    DistinctDays   = dcount(startofday(TimeGenerated)),
    FirstSeen      = min(TimeGenerated),
    LastSeen       = max(TimeGenerated),
    DeviceIds      = make_set(DeviceId),
    MaxDeviation   = max(DeviationMinutes),
    WeekendsCount  = countif(IsWeekend == true),
    AppVersions    = make_set(AppVersion)
  by UserId
| where AttemptCount >= MinAttempts and DistinctDays >= MinDistinctDays
| extend
    AlertName    = "AfterHoursWork",
    AlertDetails = strcat(
        "User ", UserId,
        " performed ", AttemptCount, " off-hours logins",
        " across ", DistinctDays, " distinct days.",
        " Max deviation from working hours: ", MaxDeviation, " min.",
        " Weekend logins: ", WeekendsCount, "."
    )
| project
    TimeGenerated = LastSeen,
    UserId, AttemptCount, DistinctDays, MaxDeviation,
    WeekendsCount, DeviceIds, AppVersions, FirstSeen, LastSeen,
    AlertName, AlertDetails
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    groupByEntities:
    - Account
    enabled: true
    matchingMethod: Selected
    reopenClosedIncident: false
    lookbackDuration: 5h
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: UserId
    identifier: Name
query: |
  let LookbackPeriod    = 48h;
  let MinAttempts       = 3;
  let MinDistinctDays   = 2;
  let OffHoursThreshold = 180;
  StealthTalkAnomalousAuth_CL
  | where TimeGenerated >= ago(LookbackPeriod)
  | where EventType == "OffHoursLogin"
  | where IsWeekend == true or DeviationMinutes >= OffHoursThreshold
  | summarize
      AttemptCount   = count(),
      DistinctDays   = dcount(startofday(TimeGenerated)),
      FirstSeen      = min(TimeGenerated),
      LastSeen       = max(TimeGenerated),
      DeviceIds      = make_set(DeviceId),
      MaxDeviation   = max(DeviationMinutes),
      WeekendsCount  = countif(IsWeekend == true),
      AppVersions    = make_set(AppVersion)
    by UserId
  | where AttemptCount >= MinAttempts and DistinctDays >= MinDistinctDays
  | extend
      AlertName    = "AfterHoursWork",
      AlertDetails = strcat(
          "User ", UserId,
          " performed ", AttemptCount, " off-hours logins",
          " across ", DistinctDays, " distinct days.",
          " Max deviation from working hours: ", MaxDeviation, " min.",
          " Weekend logins: ", WeekendsCount, "."
      )
  | project
      TimeGenerated = LastSeen,
      UserId, AttemptCount, DistinctDays, MaxDeviation,
      WeekendsCount, DeviceIds, AppVersions, FirstSeen, LastSeen,
      AlertName, AlertDetails
suppressionEnabled: false
id: e3a8b2f1-5c7d-4d89-9b6e-0f1a2c3d4e5f
queryFrequency: 1h
alertDetailsOverride:
  alertDisplayNameFormat: 'StealthTalk: After-Hours Work - {{UserId}} ({{AttemptCount}} events / {{DistinctDays}} days)'
  alertDescriptionFormat: '{{AlertDetails}}'
status: Available
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/StealthTalk/Analytic%20Rules/AfterHoursWork.yaml
suppressionDuration: 5h
version: 1.0.0
severity: Low
relevantTechniques:
- T1078
name: StealthTalk - After hours work
kind: Scheduled
tactics:
- InitialAccess
- DefenseEvasion
- Persistence
requiredDataConnectors:
- dataTypes:
  - StealthTalkAnomalousAuth_CL
  connectorId: StealthTalkAnomalousAuth
description: |
  Identifies systematic off-hours activity for a single StealthTalk user - repeated authentications
  outside the user's configured working hours OR on weekends, observed across at least two
  distinct calendar days within a 48-hour window. The pattern is a common indicator of credential
  misuse, insider threat, or compromise of the account by an attacker operating in a different
  timezone.

  An "off-hours event" is one where IsWeekend=true OR DeviationMinutes >= 180 (i.e. >= 3 hours
  after the configured working-hours end). Three or more such events on at least two distinct
  days are required for an incident to fire - a single late-evening login is not enough.
customDetails:
  WeekendsCount: WeekendsCount
  DistinctDays: DistinctDays
  AttemptCount: AttemptCount
  MaxDeviation: MaxDeviation
  LastSeen: LastSeen
  FirstSeen: FirstSeen
triggerOperator: gt
triggerThreshold: 0
queryPeriod: 2d
{
  "$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/e3a8b2f1-5c7d-4d89-9b6e-0f1a2c3d4e5f')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/e3a8b2f1-5c7d-4d89-9b6e-0f1a2c3d4e5f')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "{{AlertDetails}}",
          "alertDisplayNameFormat": "StealthTalk: After-Hours Work - {{UserId}} ({{AttemptCount}} events / {{DistinctDays}} days)"
        },
        "alertRuleTemplateName": "e3a8b2f1-5c7d-4d89-9b6e-0f1a2c3d4e5f",
        "customDetails": {
          "AttemptCount": "AttemptCount",
          "DistinctDays": "DistinctDays",
          "FirstSeen": "FirstSeen",
          "LastSeen": "LastSeen",
          "MaxDeviation": "MaxDeviation",
          "WeekendsCount": "WeekendsCount"
        },
        "description": "Identifies systematic off-hours activity for a single StealthTalk user - repeated authentications\noutside the user's configured working hours OR on weekends, observed across at least two\ndistinct calendar days within a 48-hour window. The pattern is a common indicator of credential\nmisuse, insider threat, or compromise of the account by an attacker operating in a different\ntimezone.\n\nAn \"off-hours event\" is one where IsWeekend=true OR DeviationMinutes >= 180 (i.e. >= 3 hours\nafter the configured working-hours end). Three or more such events on at least two distinct\ndays are required for an incident to fire - a single late-evening login is not enough.\n",
        "displayName": "StealthTalk - After hours work",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "UserId",
                "identifier": "Name"
              }
            ]
          }
        ],
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": true,
            "groupByEntities": [
              "Account"
            ],
            "lookbackDuration": "PT5H",
            "matchingMethod": "Selected",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/StealthTalk/Analytic%20Rules/AfterHoursWork.yaml",
        "query": "let LookbackPeriod    = 48h;\nlet MinAttempts       = 3;\nlet MinDistinctDays   = 2;\nlet OffHoursThreshold = 180;\nStealthTalkAnomalousAuth_CL\n| where TimeGenerated >= ago(LookbackPeriod)\n| where EventType == \"OffHoursLogin\"\n| where IsWeekend == true or DeviationMinutes >= OffHoursThreshold\n| summarize\n    AttemptCount   = count(),\n    DistinctDays   = dcount(startofday(TimeGenerated)),\n    FirstSeen      = min(TimeGenerated),\n    LastSeen       = max(TimeGenerated),\n    DeviceIds      = make_set(DeviceId),\n    MaxDeviation   = max(DeviationMinutes),\n    WeekendsCount  = countif(IsWeekend == true),\n    AppVersions    = make_set(AppVersion)\n  by UserId\n| where AttemptCount >= MinAttempts and DistinctDays >= MinDistinctDays\n| extend\n    AlertName    = \"AfterHoursWork\",\n    AlertDetails = strcat(\n        \"User \", UserId,\n        \" performed \", AttemptCount, \" off-hours logins\",\n        \" across \", DistinctDays, \" distinct days.\",\n        \" Max deviation from working hours: \", MaxDeviation, \" min.\",\n        \" Weekend logins: \", WeekendsCount, \".\"\n    )\n| project\n    TimeGenerated = LastSeen,\n    UserId, AttemptCount, DistinctDays, MaxDeviation,\n    WeekendsCount, DeviceIds, AppVersions, FirstSeen, LastSeen,\n    AlertName, AlertDetails\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P2D",
        "severity": "Low",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT5H",
        "suppressionEnabled": false,
        "tactics": [
          "DefenseEvasion",
          "InitialAccess",
          "Persistence"
        ],
        "techniques": [
          "T1078"
        ],
        "templateVersion": "1.0.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}