使用 STIX 物件與指標,提升 Microsoft Sentinel (預覽) 中的威脅情報與威脅狩獵能力

2025 年 4 月 3 日,我們公開預覽了兩個新表格,以支援 STIX (結構化威脅資訊 eXpression) 指標與物件結構: ThreatIntelIndicators 以及 ThreatIntelObjects。 本文提供如何將 STIX 物件整合到查詢中以強化威脅狩獵的範例,以及如何遷移到新的威脅指標架構。

欲了解更多關於 Microsoft Sentinel 威脅情報的資訊,請參閱 Microsoft Sentinel 中的威脅情報

重要事項

Microsoft Sentinel 將所有威脅情報匯入新ThreatIntelIndicators資料表ThreatIntelObjects,並持續將相同資料匯入舊ThreatIntelligenceIndicator資料表,直到 2025 年 7 月 31 日。 請務必在 2025 年 7 月 31 日前更新您的自訂查詢、分析與偵測規則、工作簿及自動化,以使用新資料表。 在此日期之後,Microsoft Sentinel 將停止將資料匯入舊ThreatIntelligenceIndicator有資料表。 我們正在更新 Content Hub 中所有開箱即用的威脅情報解決方案,以利用這些新表格。 我們對資料重新發布流程進行了重要更新。

  1. 過去,資料會被分割並重新發布給Log Analytics,期限為 12天。 現在 ,所有數據7到10天重新發布一次。 你可以透過檢查 LastUpdateMethod 是否LogARepublisher等於 來識別 和 ThreatIntelObjects 表格中的這些資料ThreatIntelIndicators
  2. 新資料表現在支援更多欄位,包括欄位, Data 該欄位包含完整的資料物件 (,除了其他欄位中已存在的屬性外,) 用於進階狩獵場景。 如果這些欄位與你的情境不符,請在輸入 Log Analytics 前, 了解如何過濾欄位
  3. 為了優化對日誌分析的擷取,排除無資料的鍵值對。 此外,欄位中的 Data 某些欄位——如 descriptionpattern—— 若超過 1,000 字元,會被截斷。 欲了解更多關於更新架構及其可能影響使用情況的資訊,請參閱 ThreatIntelIndicatorsThreatIntelObjects

識別與特定威脅指標相關的威脅行為者

此查詢範例說明如何將威脅指標(如 IP 位址)與威脅行為者相關聯:

 let IndicatorsWithThatIP = (ThreatIntelIndicators
| extend tlId = tostring(Data.id)
| summarize arg_max(TimeGenerated,*) by Id
|  where IsDeleted == false);
let ThreatActors = (ThreatIntelObjects
| where StixType == 'threat-actor'
| extend tlId = tostring(Data.id)
| extend ThreatActorName = Data.name
| extend ThreatActorSource = base64_decode_tostring(tostring(split(Id, '---')[0]))
| summarize arg_max(TimeGenerated,*) by Id
|  where IsDeleted == false);
let AllRelationships = (ThreatIntelObjects
| where StixType == 'relationship'
| extend tlSourceRef = tostring(Data.source_ref)
| extend tlTargetRef = tostring(Data.target_ref)
| extend tlId = tostring(Data.id)
| summarize arg_max(TimeGenerated,*) by Id
|  where IsDeleted == false);
let IndicatorAsSource = (IndicatorsWithThatIP
| join AllRelationships on $left.tlId == $right.tlSourceRef
| join ThreatActors on $left.tlTargetRef == $right.tlId);
let IndicatorAsTarget = (IndicatorsWithThatIP
| join AllRelationships on $left.tlId == $right.tlTargetRef
| join ThreatActors on $left.tlSourceRef == $right.tlId);
IndicatorAsSource
| union IndicatorAsTarget
| project ObservableValue, ThreatActorName

此查詢提供威脅行為者) TTP (策略、技術與程序的洞見, (將該威脅行為者名稱替換 Sangria Tempest 為) :

let THREAT_ACTOR_NAME = 'Sangria Tempest';
let ThreatIntelObjectsPlus = (ThreatIntelObjects
| union (ThreatIntelIndicators
| extend StixType = 'indicator')
| extend tlId = tostring(Data.id)
| extend PlusStixTypes = StixType
| extend importantfield = case(StixType == "indicator", Data.pattern,
                            StixType == "attack-pattern", Data.name,
                            "Unkown")
| extend feedSource = base64_decode_tostring(tostring(split(Id, '---')[0]))
| summarize arg_max(TimeGenerated,*) by Id
|  where IsDeleted == false);
let ThreatActorsWithThatName = (ThreatIntelObjects
| where StixType == 'threat-actor'
| where Data.name == THREAT_ACTOR_NAME
| extend tlId = tostring(Data.id)
| extend ActorName = tostring(Data.name)
| summarize arg_max(TimeGenerated,*) by Id
|  where IsDeleted == false);
let AllRelationships = (ThreatIntelObjects
| where StixType == 'relationship'
| extend tlSourceRef = tostring(Data.source_ref)
| extend tlTargetRef = tostring(Data.target_ref)
| extend tlId = tostring(Data.id)
| summarize arg_max(TimeGenerated,*) by Id
|  where IsDeleted == false);
let SourceRelationships = (ThreatActorsWithThatName
| join AllRelationships on $left.tlId == $right.tlSourceRef
| join ThreatIntelObjectsPlus on $left.tlTargetRef == $right.tlId);
let TargetRelationships = (ThreatActorsWithThatName
| join AllRelationships on $left.tlId == $right.tlTargetRef
| join ThreatIntelObjectsPlus on $left.tlSourceRef == $right.tlId);
SourceRelationships
| union TargetRelationships
| project ActorName, PlusStixTypes, ObservableValue, importantfield, Tags, feedSource

將現有查詢遷移到新的 ThreatIntelIndicators 架構

此範例展示了如何將現有查詢從舊 ThreatIntelligenceIndicator 有資料表遷移到新 ThreatIntelIndicators 架構。 查詢會利用運算extend元根據新資料表中的 和 ObservableValue 欄位重建舊有欄位ObservableKey

ThreatIntelIndicators
| extend NetworkIP = iff(ObservableKey == 'ipv4-addr:value', ObservableValue, ''),
        NetworkSourceIP = iff(ObservableKey == 'network-traffic:src_ref.value', ObservableValue, ''),
        NetworkDestinationIP = iff(ObservableKey == 'network-traffic:dst_ref.value', ObservableValue, ''),
        DomainName = iff(ObservableKey == 'domain-name:value', ObservableValue, ''),
        EmailAddress = iff(ObservableKey == 'email-addr:value', ObservableValue, ''),
        FileHashType = case(ObservableKey has 'MD5', 'MD5',
                                ObservableKey has 'SHA-1', 'SHA-1',
                                ObservableKey has 'SHA-256', 'SHA-256',
                                ''),
        FileHashValue = iff(ObservableKey has 'file:hashes', ObservableValue, ''),
        Url = iff(ObservableKey == 'url:value', ObservableValue, ''),
        x509Certificate = iff(ObservableKey has 'x509-certificate:hashes.', ObservableValue, ''),
        x509Issuer = iff(ObservableKey has 'x509-certificate:issuer', ObservableValue, ''),
        x509CertificateNumber = iff(ObservableKey == 'x509-certificate:serial_number', ObservableValue, ''),        
        Description = tostring(Data.description),
        CreatedByRef = Data.created_by_ref,
        Extensions = Data.extensions,
        ExternalReferences = Data.references,
        GranularMarkings = Data.granular_markings,
        IndicatorId = tostring(Data.id),
        ThreatType = tostring(Data.indicator_types[0]),
        KillChainPhases = Data.kill_chain_phases,
        Labels = Data.labels,
        Lang = Data.lang,
        Name = Data.name,
        ObjectMarkingRefs = Data.object_marking_refs,
        PatternType = Data.pattern_type,
        PatternVersion = Data.pattern_version,
        Revoked = Data.revoked,
        SpecVersion = Data.spec_version
| project-reorder TimeGenerated, WorkspaceId, AzureTenantId, ThreatType, ObservableKey, ObservableValue, Confidence, Name, Description, LastUpdateMethod, SourceSystem, Created, Modified, ValidFrom, ValidUntil, IsDeleted, Tags, AdditionalFields, CreatedByRef, Extensions, ExternalReferences, GranularMarkings, IndicatorId, KillChainPhases, Labels, Lang, ObjectMarkingRefs, Pattern, PatternType, PatternVersion, Revoked, SpecVersion, NetworkIP, NetworkDestinationIP, NetworkSourceIP, DomainName, EmailAddress, FileHashType, FileHashValue, Url, x509Certificate, x509Issuer, x509CertificateNumber, Data

將傳送至Log Analytics的資料轉送出去

Azure Monitor 中的轉換功能允許你在資料儲存到 Log Analytics 工作空間之前,對其進行過濾或修改。 它們以 Kusto 查詢語言 (KQL) 語句的形式實作於 DCR) 的資料收集規則中 (。 了解更多關於如何 打造工作空間轉型 及其 成本的資訊。

將送往 Log Analytics 的欄位轉掉

ThreatIntelIndicatorThreatIntelObjects表格包含一個Data欄位,包含完整的原始 STIX 物件。 如果這欄與你的使用情境無關,你可以在擷取前用以下 KQL 語句過濾掉它:

source
| project-away Data

將送往 Log Analytics 的列轉換

ThreatIntelIndicators表格中每個未過期指示器至少會接收一列。 在某些情況下,STIX 模式無法解析成鍵值對。 當這種情況發生時,指標仍會傳送到Log Analytics,但只包含原始且未解析的模式——讓使用者在需要時能建立自訂分析。 如果這些列對你的情境沒用,你可以在輸入前用以下 KQL 語句過濾掉它們:

source
| where (ObservableKey != "" and isnotempty(ObservableKey)) 
    or (ObservableValue != "" and isnotempty(ObservableValue))

如需詳細資訊,請參閱下列文章:

欲了解更多關於KQL的資訊,請參閱Kusto 查詢語言 (KQL) 概述

其他資源: