Working with Analytics rules Part 1 – Templates

Introduction

In the previous post I showed you how to get a listing of all your Incidents (AKA cases) from Azure Sentinel.  I will come back to those in just a little bit.  But for now I want to talk about how those Incidents get generated.

As I am sure you know, Incidents are usually generated from Alerts that in turn are created based on Analytic rules.   Can you add those rules from PowerShell?  Absolutely!

Analytics Rule Types

First,  a little primer on Analytic rule types.  There are currently 4 rule types.  I have no idea if MS will adding more in the future but you never know.  Those 4 are Scheduled, Fusion, Microsoft Security (currently in preview), and ML Behavior Analytics.

The reason I bring this is up is that folks at Wortell have done the work to create a PowerShell script to create new Scheduled Analytic rule.  Go back to Introduction to Azure Sentinel REST APIs to see how to get those scripts.

Since they have already taken care of the Scheduled rules, we will focus on the other ones.  However, in order to do that, we must first talk about Alert Rule Templates.

Analytics Rule Templates

If you look at the Azure Sentinel Analytics page you will notice that Microsoft has provided a long list of prebuilt templates that are available for your use.  These cover all four of the rule types and a wide variety of topics.

To use one, select it from the list.  In the detail pane on the right side of the screen, click on the Create rule button to create the rule (looks like Microsoft just changed the functionality so that you can create the rule from template whether or not you have the proper data sources), then fill in the required fields (usually the defaults that get filled in from the template are good enough) and create it.  Instant, or almost instant, Analytic rule

How can we get this listing of templates ourselves?  We can make the REST call to get them.  I will not go through all the steps needed to make the call since that was covered in Your first Azure Sentinel REST API call so I will just show you the differences from the call that was previous covered.

REST Call

The main change, of course, is the URL to call.  In this case you will call

https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}/providers/Microsoft.SecurityInsights/alertruletemplates?api-version=2019-01-01-preview

making all the needed replacements for {subscriptionId}, {resourceGroupName}, and {workspaceName}.

You can still use the same PowerShell call as before to get the information, namely:

ConvertTo-Json(Invoke-RestMethod -Method "Get" -Uri $url2 -Headers $authHeader )

and you will get a listing of return values like this one:

{
      "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-sentinel-beta/providers/Microsoft.OperationalInsights/workspaces/la-sentinel-beta/providers/Microsoft.SecurityInsights/AlertRuleTemplates/157c0cfc-d76d-463b-8755-c781608cdc1a",
      "name": "157c0cfc-d76d-463b-8755-c781608cdc1a",
      "type": "Microsoft.SecurityInsights/AlertRuleTemplates",
      "kind": "Scheduled",
      "properties": "@{severity=Medium; query=let PrivateIPregex = @'^127\\.|^10\\.|^172\\.1[6-9]\\.|^172\\.2[0-9]\\.|^172\\.3[0-1]\\.|^192\\.168\\.';\nlet endtime = 1d;\nCommonSecurityLog\n| where TimeGenerated >= ago(endtime) \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceAction =~ \"denied\"\n| extend SourceIPType = iff(SourceIP matches regex PrivateIPregex,\"private\" ,\"public\" )\n| where SourceIPType == \"public\"\n| summarize count() by SourceIP\n| join (\n    // Successful signins from IPs blocked by the firewall solution are suspect\n    // Include fully successful sign-ins, but also ones that failed only at MFA stage\n    // as that supposes the password was sucessfully guessed.\n  SigninLogs\n  | where ResultType in (\"0\", \"50574\", \"50576\") \n) on $left.SourceIP == $right.IPAddress\n| extend timestamp = TimeGenerated, IPCustomEntity = SourceIP, AccountCustomEntity = UserPrincipalName; queryFrequency=P1D; queryPeriod=P1D; triggerOperator=GreaterThan; triggerThreshold=0; displayName=Cisco - firewall block but success logon to Azure AD; description=Correlate IPs blocked by a Cisco firewall appliance with successful Azure Active Directory signins. \nBecause the IP was blocked by the firewall, that same IP logging on successfully to AAD is potentially suspect\nand could indicate credential compromise for the user account.; tactics=System.Object[]; createdDateUTC=07/08/2019 00:00:00; status=Available; requiredDataConnectors=System.Object[]; alertRulesCreatedByTemplateCount=0}"
    }

But you may notice that the properties field has a lot of information that is hard to get to. In order to see it easier, change your call to:

ConvertTo-Json(Invoke-RestMethod -Method "Get" -Uri $url2 -Headers $authHeader ) -Depth 5

The Depth parameter tells the ConvertTo-Json command to expand further down the JSON chain that the default. In this case you will get a listing of return values as before, but the properties field has been expanded to look like what is shown below, making it much easier to read:

"properties": {
        "severity": "Medium",
        "query": "let PrivateIPregex = @'^127\\.|^10\\.|^172\\.1[6-9]\\.|^172\\.2[0-9]\\.|^172\\.3[0-1]\\.|^192\\.168\\.';\nlet endtime = 1d;\nCommonSecurityLog\n| where TimeGenerated >= ago(endtime) \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceAction =~ \"denied\"\n| extend SourceIPType = iff(SourceIP matches regex PrivateIPregex,\"private\" ,\"public\" )\n| where SourceIPType == \"public\"\n| summarize count() by SourceIP\n| join (\n    // Successful signins from IPs blocked by the firewall solution are suspect\n    // Include fully successful sign-ins, but also ones that failed only at MFA stage\n    // as that supposes the password was sucessfully guessed.\n  SigninLogs\n  | where ResultType in (\"0\", \"50574\", \"50576\") \n) on $left.SourceIP == $right.IPAddress\n| extend timestamp = TimeGenerated, IPCustomEntity = SourceIP, AccountCustomEntity = UserPrincipalName",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0,
        "displayName": "Cisco - firewall block but success logon to Azure AD",
        "description": "Correlate IPs blocked by a Cisco firewall appliance with successful Azure Active Directory signins. \nBecause the IP was blocked by the firewall, that same IP logging on successfully to AAD is potentially suspect\nand could indicate credential compromise for the user account.",
        "tactics": [
          "InitialAccess"
        ],
        "createdDateUTC": "2019-07-08T00:00:00Z",
        "status": "Available",
        "requiredDataConnectors": [
          {
            "connectorId": "CiscoASA",
            "dataTypes": "@{CommonSecurityLog=Exist}"
          },
          {
            "connectorId": "AzureActiveDirectory",
            "dataTypes": "@{SigninLogs=Exist}"
          }
        ],
        "alertRulesCreatedByTemplateCount": 0
      }

Conclusion

In this posting,  we discussed how to get the listing of all the Azure Sentinel Analytic Rule Templates.  In the next post, I’ll show you how to use this information.

2 thoughts on “Working with Analytics rules Part 1 – Templates

Leave a Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.