{
  "version": "Notebook/1.0",
  "items": [
    {
      "type": 9,
      "content": {
        "version": "KqlParameterItem/1.0",
        "parameters": [
          {
            "id": "d7ccc5ca-c8ec-458f-ab0d-564a7ef1d217",
            "version": "KqlParameterItem/1.0",
            "name": "Help",
            "label": "Show Guide",
            "type": 10,
            "isRequired": true,
            "jsonData": "[\n    {\"value\": \"Yes\", \"label\": \"Yes\", \"selected\":true},\n    {\"value\": \"No\", \"label\": \"No\"}\n]",
            "timeContext": {
              "durationMs": 86400000
            },
            "value": "No"
          }
        ],
        "style": "pills",
        "queryType": 0,
        "resourceType": "microsoft.operationalinsights/workspaces"
      },
      "name": "parameters - 7"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "### Guide: Domain Correlation \n\nRecorded Future’s Domain Correlation Workbook helps you detect malicious domains within your environment by correlating your logs with Recorded Future Domain Risk Lists.\n\n### How to Correlate Domains\n\nTo correlate domains, follow the steps below:\n\n1. In the **Domain Logs Table** dropdown, select a log table that contains domain logs.\n\t* If a particular log table is not listed in the dropdown, ensure it is enabled in your environment.\n2. In the **Log field with domains** dropdown, select the log field that holds the domains to be correlated.\n\t* The workbook can correlate domains in the format: `domainName.net`.\n3. Select a Recorded Future Domain Risk List for correlation.\n4. If necessary, adjust the values in the **Logs from** and **Data from** dropdowns to match your requirements.\n5. Done\n\n---\n\n#### Log table with examples of correlatable log fields\n\n| Table      \t | Field |\n| ----------- \t | ----------- |\n| DNSEvents      | Name        |\n| _Im_Dns   \t | DnsQuery    |",
              "style": "info"
            },
            "name": "text - 0"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "Help",
        "comparison": "isEqualTo",
        "value": "Yes"
      },
      "name": "group - 15"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "### Domains (from logs)"
            },
            "customWidth": "50",
            "name": "text - 2"
          },
          {
            "type": 1,
            "content": {
              "json": "### Recorded Future Risk List"
            },
            "customWidth": "50",
            "name": "text - 3"
          },
          {
            "type": 9,
            "content": {
              "version": "KqlParameterItem/1.0",
              "parameters": [
                {
                  "id": "b91b8b5b-10cf-4106-99e2-793eb0d72dce",
                  "version": "KqlParameterItem/1.0",
                  "name": "Domain_Logs_Time_Range",
                  "label": "Logs from",
                  "type": 4,
                  "isRequired": true,
                  "typeSettings": {
                    "selectableValues": [
                      {
                        "durationMs": 300000
                      },
                      {
                        "durationMs": 900000
                      },
                      {
                        "durationMs": 1800000
                      },
                      {
                        "durationMs": 3600000
                      },
                      {
                        "durationMs": 14400000
                      },
                      {
                        "durationMs": 43200000
                      },
                      {
                        "durationMs": 86400000
                      },
                      {
                        "durationMs": 172800000
                      },
                      {
                        "durationMs": 259200000
                      },
                      {
                        "durationMs": 604800000
                      },
                      {
                        "durationMs": 1209600000
                      },
                      {
                        "durationMs": 2419200000
                      },
                      {
                        "durationMs": 2592000000
                      },
                      {
                        "durationMs": 5184000000
                      },
                      {
                        "durationMs": 7776000000
                      }
                    ]
                  },
                  "timeContext": {
                    "durationMs": 86400000
                  },
                  "value": {
                    "durationMs": 604800000
                  }
                },
                {
                  "id": "3300ad41-acbc-4ebd-900a-c6ab250b7c73",
                  "version": "KqlParameterItem/1.0",
                  "name": "Domain_Logs_Table",
                  "label": "Domain Logs Table",
                  "type": 2,
                  "description": "Log Table to correlate Domains Against",
                  "isRequired": true,
                  "query": "search \"*\" \n| where TimeGenerated {Domain_Logs_Time_Range:query}\n| summarize count() by $table \n| sort by count_ desc \n| where $table != \"ThreatIntelIndicators\" \n| project $table\n",
                  "queryType": 0,
                  "resourceType": "microsoft.operationalinsights/workspaces",
                  "value": "Squid_Proxy_Domain_CL"
                },
                {
                  "id": "f4f77ada-b97c-4a82-9421-20a58fb7ce26",
                  "version": "KqlParameterItem/1.0",
                  "name": "Domain_Logs_Field",
                  "label": "Log Field with Domains",
                  "type": 2,
                  "description": "Select the field containing the Domain Name that you want to correlate against",
                  "isRequired": true,
                  "query": "{Domain_Logs_Table:value}\n| getschema\n| where DataType == \"System.String\"\n| project ColumnName",
                  "queryType": 0,
                  "resourceType": "microsoft.operationalinsights/workspaces",
                  "value": "Domain_s"
                }
              ],
              "style": "pills",
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces"
            },
            "customWidth": "50",
            "name": "parameters - 0"
          },
          {
            "type": 9,
            "content": {
              "version": "KqlParameterItem/1.0",
              "parameters": [
                {
                  "id": "95e78560-1e69-437c-8226-7b0f8c4dc199",
                  "version": "KqlParameterItem/1.0",
                  "name": "Threat_Intelligence_Time_Range",
                  "label": "Data from",
                  "type": 4,
                  "isRequired": true,
                  "typeSettings": {
                    "selectableValues": [
                      {
                        "durationMs": 300000
                      },
                      {
                        "durationMs": 900000
                      },
                      {
                        "durationMs": 1800000
                      },
                      {
                        "durationMs": 3600000
                      },
                      {
                        "durationMs": 14400000
                      },
                      {
                        "durationMs": 43200000
                      },
                      {
                        "durationMs": 86400000
                      },
                      {
                        "durationMs": 172800000
                      },
                      {
                        "durationMs": 259200000
                      },
                      {
                        "durationMs": 604800000
                      },
                      {
                        "durationMs": 1209600000
                      },
                      {
                        "durationMs": 2419200000
                      },
                      {
                        "durationMs": 2592000000
                      },
                      {
                        "durationMs": 5184000000
                      },
                      {
                        "durationMs": 7776000000
                      }
                    ]
                  },
                  "value": {
                    "durationMs": 604800000
                  }
                },
                {
                  "id": "e7c7e2ea-f5b3-4505-b64c-b18ca8561168",
                  "version": "KqlParameterItem/1.0",
                  "name": "RF_Risk_list",
                  "label": "Risk List",
                  "type": 2,
                  "description": "Which Domain Risk List do you want to correlate against",
                  "isRequired": true,
                  "query": "ThreatIntelIndicators\n| where ObservableKey == 'domain-name:value'\n | where isnotempty(ObservableValue)\n| where Data.description contains \"Recorded Future\"\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\n| summarize count() by tostring(Data.description)\n| project output = strcat('\"', Data_description, '\"')\n",
                  "queryType": 0,
                  "resourceType": "microsoft.operationalinsights/workspaces",
                  "value": "\"Recorded Future - DOMAIN - Default RiskList\""
                }
              ],
              "style": "pills",
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces"
            },
            "customWidth": "50",
            "name": "parameters - 1"
          }
        ],
        "exportParameters": true
      },
      "name": "group - 10"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "\n### Guide: Detected Domains Per Day\n\nThe chart displays the number of correlation detections per day between domain logs and Recorded Future's domain Risk lists.",
              "style": "info"
            },
            "customWidth": "100",
            "conditionalVisibility": {
              "parameterName": "Help",
              "comparison": "isEqualTo",
              "value": "Yes"
            },
            "name": "text - 0"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let list_tlds = ThreatIntelIndicators\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\n// Picking up only Recorded Future IOC's that are pertinent to the use case (Malware C2 Detection)\n| where Data.description == {RF_Risk_list:value}\n| where ObservableKey == 'domain-name:value'\n | where isnotempty(ObservableValue)\n| where isnotempty(Tags)\n| extend parts = split(ObservableValue, '.')\n| extend tld = parts[(array_length(parts)-1)]\n| summarize count() by tostring(tld)\n| summarize make_list(tld);\nThreatIntelIndicators\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\n| where IsActive == true\n// Picking up only Recorded Future IOC's that are pertinent to the use case (Malware C2 Detection)\n| where Data.description == {RF_Risk_list:value}\n// Picking up only IOC's that contain the entities we want\n| where ObservableKey == 'domain-name:value'\n | where isnotempty(ObservableValue)\n| where isnotempty(Tags)\n| join (\n    {Domain_Logs_Table:value}\n    | where TimeGenerated  {Domain_Logs_Time_Range:query}\n    //Extract Domain patterns from syslog message\n    | where isnotempty({Domain_Logs_Field:value})\n    | extend parts = split({Domain_Logs_Field:value}, '.')\n    //Split out the TLD\n    | extend tld = parts[(array_length(parts)-1)]\n    //Validate parsed Domain by checking if the TLD is in the list of TLDs in our threat feed\n    | where tld in~ (list_tlds)\n    | extend DNS_TimeGenerated = TimeGenerated\n) on $left.ObservableValue==$right.{Domain_Logs_Field:value}\n| summarize Correlation_Matches=count() by bin(DNS_TimeGenerated, 1d)\n| render barchart",
              "size": 0,
              "title": "Detected Domains Per Day",
              "noDataMessage": "No detected domains",
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces"
            },
            "customWidth": "100",
            "name": "query - 1"
          }
        ]
      },
      "customWidth": "100",
      "name": "group - 14"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "\n### Guide: Detected Domains\n\nThe Detected Domains table lists domains from the correlated logs that have been matched with Recorded Future Domain Risk Lists.\n\n**Table Columns**\n\n* **Risk Score:** The Recorded Future Risk Score for the domain (IOC), ranging from 1 to 99, with 99 being the highest level of severity.\n* **Domain:** The detected domain.\n* **Detected:** The time when the log was correlated with a Risk List.\n* **Log Created:** The time when the log event itself was created.\n* **Threat Classification:** The type of threat associated with the domain (IOC).",
              "style": "info"
            },
            "conditionalVisibility": {
              "parameterName": "Help",
              "comparison": "isEqualTo",
              "value": "Yes"
            },
            "name": "text - 1"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let list_tlds = ThreatIntelIndicators\r\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\r\n// Picking up only Recorded Future IOC's that are pertinent to the use case (Malware C2 Detection)\r\n| where Data.description == {RF_Risk_list:value}\r\n| where ObservableKey == 'domain-name:value'\n | where isnotempty(ObservableValue)\n| where isnotempty(Tags)\r\n| extend parts = split(ObservableValue, '.')\r\n| extend tld = parts[(array_length(parts)-1)]\r\n| summarize count() by tostring(tld)\r\n| summarize make_list(tld);\r\nThreatIntelIndicators\r\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\r\n| where IsActive == true\r\n// Picking up only Recorded Future IOC's that are pertinent to the use case (Malware C2 Detection)\r\n| where Data.description == {RF_Risk_list:value}\r\n// Picking up only IOC's that contain the entities we want\r\n| where ObservableKey == 'domain-name:value'\n | where isnotempty(ObservableValue)\r\n| join (\r\n    {Domain_Logs_Table:value}\r\n    | where TimeGenerated  {Domain_Logs_Time_Range:query}\r\n    //Extract Domain patterns from syslog message\r\n    | where isnotempty({Domain_Logs_Field:value})\r\n    | extend parts = split({Domain_Logs_Field:value}, '.')\r\n    //Split out the TLD\r\n    | extend tld = parts[(array_length(parts)-1)]\r\n    //Validate parsed Domain by checking if the TLD is in the list of TLDs in our threat feed\r\n    | where tld in~ (list_tlds)\r\n    | extend DNS_TimeGenerated = TimeGenerated\r\n) on $left.ObservableValue==$right.{Domain_Logs_Field:value}\r\n| project [\"Risk Score\"]=Confidence, Domain=ObservableValue, Detected=format_datetime(TimeGenerated, 'yyyy-MM-dd HH:mm:ss'), [\"Log Created\"]=format_datetime(DNS_TimeGenerated, 'yyyy-MM-dd HH:mm:ss'), [\"Threat Classification\"]=tostring(Data.indicator_types)\r\n| summarize [\"Log Created\"]=max([\"Log Created\"]) by Domain, [\"Risk Score\"], Detected, [\"Threat Classification\"]\r\n| project [\"Risk Score\"], Domain, Detected, [\"Log Created\"], [\"Threat Classification\"]\r\n| sort by [\"Risk Score\"] desc",
              "size": 0,
              "title": "Detected Domains",
              "noDataMessage": "No detected domains",
              "exportFieldName": "Domain",
              "exportParameterName": "MaliciousDomainMatch",
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Risk",
                    "formatter": 18,
                    "formatOptions": {
                      "thresholdsOptions": "colors",
                      "thresholdsGrid": [
                        {
                          "operator": ">=",
                          "thresholdValue": "90",
                          "representation": "redBright",
                          "text": "{0}{1}"
                        },
                        {
                          "operator": ">=",
                          "thresholdValue": "65",
                          "representation": "orange",
                          "text": "{0}{1}"
                        },
                        {
                          "operator": ">=",
                          "thresholdValue": "25",
                          "representation": "yellow",
                          "text": "{0}{1}"
                        },
                        {
                          "operator": "Default",
                          "representation": "blue",
                          "text": "{0}{1}"
                        }
                      ]
                    }
                  }
                ]
              }            },
            "customWidth": "70",
            "name": "query - 3"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let list_tlds = ThreatIntelIndicators\r\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\r\n// Picking up only Recorded Future IOC's that are pertinent to the use case (Malware C2 Detection)\r\n| where Data.description == {RF_Risk_list:value}\r\n| where ObservableKey == 'domain-name:value'\n | where isnotempty(ObservableValue)\r\n| where isnotempty(Tags)\r\n| extend parts = split(ObservableValue, '.')\r\n| extend tld = parts[(array_length(parts)-1)]\r\n| summarize count() by tostring(tld)\r\n| summarize make_list(tld);\r\nThreatIntelIndicators\r\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\r\n| where IsActive == true\r\n// Picking up only Recorded Future IOC's that are pertinent to the use case (Malware C2 Detection)\r\n| where Data.description == {RF_Risk_list:value}\r\n// Picking up only IOC's that contain the entities we want\r\n| where ObservableKey == 'domain-name:value'\n | where isnotempty(ObservableValue)\r\n| where isnotempty(Tags)\r\n| join (\r\n    {Domain_Logs_Table:value}\r\n    | where TimeGenerated  {Domain_Logs_Time_Range:query}\r\n    //Extract Domain patterns from syslog message\r\n    | where isnotempty({Domain_Logs_Field:value})\r\n    | extend parts = split({Domain_Logs_Field:value}, '.')\r\n    //Split out the TLD\r\n    | extend tld = parts[(array_length(parts)-1)]\r\n    //Validate parsed Domain by checking if the TLD is in the list of TLDs in our threat feed\r\n    | where tld in~ (list_tlds)\r\n    | extend DNS_TimeGenerated = TimeGenerated\r\n) on $left.ObservableValue==$right.{Domain_Logs_Field:value}\r\n| project Risk=Confidence, ObservableValue, Data.indicator_types, Tags\r\n| extend Evidence=parse_json(Tags)\r\n| mv-expand Evidence = parse_json(tostring(Evidence))\r\n// Capitalize the first letter in each rule, the we get the rule from 'Evidence['rule']'\r\n| extend Rule=strcat(toupper(substring(Evidence['rule'], 0, 1)), substring(Evidence['rule'], 1))\r\n| summarize count() by tostring(Rule)\r\n| sort by count_ desc\r\n\r\n",
              "size": 0,
              "title": "Top Triggered Risk Rules",
              "noDataMessage": "No triggered Risk Rules",
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "count_",
                    "formatter": 8,
                    "formatOptions": {
                      "palette": "orange"
                    }
                  }
                ],
                "labelSettings": [
                  {
                    "columnId": "count_",
                    "label": "Count"
                  }
                ]
              }
            },
            "customWidth": "30",
            "name": "query - 2"
          },
          {
            "type": 1,
            "content": {
              "json": "### Detected Domains: Evidence Details\n\nTo view evidence details, click a row (domain) in the Detected Domains table."
            },
            "name": "text - 3"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "ThreatIntelIndicators\n| where TimeGenerated {Threat_Intelligence_Time_Range:query}\n| where Data.description contains {RF_Risk_list:value}\n| where ObservableValue == \"{MaliciousDomainMatch}\"\n| where isnotempty(Tags)\n//| where ExpirationDateTime > now()\n| extend Evidence=parse_json(Tags)[0]\n| take 1\n| mv-expand Evidence = parse_json(tostring(Evidence))\n// Capitalize the first letter in each rule, the we get the rule from 'Evidence['rule']'\r\n | project Rule=strcat(toupper(substring(Evidence['rule'], 0, 1)), substring(Evidence['rule'], 1)), Criticality = Evidence['Criticality'], Evidence_String = Evidence['EvidenceString'] \n| sort by toint(Criticality) desc",
              "size": 1,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Evidence_String",
                    "formatter": 0,
                    "formatOptions": {
                      "customColumnWidthSetting": "70%"
                    }
                  }
                ]
              }
            },
            "conditionalVisibility": {
              "parameterName": "MaliciousDomainMatch",
              "comparison": "isNotEqualTo"
            },
            "name": "query - 3"
          },
          {
            "type": 1,
            "content": {
              "json": "\n### Source data from {Domain_Logs_Table:value}\nTo view source data of correlated domain, click a row (domain) in the Detected Domains table."
            },
            "name": "text - 5"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "{Domain_Logs_Table:value}\n| where TimeGenerated {Domain_Logs_Time_Range:query}\n| where {Domain_Logs_Field:value} == \"{MaliciousDomainMatch}\"\n",
              "size": 1,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces"
            },
            "conditionalVisibility": {
              "parameterName": "MaliciousDomainMatch",
              "comparison": "isNotEqualTo",
              "value": ""
            },
            "name": "query - 1"
          }
        ]
      },
      "name": "group - 8"
    }
  ],
  "styleSettings": {
    "paddingStyle": "wide"
  },
  "fromTemplateId": "sentinel-RecordedFutureDomainCorrelationWorkbook",
  "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json"
}