- "query": "let dt_lookBack = 1h; // Look back 1 hour for AppServiceHTTPLogs\nlet ioc_lookBack = 14d; // Look back 14 days for threat intelligence indicators\n// Fetch threat intelligence indicators related to IP addresses\nlet IP_Indicators = ThreatIntelIndicators\n //extract key part of kv pair\n | extend IndicatorType = replace(@\"\\[|\\]|\\\"\"\", \"\", tostring(split(ObservableKey, \":\", 0)))\n | where IndicatorType in (\"ipv4-addr\", \"ipv6-addr\", \"network-traffic\")\n | extend NetworkSourceIP = ObservableValue\n | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)\n // Filter out indicators without relevant IP address fields\n | where TimeGenerated >= ago(ioc_lookBack)\n | where TimeGenerated >= ago(ioc_lookBack)\n // Filtering out rows where the Confidence Score is less than 50 as they would not have an Alert Priority label. \n | where Confidence > 50\n // Select the IP entity based on availability of different IP fields\n | extend TI_ipEntity = iff(isnotempty(NetworkSourceIP), NetworkSourceIP, NetworkSourceIP)\n | extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)\n | extend Url = iff(ObservableKey == \"url:value\", ObservableValue, \"\")\n // Determine Severity based on ConfidenceScore\n | extend Severity = case(Confidence > 82, \"High\",\n Confidence > 74, \"Medium\",\n \"Low\")\n // Exclude local addresses using the ipv4_is_private operator and filtering out specific address prefixes\n | where ipv4_is_private(TI_ipEntity) == false and TI_ipEntity !startswith \"fe80\" and TI_ipEntity !startswith \"::\" and TI_ipEntity !startswith \"127.\"\n | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue\n | where IsActive and (ValidUntil > now() or isempty(ValidUntil));\n // Perform a join between IP indicators and AppServiceHTTPLogs to identify potential malicious activity\nIP_Indicators\n| project-reorder *, IsActive, Tags, TrafficLightProtocolLevel, NetworkSourceIP, Type, TI_ipEntity, Severity\n // Use innerunique to keep performance fast and result set low, as we only need one match to indicate potential malicious activity that needs investigation\n | join kind=innerunique (\n AppServiceHTTPLogs | where TimeGenerated >= ago(dt_lookBack)\n | where isnotempty(CIp)\n | extend WebApp = split(_ResourceId, '/')[8]\n | extend AppService_TimeGenerated = TimeGenerated // Rename time column for clarity\n )\n on $left.TI_ipEntity == $right.CIp\n // Filter out logs that occurred after the expiration of the corresponding indicator\n | where AppService_TimeGenerated < ValidUntil\n // Group the results by IndicatorId and CIp, and keep the log entry with the latest timestamp\n | summarize AppService_TimeGenerated = arg_max(AppService_TimeGenerated, *) by Id, CIp\n // Select the desired output fields\n | extend Description = tostring(parse_json(Data).description)\n | extend ActivityGroupNames = extract(@\"ActivityGroup:(\\S+)\", 1, tostring(parse_json(Data).labels))\n | project AppService_TimeGenerated, Description, ActivityGroupNames, Id, ValidUntil, Confidence, TI_ipEntity, CsUsername, WebApp = split(_ResourceId, '/')[8], CIp, CsHost, NetworkSourceIP, _ResourceId, Type, Url\n // Extract hostname and DNS domain from the CsHost field\n | extend HostName = tostring(split(CsHost, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(CsHost, '.'), 1, -1), '.'))\n // Rename the timestamp field\n | extend timestamp = AppService_TimeGenerated\n",
0 commit comments