LoFP LoFP / infrastructure-as-code, configuration management, and patching automation routinely create, update, and delete vm extensions. the first time a given extension resource name is operated on from a new source as number will alert. baseline expected management networks (corporate egress, ci/cd runners, third-party automation saas) and exclude their as numbers if the activity is verified as authorized. read operations are typically not emitted to the azure activity log; the rule predominantly fires on write and delete.

Techniques

Sample rules

Azure VM Extension CRUD Operation with Unusual Source ASN

Description

Identifies create, read, update, or delete (CRUD) operations against Azure VM or VM scale set extensions (“MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/*” or the scale set equivalent) where the combination of the targeted extension resource name and the source autonomous system (AS) number has not been observed recently. VM extensions such as CustomScript and DSC run with high privilege on the guest (SYSTEM on Windows, root on Linux), so writing, modifying, or removing them is a common code-execution and persistence primitive. By keying a new terms approach on the extension resource name and the source AS number, this rule surfaces extension operations originating from networks that have not historically managed that extension, while routine first-party Microsoft automation (which originates from well-known Microsoft AS numbers) is excluded.

Detection logic

data_stream.dataset:azure.activitylogs and
    event.action:(
        "MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/DELETE" or
        "MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/READ" or
        "MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/WRITE" or
        "MICROSOFT.COMPUTE/VIRTUALMACHINESCALESETS/EXTENSIONS/DELETE" or
        "MICROSOFT.COMPUTE/VIRTUALMACHINESCALESETS/EXTENSIONS/READ" or
        "MICROSOFT.COMPUTE/VIRTUALMACHINESCALESETS/EXTENSIONS/WRITE"
    ) and event.outcome:(Success or success) and
    azure.resource.name:* and
    source.as.number:(* and not (3598 or 8068 or 8069 or 8070 or 8071 or 8072 or 8073 or 8074 or 8075 or 12076))