Panther informational experimental python
Azure Serverless Script Execution
Detects when serverless resources execute PowerShell or Python scripts through Azure Automation runbook jobs or Azure Function Apps. Adversaries may abuse access to serverless resources to execute commands with inherited permissions from managed identities, RunAs accounts, or hybrid worker groups.
Detection Logic
from panther_azureactivity_helpers import (
azure_activity_alert_context,
azure_activity_success,
extract_resource_name_from_id,
)
# AZT302.1/2/3 - Automation Account Runbook Job Execution
RUNBOOK_JOB_WRITE = "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/JOBS/WRITE"
# AZT302.4 - Function Application Execution
FUNCTION_APP_ACTION = "MICROSOFT.WEB/SITES/HOSTRUNTIME/HOST/ACTION"
AZT302_OPERATIONS = [
RUNBOOK_JOB_WRITE,
FUNCTION_APP_ACTION,
]
def rule(event):
operation = event.get("operationName", "").upper()
return all([operation in AZT302_OPERATIONS, azure_activity_success(event)])
def title(event):
resource_id = event.get("resourceId", "<UNKNOWN_RESOURCE>")
operation = event.get("operationName", "").upper()
if operation == RUNBOOK_JOB_WRITE:
technique = "Automation Runbook Job"
resource_name = extract_resource_name_from_id(
resource_id, "automationAccounts", default="<UNKNOWN_ACCOUNT>"
)
elif operation == FUNCTION_APP_ACTION:
technique = "Function App"
resource_name = extract_resource_name_from_id(resource_id, "sites", default="<UNKNOWN_APP>")
else:
technique = "Serverless"
resource_name = "<UNKNOWN_RESOURCE>"
return f"Azure {technique} Execution detected on [{resource_name}]"
def alert_context(event):
context = azure_activity_alert_context(event)
operation = event.get("operationName", "").upper()
resource_id = event.get("resourceId", "")
if operation == RUNBOOK_JOB_WRITE:
context["resource_type"] = "Automation Runbook Job"
automation_account = extract_resource_name_from_id(
resource_id, "automationAccounts", default=""
)
if automation_account:
context["automation_account"] = automation_account
runbook_name = extract_resource_name_from_id(resource_id, "runbooks", default="")
if runbook_name:
context["runbook_name"] = runbook_name
job_id = extract_resource_name_from_id(resource_id, "jobs", default="")
if job_id:
context["job_id"] = job_id
elif operation == FUNCTION_APP_ACTION:
context["resource_type"] = "Function App"
function_app_name = extract_resource_name_from_id(resource_id, "sites", default="")
if function_app_name:
context["function_app_name"] = function_app_name
return context Field Validations
Loading…
Comments (0)
Loading comments...