다음을 통해 공유


MICROSOFT Sentinel에서 STIX 개체 및 지표를 사용하여 위협 인텔리전스 및 위협 헌팅 향상(미리 보기)

2025년 4월 3일, 저희는 STIX(구조화된 위협 정보 표현) 지표와 객체 스키마를 지원하기 위한 두 개의 새로운 테이블 ThreatIntelIndicatorsThreatIntelObjects을 공개적으로 미리 선보였습니다. 이 문서에서는 STIX 개체를 쿼리에 통합하여 위협 헌팅을 향상시키는 방법 및 새 위협 지표 스키마로 마이그레이션하는 방법에 대한 예제를 제공합니다.

Microsoft Sentinel의 위협 인텔리전스에 대한 자세한 내용은 Microsoft Sentinel의 위협 인텔리전스를 참조하세요.

중요합니다

Microsoft Sentinel은 2025년 7월 31일까지 동일한 데이터를 레거시 ThreatIntelIndicators 테이블에 계속 수집하면서 모든 위협 인텔리전스를 새 ThreatIntelObjects 테이블과 ThreatIntelligenceIndicator 테이블에 수집합니다. 2025년 7월 31일까지 새 테이블을 사용하도록 사용자 지정 쿼리, 분석 및 검색 규칙, 통합 문서 및 자동화를 업데이트해야 합니다. 이 날짜 이후 Microsoft Sentinel은 레거시 ThreatIntelligenceIndicator 테이블에 대한 데이터 수집을 중지합니다. 새 테이블을 활용하기 위해 콘텐츠 허브의 모든 기본 위협 인텔리전스 솔루션을 업데이트하고 있습니다. 데이터 다시 게시 프로세스에 대한 중요한 업데이트를 도입했습니다.

  1. 이전에는 데이터를 분할하고 12일 동안 Log Analytics에 다시 게시했습니다. 이제 모든 데이터7~10일마다 다시 게시됩니다. ThreatIntelIndicatorsThreatIntelObjects 테이블에서 이 데이터를 식별하려면 LastUpdateMethodLogARepublisher와 같은지 확인하십시오.
  2. 이제 새 테이블은 고급 헌팅 시나리오에서 사용되는 전체 데이터 개체(다른 열에 이미 존재하는 특성 제외)를 포함하는 Data 열을 포함하여 더 많은 열을 지원합니다. 이러한 열이 시나리오에 맞지 않는 경우 Log Analytics로 수집하기 전에 을 필터링하는 방법에 대해 자세히 알아보세요.
  3. Log Analytics에 대한 수집을 최적화하기 위해 데이터가 없는 키-값 쌍은 제외됩니다. 또한 열 내의 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 사용하여 새 테이블의 ObservableKey 열 및 ObservableValue 열을 기반으로 레거시 열을 다시 만듭니다.

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 작업 영역에 저장하기 전에 필터링하거나 수정할 수 있습니다. DCR(데이터 수집 규칙)에서 KQL(Kusto Query Language) 문으로 구현됩니다. 작업 영역 변환을 만드는 방법 및 변환 비용에 대해 자세히 알아봅니다.

Log Analytics로 전송되지 않도록 열 변환

테이블 ThreatIntelIndicatorThreatIntelObjects에는 전체 원래 STIX 객체를 포함하는 Data 열이 있습니다. 이 열이 사용 사례와 관련이 없는 경우 다음 KQL 문을 사용하여 데이터 처리 전에 제외할 수 있습니다.

source
| project-away Data

Log Analytics로 전송된 행을 제거 또는 변환

ThreatIntelIndicators 테이블은 만료되지 않은 각 표시기에 대해 항상 최소한 하나의 행을 받습니다. 경우에 따라 STIX 패턴을 키/값 쌍으로 구문 분석할 수 없습니다. 이 경우 지표는 여전히 Log Analytics로 전송되지만 구문 분석되지 않은 원시 패턴만 포함되므로 필요한 경우 사용자가 사용자 지정 분석을 빌드할 수 있습니다. 이러한 행이 시나리오에 유용하지 않은 경우 다음 KQL 문을 사용하여 수집 전에 해당 행을 필터링할 수 있습니다.

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

자세한 내용은 다음 문서를 참조하세요.

KQL에 대한 자세한 내용은 KQL(Kusto 쿼리 언어) 개요를 참조하세요.

기타 리소스: