Query Details

RULE 05 Automation Runbook New Caller

Query

// Rule    : Azure - Automation Runbook Created or Published by First-Time Caller
// Severity: High
// Tactics : Execution, Persistence
// MITRE   : T1059
// Freq    : PT6H   Period: P14D
//==========================================================================================

let KnownRunbookCallers = AzureActivity
    | where TimeGenerated between (ago(14d) .. ago(6h))
    | where OperationNameValue has_any ("AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/WRITE", "AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/PUBLISH/ACTION", "AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DRAFT/WRITE")
    | where ActivityStatusValue =~ "Success"
    | distinct Caller;
let ExcludedPatterns = dynamic(["automation-account", "devops", "pipeline", "github", "bicep", "terraform"]);
AzureActivity
| where TimeGenerated > ago(6h)
| where OperationNameValue has_any ("AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/WRITE", "AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/PUBLISH/ACTION")
| where ActivityStatusValue =~ "Success"
| where not(tolower(Caller) has_any (ExcludedPatterns))
| where isnotempty(CallerIpAddress)
| where CallerIpAddress !startswith "168.63." and CallerIpAddress !startswith "169.254."
| where Caller !in (KnownRunbookCallers)
| summarize
    RunbookOpCount = count(),
    RunbookNames = make_set(tostring(split(ResourceId, "/")[-1]), 10),
    Operations = make_set(OperationNameValue, 5),
    SourceIPs = make_set(CallerIpAddress, 5),
    CallerIP = any(CallerIpAddress),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by Caller, ResourceGroup, SubscriptionId
| extend
    AccountName = tostring(split(Caller, "@")[0]),
    AccountUPNSuffix = tostring(split(Caller, "@")[1])

Explanation

This query is designed to detect potentially suspicious activities related to the creation or publication of Azure Automation Runbooks by users who have not previously performed such actions within a specified timeframe. Here's a simplified breakdown:

  1. Purpose: The query identifies instances where a runbook is created or published by a user for the first time, which could indicate unauthorized or unusual activity.

  2. Timeframe: It looks at activities over the past 14 days but focuses on the last 6 hours for new activities.

  3. Known Callers: It first compiles a list of users who have successfully created or published runbooks in the past 14 days (excluding the last 6 hours).

  4. Exclusions: It excludes certain patterns in usernames that are likely to be automated or expected (e.g., "automation-account", "devops").

  5. Current Activity: It then checks for successful runbook creation or publication activities in the last 6 hours by users not in the known list.

  6. IP Filtering: It filters out internal Azure IP addresses (those starting with "168.63." or "169.254.").

  7. Summary: For each new caller, it summarizes:

    • The number of operations performed.
    • The names of the runbooks involved.
    • The types of operations performed.
    • The source IP addresses used.
    • The first and last time the activity was seen.
  8. Output: It provides additional details like the account name and domain part of the user's email.

This query helps in identifying potentially unauthorized or unusual runbook activities, which could be indicative of a security threat.

Details

David Alonso profile picture

David Alonso

Released: March 12, 2026

Tables

AzureActivity

Keywords

AzureActivityAutomationRunbooksCallerResourceGroupSubscriptionIdAccountNameUPNSuffixIpAddressOperationValueStatusTimeGenerated

Operators

letbetweenagohas_any=~distinctdynamic>nottolowerisnotempty!startswith!insummarizecountmake_settostringsplitanyminmaxbyextend

MITRE Techniques

Actions

GitHub