Query Details

TI Map Query Generator

Query

// Active threat indicators in Sentinel are renovated as ThreatIntelligenceIndicator events every ~12 days.
            let query_frequency = 1h;
            let query_period = 14d;
            let query_wait = <<<TableQueryWait>>>;
            let table_query_lookback = <<<TITableLookback>>>;
            let _TIBenignProperty =
                _GetWatchlist('ID-TIBenignProperty')
                | where Notes has_any (<<<TIWatchlistNoteType>>>)
                | project IndicatorId, BenignProperty
            ;
            let _TIExcludedSources = toscalar(
                _GetWatchlist('Activity-ExpectedSignificantActivity')
                | where Activity == "ThreatIndicatorSource"
                | summarize make_list(Auxiliar)
            );<<<TIAdditionalLets>>><<<TableAdditionalLets>>><<<TITableAdditionalLets>>>
            let _TITableMatch = (table_start:datetime, table_end:datetime, only_new_ti:boolean, ti_start:datetime = datetime(null)) {
                // Scheduled Analytics rules have a query period limit of 14d
                let _Indicators =// materialize(
                    ThreatIntelligenceIndicator
                    | where TimeGenerated > ago(query_period)
                    // Take the earliest TimeGenerated and the latest column info
                    | summarize hint.strategy=shuffle
                        minTimeGenerated = min(TimeGenerated),
                        arg_max(TimeGenerated, Active, Description, ActivityGroupNames, IndicatorId, ThreatType, DomainName, Url, ExpirationDateTime, ConfidenceScore, SourceSystem, Tags, AdditionalInformation, ExternalIndicatorId<<<TIProjectColumns>>>)
                        by IndicatorId
                    // Remove inactive or expired indicators
                    | where not(not(Active) or ExpirationDateTime < now())
                    // Pick indicators that contain the desired entity type<<<TIOperators>>>
                    // Remove indicators from specific sources
                    | where not(AdditionalInformation has_any (_TIExcludedSources) or Description has_any (_TIExcludedSources))
                    // Remove excluded indicators with benign properties
                    | join kind=leftanti _TIBenignProperty on IndicatorId, $left.<<<TIGroupByColumn>>> == $right.BenignProperty
                    // Deduplicate indicators by <<<TIGroupByColumn>>> column, equivalent to using join kind=innerunique afterwards
                    | summarize hint.strategy=shuffle
                        minTimeGenerated = min(minTimeGenerated),
                        take_any(*)
                        by <<<TIGroupByColumn>>>
                    // If we want only new indicators, remove indicators received previously
                    | where not(only_new_ti and minTimeGenerated < ti_start)
                //)
                ;<<<TIPrefilter>>>
                let _TableEvents =
                    <<<TableName>>>
                    | where <<<TableTimeColumn>>> between (table_start .. table_end)<<<PreTableOperators>>>
                    // Filter events that may contain indicators<<<TITableConditions>>><<<PostTableOperators>>>
                    | project-rename <<<TableName>>>_TimeGenerated = TimeGenerated
                ;
                _Indicators
                | join kind=inner hint.strategy=shuffle _TableEvents on <<<TIGroupByColumn>>>
                // Take only a single event by key columns
                //| summarize hint.strategy=shuffle take_any(*) by <<<TIGroupByColumn>>><<<TableGroupByColumn>>>
                | project
                    <<<TableName>>>_TimeGenerated,
                    Description, ActivityGroupNames, IndicatorId, ThreatType, DomainName, Url, ExpirationDateTime, ConfidenceScore, SourceSystem, Tags, AdditionalInformation<<<TIExtendColumns>>><<<TIProjectColumns>>>,
                    <<<TableColumns&LookUp>>>
            };
            union// isfuzzy=true
                // Match      current table events                                all indicators available
                _TITableMatch(ago(query_frequency + query_wait), ago(query_wait),                           false),
                // Match      past table events                                                          new indicators since last query execution
                _TITableMatch(ago(table_query_lookback + query_wait), ago(query_frequency + query_wait),    true, ago(query_frequency))
            | summarize arg_max(<<<TableName>>>_TimeGenerated, *) by IndicatorId<<<TableGroupByColumn>>>
            | extend
                timestamp = <<<TableName>>>_TimeGenerated<<<TableCustomEntityExtend>>><<<TICustomEntityExtend>>><<<TableExclusion>>>

About this query

Explanation

This query defines a function called TIMapQueryGenerator that helps create consistent analytics rules for matching threat intelligence indicators with various data tables in Azure Sentinel. Here's a simplified breakdown:

  1. Purpose: The function is designed to streamline the process of writing analytics rules by centralizing the logic for matching different types of threat indicators (like URLs, IPs, file hashes, etc.) with corresponding data tables (like VMConnection, Syslog, SecurityAlert, etc.).

  2. Indicator and Table Definitions:

    • The function starts by defining a set of threat indicator types and their associated properties.
    • It then defines a set of data tables and their associated properties.
  3. Matching Logic:

    • For each combination of indicator type and data table, the function specifies how to match the indicators with the data in the table.
    • This includes defining lookback periods, filtering conditions, and how to handle specific fields in the data.
  4. Query Generation:

    • The function generates a query for each combination of indicator type and data table.
    • These queries are designed to find matches between threat indicators and data table entries, taking into account various conditions and exclusions.
  5. Usage:

    • Once the function is defined, it can be called to generate the necessary queries for all combinations of indicators and tables.
    • This ensures consistency and makes it easier to update the logic in one place if needed.

In essence, TIMapQueryGenerator is a powerful tool for automating and standardizing the creation of threat intelligence analytics rules in Azure Sentinel.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: April 1, 2024

Tables

_VMConnectionUrlClickEventsSyslogStorageFileLogsStorageBlobLogsAADManagedIdentitySignInLogsAADServicePrincipalSignInLogsADFSSignInLogsAADNonInteractiveUserSignInLogsSigninLogsSecurityEventSecurityAlertPowerPlatformConnectorActivityPowerAppsActivityOfficeActivityEmailUrlInfoEmailEventsEmailAttachmentInfoDnsEventsDeviceNetworkEventsDeviceFileEventsCisco_Umbrella_dns_CLAzureActivityAzureDiagnosticsAKSAuditAKSAuditAdminAZKVAuditLogsAZFWApplicationRuleAZFWIdpsSignatureAZFWNetworkRuleAZFWThreatIntelAWSCloudTrailAuditLogsAppServiceIPSecAuditLogsAppServiceAuditLogs

Keywords

ThreatIntelligenceIndicatorsThreatIntelligenceIndicatorsURLIPFileHashEmailDomainVMConnectionUrlClickEventsSyslogStorageFileLogsStorageBlobLogsAADManagedIdentitySignInLogsAADServicePrincipalSignInLogsADFSSignInLogsAADNonInteractiveUserSignInLogsSigninLogsSecurityEventSecurityAlertPowerPlatformConnectorActivityPowerAppsActivityOfficeActivityEmailUrlInfoEmailEventsEmailAttachmentInfoDnsEventsDeviceNetworkEventsDeviceFileEventsCiscoUmbrellaAzureActivityAzureSQLKubernetesLegacyKeyVaultFirewallDataLakeAWSCloudTrailAuditLogsAppServiceIPSecAuditLogsAppServiceAuditLogs

Operators

letdatatabledynamicstringprojectextendwheresummarizecountmake_set_ifisnotemptyarray_lengthtoscalarjoinkindleftantileftouteronbag_mergemv-expandtolowertoupperiffcasesplitarray_slicearray_concattrim_endtrim_startparseproject-renameproject-awayhint.strategyshufflearg_maxminmaxbetweenagonownotmaterializeunionisfuzzytake_anyreplace_stringstrcattostringtodynamicdynamic_to_jsonextract_allextractpack_arraymake_listmake_list_ifmake_bagmake_bag_ifparse_ipv4parse_ipv6ipv4_is_privateipv4_is_in_any_rangematchesregexreplace_regexhashas_anyhas_allendswithstartswithcoalescecolumn_ifexistsbag_keystodatetime

Actions

GitHub