Query Details

HUNT 12 NSG Firewall Change History

Query

// Hunt     : Hunt - NSG Deletion and Firewall Rule Modification History (30 Days)
// Tactics  : DefenseEvasion
// MITRE    : T1562.007
// Purpose  : Show the complete history of NSG deletions AND individual security rule modifications (inbound/outbound allow-all rules added) over 30 days. Helps determine whether Rule-14 alerts are isolated events or part of a broader network exposure campaign.
//==========================================================================================

let NSGOps = dynamic([
    "MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/DELETE",
    "MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/WRITE",
    "MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/SECURITYRULES/WRITE",
    "MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/SECURITYRULES/DELETE"
]);
AzureActivity
| where TimeGenerated > ago(30d)
| where OperationNameValue has_any (NSGOps)
| where ActivityStatusValue =~ "Success"
| extend ChangeType = case(
    OperationNameValue has "DELETE" and OperationNameValue has "NETWORKSECURITYGROUPS/DELETE", "NSG Deleted",
    OperationNameValue has "SECURITYRULES/DELETE", "Security Rule Deleted",
    OperationNameValue has "SECURITYRULES/WRITE",  "Security Rule Modified/Added",
    OperationNameValue has "NETWORKSECURITYGROUPS/WRITE", "NSG Created/Modified",
    "Other")
// Parse the security-rule body to surface DANGEROUS any-any allow-from-Internet rules,
// which are the actual attacker objective (exposing RDP/SSH/management ports).
| extend Props        = parse_json(Properties)
| extend RuleAccess   = tostring(Props.requestbody.properties.access)
| extend RuleDirection = tostring(Props.requestbody.properties.direction)
| extend SourcePrefix = tostring(Props.requestbody.properties.sourceAddressPrefix)
| extend DestPortRange = tostring(Props.requestbody.properties.destinationPortRange)
| extend IsDangerousAllowAny = ChangeType == "Security Rule Modified/Added"
    and RuleAccess =~ "Allow"
    and RuleDirection =~ "Inbound"
    and SourcePrefix in ("*", "0.0.0.0/0", "Internet", "any")
    and DestPortRange in ("*", "0-65535")
| project
    TimeGenerated,
    Caller,
    CallerIpAddress,
    ChangeType,
    IsDangerousAllowAny,
    RuleAccess,
    RuleDirection,
    SourcePrefix,
    DestPortRange,
    ResourceId,
    ResourceGroup,
    SubscriptionId
| order by IsDangerousAllowAny desc, TimeGenerated desc

Explanation

This query is designed to track and analyze changes to Network Security Groups (NSGs) and their security rules over the past 30 days. It focuses on identifying potentially risky modifications that could expose a network to threats. Here's a simplified breakdown:

  1. Purpose: The query aims to provide a historical view of NSG deletions and modifications to security rules, specifically looking for any "allow-all" inbound rules that could indicate a security risk.

  2. Data Source: It uses data from AzureActivity, which logs activities related to Azure resources.

  3. Time Frame: It examines activities from the last 30 days.

  4. Operations Tracked: The query looks for specific operations related to NSGs:

    • Deleting an NSG
    • Creating or modifying an NSG
    • Adding or modifying security rules
    • Deleting security rules
  5. Filtering: It only considers successful operations.

  6. Change Type Identification: It categorizes each operation into:

    • NSG Deleted
    • Security Rule Deleted
    • Security Rule Modified/Added
    • NSG Created/Modified
  7. Risk Identification: The query checks if any modified or added security rules are potentially dangerous. It flags rules that:

    • Allow inbound traffic
    • Have a source address of "any" (e.g., from the entire internet)
    • Allow traffic on any port
  8. Output: The results include details such as the time of the change, who made it, their IP address, the type of change, and whether it was a potentially dangerous rule change.

  9. Sorting: The results are sorted to show potentially dangerous changes first, followed by the most recent changes.

This query helps security teams determine if specific alerts are isolated incidents or part of a larger pattern of risky network exposure.

Details

David Alonso profile picture

David Alonso

Released: July 27, 2026

Tables

AzureActivity

Keywords

AzureActivityNetworkSecurityGroupsRulesProperties

Operators

letdynamicagohas_any=~casehasparse_jsontostringinprojectorder bydesc

MITRE Techniques

Actions

GitHub