YARA-L 2.0 쿼리 참조 라이브러리

다음에서 지원:

이 문서에서는 YARA-L 2.0으로 작성된 쿼리를 보여줍니다. 각 예시에서는 쿼리 규칙 언어 내에서 이벤트의 상관관계를 지정하여 보안 위협을 식별하고, 엔티티 동작을 모니터링하고, 비즈니스 로직으로 감지를 보강하는 방법을 보여줍니다.

단일 이벤트 감지, 정규 표현식 일치, 네트워크 범위 필터링 등 YARA-L 2.0의 기본 요소로 예시를 사용합니다. 이러한 예는 기본 로직에서 고급 다중 이벤트 상관관계 및 복합 감지로 진행하는 데 도움이 되도록 기능별 카테고리로 정리되어 있습니다.

기본 구문 및 기본

이 섹션의 예시에서는 규칙 언어 내에서 UDM 이벤트를 효과적으로 상관관계 지정하고 쿼리를 구조화하는 방법을 보여줍니다.

주제 예시
단일 이벤트 쿼리 초기 사용자 로그인 검색; 5분 로그인 감지
쿼리 및 조정 제외 기반 프로세스 감지
네트워크 범위 및 논리 단일 이벤트 일치 (IP 범위)
쿼리의 정규 표현식 이메일 필터링; 호스트 이름 정규식; 원시 로그 검색
범용 조건이 있는 반복 필드 의심스러운 로그인 IP 유효성 검사

단일 이벤트 쿼리

사용 사례: 시간 창에서 상관관계를 지정할 필요 없이 특정 이벤트 유형 (예: USER_LOGIN)을 기본적으로 감지합니다.

핵심 로직: 이벤트 및 조건 섹션만 사용하여 단일 발생을 식별합니다. 단일 이벤트 규칙은 다음과 같을 수 있습니다.

  • match 섹션이 없는 모든 규칙
  • 하나의 이벤트 존재만 확인하는 match 섹션 및 condition 섹션의 규칙 (예: $e, #e > 0, #e >= 1, 1 <= #e, 0 < #e)

규칙

다음 규칙 예시는 사용자 로그인 (USER_LOGIN) 이벤트를 검색하고 Google SecOps 계정 내에 저장된 기업 데이터 내에서 발생하는 첫 번째 항목을 반환합니다.

rule SingleEventRule {
meta:
  author = "noone@altostrat.com"

events:
  $e.metadata.event_type = "USER_LOGIN"

condition:
  $e
}

이 집계되지 않은 검색 예시에서는 개별 이벤트를 직접 출력합니다. 이 쿼리에는 이벤트 상관관계가 필요하지 않으므로 $e1와 같은 이벤트 변수가 생략됩니다.

metadata.event_type = "USER_LOGIN"

대시보드

이 쿼리 로직은 상관관계가 없는 특정 이벤트를 원시 상태로 표시하는 데 중점을 두므로 대시보드 시각화에 필요한 match 또는 outcome 섹션을 사용하지 않습니다.

예: 5분 로그인 감지

규칙

다음 예에서는 match 섹션을 사용하여 5분 (5m) 시간 범위 내에 로그인 이벤트가 하나 이상 발생한 사용자를 찾는 단일 이벤트 규칙을 보여줍니다. 사용자 로그인 이벤트의 존재를 확인합니다.

rule SingleEventRule {
meta:
  author = "alice@example.com"
  description = "windowed single event example rule"

events:
  $e.metadata.event_type = "USER_LOGIN"
  $e.principal.user.userid = $user

match:
  $user over 5m

condition:
  #e > 0
}

검색

이 통계 검색 예에서는 활동을 5분 (5m) 텀블링 윈도로 집계하며, 창당 사용자당 하나의 행을 출력합니다. 쿼리는 윈도우당 볼륨 수에 초점을 맞추므로 결과에 하나 이상의 이벤트가 포함되어 있기 때문에 event 변수와 condition 섹션이 생략됩니다. 이 버전에서는 홉핑 윈도우 대신 텀블링 윈도우를 사용하여 플랫폼 내에서 결과가 올바르게 렌더링되도록 합니다.

metadata.event_type = "USER_LOGIN"
principal.user.userid = $user

match:
  $user by 5m

대시보드

다음 예시에서는 outcome 섹션을 통합하여 사용자당 총 이벤트 수를 계산합니다. 이를 통해 데이터를 시간 경과에 따른 통계 값으로 표시할 수 있습니다. 이 쿼리는 홉핑 윈도우 대신 텀블링 윈도우를 사용하여 데이터 포인트가 겹치지 않는 개별 버킷에 매핑되도록 하고 대시보드 추세에 대한 더 명확한 시각화를 제공합니다.

metadata.event_type = "USER_LOGIN"
principal.user.userid = $user

match:
  $user by 5m

outcome:
  $event_count = count(metadata.id)

쿼리 및 조정

사용 사례: 비표준 디렉터리에서 실행되는 Windows svchost.exe 감지

주요 논리: 부정 (not)과 정규 표현식 일치

예: 제외 기반 프로세스 감지

규칙

다음 규칙은 이벤트 데이터의 특정 패턴을 확인하고 패턴이 발견되면 감지를 만듭니다. 이 규칙에는 이벤트 유형과 metadata.event_type UDM 필드를 추적할 수 있도록 $e1 변수가 포함됩니다. 이 규칙은 e1과 일치하는 정규 표현식 특정 일치 항목을 확인합니다. $e1 이벤트가 발생하면 감지가 생성됩니다. not 조건은 악성이 아닌 특정 경로를 제외하는 규칙에 포함되어 있습니다. not 조건을 추가하여 거짓양성을 방지할 수 있습니다.

rule suspicious_unusual_location_svchost_execution
{
meta:
  author = "Google Cloud Security"
  description = "Windows 'svchost' executed from an unusual location"
  yara_version = "YL2.0"
  rule_version = "1.0"

events:
  $e1.metadata.event_type = "PROCESS_LAUNCH"
  re.regex($e1.principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
  not re.regex($e1.principal.process.command_line, `\\Windows\\System32\\`) nocase

condition:
  $e1
}

검색

이 예시에서는 집계되지 않은 검색을 실행하여 개별 이벤트를 출력합니다. 이 검색에서는 여러 인스턴스 간의 이벤트 상관관계가 필요하지 않으므로 $e1와 같은 이벤트 변수는 필요하지 않습니다.

metadata.event_type = "PROCESS_LAUNCH"
re.regex(principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
not re.regex(principal.process.command_line, `\\Windows\\System32\\`) nocase

대시보드

이 구문은 matchoutcome 섹션을 통합하여 시간 경과에 따른 이벤트 볼륨을 계산합니다. timestamp.get_timestamp() 함수는 추세 시각화를 위해 결과를 일별로 버킷팅합니다.

metadata.event_type = "PROCESS_LAUNCH"
re.regex(principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
not re.regex(principal.process.command_line, `\\Windows\\System32\\`) nocase
$date = timestamp.get_timestamp(metadata.event_timestamp.seconds)

match:
  $date

outcome:
  $event_count = count(metadata.id)

네트워크 범위 및 논리

사용 사례: 특정 IP 서브넷 (CIDR)을 기반으로 활동을 필터링하고 가능한 여러 호스트 이름과 일치시킵니다.

주요 개념:

  • net.ip_in_range_cidr(): 이 함수는 서브넷 일치 및 문자열 배열의 or 연산자에 대해 지정된 IP 주소가 지정된 클래스 없는 도메인 간 라우팅 (CIDR) 서브넷 내에 포함되어 있는지 확인합니다.
  • 논리 연산자 OR: 여러 조건을 결합하는 데 사용됩니다. 이벤트 섹션 내의 조건은 AND와 암시적으로 결합됩니다. OR 연산자는 가능한 여러 호스트 이름을 확인합니다.

예: 단일 이벤트 매칭 (IP 범위)

규칙

다음 예시는 2개의 특정 호스트 이름과 특정 IP 주소 범위 사이의 일치를 검색하는 단일 이벤트 규칙을 보여줍니다.

rule OrsAndNetworkRange {
meta:
  author = "noone@altostrat.com"

events:
  // Checks CIDR ranges.
  net.ip_in_range_cidr($e.principal.ip, "203.0.113.0/24")

  // Detection when the hostname field matches either value using or.
  $e.principal.hostname = /pbateman/ or $e.principal.hostname = /sspade/

condition:
  $e
}

검색

다음 쿼리 예시는 특정 IP 주소가 정의된 CIDR 범위 내에 있고 호스트 이름이 특정 사용자 패턴과 일치하는 이벤트를 식별합니다.

net.ip_in_range_cidr(principal.ip, "203.0.113.0/24")

principal.hostname = /pbateman/ or principal.hostname = /sspade/

감지 규칙이 아닌 검색어이므로 필터가 충족되면 전체 이벤트가 자동으로 반환됩니다. match 섹션은 principal.ipprincipal.hostname로 데이터를 그룹화합니다. 이벤트 상관관계가 실행되지 않으므로 condition 섹션이 필요하지 않으며 이벤트 변수 ($e)가 생략됩니다.

대시보드

다음 예시 쿼리는 고유 IP 및 호스트 이름 쌍을 그룹화하여 결과를 집계합니다.

net.ip_in_range_cidr(principal.ip, "203.0.113.0/24")

principal.hostname = /pbateman/ or principal.hostname = /sspade/

match:
  principal.ip, principal.hostname

쿼리의 정규 표현식

사용 사례: 대소문자를 무시하면서 유연한 문자열 패턴 (예: 이메일의 특정 도메인)을 검색합니다. 이는 검색 및 규칙에서 가장 흔히 사용됩니다.

핵심 로직: 기본 일치에는 /regex/ nocase를 사용하고 복잡한 필드 분석에는 re.regex() 함수를 사용합니다.

예: 이메일 필터링

규칙

다음 YARA-L 2.0 정규 표현식 예시는 altostrat.com 도메인에서 수신된 이메일이 있는 이벤트를 검색합니다. nocase$host 변수 regex 비교 및 regex 함수에 추가되었기 때문에 이 비교는 대소문자를 구분하지 않습니다.

rule RegexRuleExample {
meta:
  author = "noone@altostrat.com"

events:
  $e.principal.hostname = $host
  $host = /.*HoSt.*/ nocase
  re.regex($e.network.email.from, `.*altostrat\.com`) nocase

match:
  $host over 10m

condition:
  #e > 10
}

검색

검색 인터페이스에서 이 로직은 충실도가 높은 위협 헌팅 및 데이터 탐색에 사용됩니다. 분석가는 자동 알림을 기다리는 대신 UDM을 수동으로 쿼리하여 타겟팅된 이메일 도메인과 함께 명명 규칙과 일치하는 호스트 이름의 특정 인스턴스를 찾을 수 있습니다. 이는 이러한 이벤트를 영구 감지 규칙으로 승격하기 전에 이벤트의 양을 검증하는 기본 방법입니다.

principal.hostname = $host
$host = /.*HoSt.*/ nocase
re.regex(network.email.from, `.*altostrat\.com`) nocase
match:
 $host over 10m
 ```

대시보드

다음 로직은 hostnameemail 원격 분석을 10분 (10m) 버킷으로 집계하여 관심 있는 패턴을 식별합니다. 대시보드에서 사용하면 이 로직을 통해 분석가는 특정 애셋 (host과 일치)에서 altostrat.com 도메인으로의 통신 빈도를 시각화할 수 있습니다. 이 보기는 내부 데이터 이동 추세를 모니터링하고 중요한 기반 시설 전반에서 상위 토커를 식별하는 데 필수적입니다.

principal.hostname = $host
$host = /.*HoSt.*/ nocase
re.regex(network.email.from, `.*altostrat\.com`) nocase

match:
  $host over 10m
  ```

예: 호스트 이름 정규 표현식

규칙

다음 예에서는 보안 주체 hostname가 웹 (webserver) 또는 개발 (devserver) 서버로 식별되는 모든 활동 기록을 식별합니다. 이 도구는 대소문자를 구분하지 않는 정규 표현식을 사용하여 명명 규칙의 변형으로 인해 감지가 누락되지 않도록 합니다.

rule WebServerOrDevServerActivity {
meta:
 author = "Alex"
 description = "Detects events where the principal hostname is 'webserver' or 'devserver', ignoring case."
 severity = "Informational"

events:
 $e.principal.hostname = /webserver|devserver/ nocase

condition:
 $e
}

검색

다음 예에서 principal.hostname = /webserver|devserver/ nocase"WebServer01", "devserver-test", "MyWebServers"과 같은 호스트 이름과 일치합니다. 특정 이벤트를 찾는 데 자주 사용되는 사용 사례입니다.

// Use /regex/ followed by nocase for a case-insensitive match
principal.hostname = /webserver|devserver/ nocase

대시보드

이 특정 예는 대시보드에 시각화되지 않지만 이 규칙은 활성 알림과 지속적인 감지를 제공합니다. 수동 검토가 필요한 대시보드와 달리, 이렇게 하면 이러한 서버의 모든 활동 인스턴스가 즉시 검색할 수 있도록 탐지 엔진에서 자동으로 플래그가 지정되고 기록됩니다.

규칙

특정 시점 조사를 위해 수동 검색을 사용하는 동안 감지 규칙은 연중무휴 지속적인 원격 분석 모니터링을 제공합니다. 성공적인 검색어를 YARA-L 규칙으로 변환하여 알림 프로세스를 자동화할 수 있습니다.

규칙의 주요 이점:

  • 실시간 알림: 일치하는 항목이 시스템에 입력되면 자동으로 플래그를 지정합니다.
  • 지속성: 검색어를 수동으로 다시 입력할 필요가 없습니다.
  • 결과 작업: 분석가 분류 및 사고 대응을 위해 탐지 보기에 직접 제공됩니다.

검색

보안 분석가는 Google SecOps 내에서 파싱되지 않은 원시 로그를 검색하기 위해 regex를 자주 사용합니다. 이 작업을 사용하면 완전히 구조화되거나 색인이 생성되지 않은 특정 아티팩트도 유연한 패턴 일치를 통해 찾을 수 있습니다. 구문은 슬래시를 사용합니다.

raw = /host/

이 쿼리는 "host" 문자 시퀀스가 표시되는 모든 원시 로그 행을 반환합니다. 일치하는 원시 로그 콘텐츠의 예로는 "hostname": "myhost123"이 있습니다.

대시보드

이 특정 이벤트 유형에 전용 대시보드 변형이 없습니다. 이러한 감지를 대규모로 시각화하려면 다음을 수행하면 됩니다.

  • 대시보드 빌더 내에서 metadata.event_type를 막대 또는 원형 차트에 매핑합니다.
  • 7일, 30일 또는 90일 기간 동안 이러한 이벤트의 빈도를 추적하여 사용자 행동의 이상치를 파악합니다.

유니버설 조건이 있는 반복 필드

사용 사례: 데이터 목록 (반복 필드)이 포함된 이벤트를 감사하여 신뢰할 수 있는 예외가 없는지 확인합니다. 예를 들어 로그인과 연결된 모든 IP 주소가 알려진 보안 범위 밖에 있는지 확인합니다.

핵심 로직: all 연산자를 사용하여 반복 필드의 모든 요소를 특정 조건에 대해 평가하고 반복 필드를 자리표시자 변수 (예: $ip)에 할당하면 목록의 각 고유 값에 대해 별도의 감지가 생성되는 방법을 보여줍니다.

예: 의심스러운 로그인 IP 검증

규칙

다음 규칙은 모든 소스 IP 주소가 5분 (5m) 내에 안전한 것으로 알려진 IP 주소와 일치하지 않는 로그인 이벤트를 검색합니다.

rule SuspiciousIPLogins {
meta:
  author = "alice@example.com"

events:
  $e.metadata.event_type = "USER_LOGIN"

  // Detects if all source IP addresses in an event do not match "100.97.16.0"
  // For example, if an event has source IP addresses
  // ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
  // it will be detected since "100.97.16.1", "100.97.16.2",
  // and "100.97.16.3" all do not match "100.97.16.0".

  all $e.principal.ip != "100.97.16.0"

  // Assigns placeholder variable $ip to the $e.principal.ip repeated field.
  // There will be one detection per source IP address.
  // For example, if an event has source IP addresses
  // ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
  // there will be one detection per address.

  $e.principal.ip = $ip

match:
  $ip over 5m

condition:
  $e
}

검색

metadata.event_type = "USER_LOGIN"

// Detects if all source IP addresses in an event do not match "100.97.16.0"
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// it will be detected since "100.97.16.1", "100.97.16.2",
// and "100.97.16.3" all do not match "100.97.16.0".

all principal.ip != "100.97.16.0"

// Assigns placeholder variable $ip to the $e.principal.ip repeated field.
// There will be one detection per source IP address.
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// there will be one detection per address.

principal.ip = $ip

match:
  $ip over 5m

대시보드

metadata.event_type = "USER_LOGIN"

// Detects if all source IP addresses in an event do not match "100.97.16.0"
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// it will be detected since "100.97.16.1", "100.97.16.2",
// and "100.97.16.3" all do not match "100.97.16.0".

all principal.ip != "100.97.16.0"

// Assigns placeholder variable $ip to the $e.principal.ip repeated field.
// There will be one detection per source IP address.
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// there will be one detection per address.

principal.ip = $ip

match:
  $ip over 5m

고급 윈도잉

이 섹션에서는 다단계 패턴과 다른 규칙의 활동에 의해 트리거된 감지를 다룹니다.

주제 예시
다중 이벤트 상관관계 다구간 로그인 감지; 빠른 사용자 만들기 및 삭제
쿼리의 슬라이딩 기간 순차 이벤트 누락 감지
다중 이벤트 쿼리 빈번한 로그인 감지
계산된 결과가 포함된 멀티 이벤트 쿼리 무차별 입력 공격 후 로그인 성공; 시간 창 호스트 일치

다중 이벤트 상관관계

이 섹션에서는 여러 이벤트 또는 기간에 걸쳐 엔티티 (사용자 또는 호스트)를 추적하여 행동 패턴을 식별하는 방법을 보여주는 예를 제공합니다.

사용 사례: 한 사용자가 5분 (5m) 이내에 두 개 이상의 도시에서 로그인하는 불가능한 이동을 감지합니다.

키 로직: match 섹션을 사용하여 $user#city > 1별로 그룹화하여 고유한 위치 값을 찾습니다.

예: 여러 도시 로그인 감지

규칙

다음 규칙은 5 (5m)분 이내에 두 개 이상의 도시에서 회사에 로그인한 사용자를 검색합니다. 여기서 $usermatch 변수이고, $udm은 이벤트 변수이며, $city$user은 자리표시자 변수입니다.

rule DifferentCityLogin {
meta:

events:
  $udm.metadata.event_type = "USER_LOGIN"
  $udm.principal.user.userid = $user
  $udm.principal.location.city = $city

match:
  $user over 5m

condition:
  $udm and #city > 1
}

다음 설명에서는 이 규칙의 작동 방식을 설명합니다.

  • 이벤트를 사용자 이름($user)과 그룹으로 묶고 일치가 발견되면 이를 반환($user)합니다.
  • 기간은 5분 (5m)입니다. 즉, 서로 5분 (5m) 이내에 발생하는 이벤트만 상관관계가 지정됩니다.
  • 해당 이벤트 유형이 USER_LOGIN인 이벤트 그룹 ($udm)을 검색합니다.
  • 이 이벤트 그룹에 대해 이 규칙은 사용자 ID를 $user로 호출하고 로그인 도시를 $city로 호출합니다.
  • city 값 (#city로 표시됨)의 고유 숫자가 이벤트 그룹 ($udm)에서 5분 (5m) 기간 내에 1보다 크면 일치를 반환합니다.

검색

다음 예시 쿼리는 불가능한 이동 패턴을 식별하기 위해 이와 동등한 통계 검색을 실행합니다. 5분 (5m) 기간 내에서 사용자별로 USER_LOGIN 이벤트를 그룹화하고, 단일 ID에 대해 서로 다른 도시가 여러 개 감지된 인스턴스만 표시하도록 결과를 필터링합니다.

events:
  metadata.event_type = "USER_LOGIN"
  principal.user.userid = $user
  principal.location.city = $city

match:
  $user over 5m

condition:
  #city > 1

대시보드

다음 예시 쿼리는 계정 도용 가능성을 추적하는 것과 동일한 대시보드 시각화를 제공합니다. 5분 (5m) 기간 동안 사용자별로 USER_LOGIN 이벤트를 집계하고 단일 ID가 두 개 이상의 고유 도시 (#city)와 연결된 인스턴스를 필터링하여 시간 경과에 따른 이러한 고위험 지리적 이상치를 표시할 수 있습니다.

events:
  metadata.event_type = "USER_LOGIN"
  principal.user.userid = $user
  principal.location.city = $city

match:
  $user over 5m

condition:
  #city > 1

빠른 사용자 만들기 및 삭제

  • 사용 사례: 생성된 일회용 계정을 식별한 후 4시간 이내에 삭제합니다.

  • 핵심 로직: 공유된 $user 변수에서 두 이벤트 유형 (USER_CREATIONUSER_DELETION)을 조인하고 타임스탬프를 비교합니다.

예: 빠른 사용자 만들기 및 삭제

규칙

다음 규칙 예에서는 $create$delete가 이벤트 변수이고 $usermatch 변수이며 자리표시자 변수가 없는 4시간 (4h) 이내에 생성된 후 삭제된 사용자를 검색합니다.

rule UserCreationThenDeletion {
meta:

events:
  $create.target.user.userid = $user
  $create.metadata.event_type = "USER_CREATION"

  $delete.target.user.userid = $user
  $delete.metadata.event_type = "USER_DELETION"

  $create.metadata.event_timestamp.seconds <=
     $delete.metadata.event_timestamp.seconds

match:
  $user over 4h

condition:
  $create and $delete
}

검색

다음 예에서는 빠른 계정 수명 주기 변경사항을 식별하는 데 사용되는 다중 이벤트 통계 검색을 보여줍니다. 이 쿼리는 4시간 내에 사용자당 하나의 행을 출력하여 ID 생성과 삭제를 상호 연관시킵니다.

검색은 기본적으로 지정된 이벤트가 포함된 모든 기간을 반환하므로 condition 섹션이 필요하지 않습니다.

$create.target.user.userid = $user
$create.metadata.event_type = "USER_CREATION"

$delete.target.user.userid = $user
$delete.metadata.event_type = "USER_DELETION"

$create.metadata.event_timestamp.seconds <=
$delete.metadata.event_timestamp.seconds

match:
  $user over 4h

대시보드

다음 예는 시간 경과에 따른 계정 수명 주기 추세를 표시하도록 설계된 다중 이벤트 대시보드 검색을 보여줍니다. 텀블링 윈도우 (by 4h)를 활용하면 결과가 중복되지 않는 개별 시간 버킷에 매핑되므로 시각화에 적합합니다.

이 변형에는 각 기간 내에서 생성 이벤트의 고유 개수를 계산하는 outcome 섹션이 포함됩니다. 이전 검색과 달리 이 버전에서는 개별 로그 행이 아닌 집계 통계 값에 중점을 두므로 특정 이벤트 변수를 반환할 필요가 없습니다.

$create.target.user.userid = $user
$create.metadata.event_type = "USER_CREATION"

$delete.target.user.userid = $user
$delete.metadata.event_type = "USER_DELETION"

$create.metadata.event_timestamp.seconds <=
$delete.metadata.event_timestamp.seconds

match:
  $user by 4h

outcome:
  $event_count = count_distinct($create.metadata.id)

쿼리의 슬라이딩 기간

사용 사례: 특정 기간 내에 동일한 호스트에서 초기 이벤트 (firewall_1) 다음에 예상되는 후속 이벤트 (firewall_2)가 발생하지 않는 잠재적인 보안 문제를 감지합니다.

핵심 로직:

  • 피벗 이벤트: 규칙은 firewall_1의 이벤트를 중심으로 하며 $e1로 지정됩니다. $e1 이벤트가 발생할 때마다 피벗 역할을 합니다.
  • 기간: match 섹션 ($host over 10m after $e1)은 각 $e1 이벤트 직후에 시작되는 10분 기간을 정의합니다. 이 창은 새 $e1 이벤트가 발생할 때마다 슬라이드됩니다.
  • 상관관계: 이벤트가 호스트 이름 ($host)별로 그룹화됩니다.
  • 감지 조건 ($e1$e2): 다음과 같은 경우 특정 호스트에 대한 감지가 트리거됩니다.
    • firewall_1 ($e1)의 이벤트가 있습니다.
    • AND: 특정 $e1 이벤트 후 10분 이내에 동일한 호스트에 대해 firewall_2 ($e2)의 NO 이벤트가 발견됩니다.

예: 누락된 순차 이벤트 감지

규칙

다음 예에서는 기본 트리거 후 보조 이벤트가 발생하지 않는 인스턴스를 식별합니다. 10분 내에 !$e2 조건을 사용하면 이 규칙은 누락된 원격 분석을 신고합니다. 특히 한 위치에서 방화벽 로그가 확인되지만 다음 예상 홉에 표시되지 않는 경우 잠재적인 가시성 격차 또는 트래픽 감소를 나타냅니다.

rule MissingSequentialEvent {
meta:
  author = "alice@example.com"

events:
  $e1.metadata.product_name = "firewall_1"
  $e1.principal.hostname = $host

  $e2.metadata.product_name = "firewall_2"
  $e2.principal.hostname = $host

match:
// $e1 is the pivot; the 10-minute window starts at the $e1 timestamp
  $host over 10m after $e1

condition:
  $e1 and !$e2
}

검색

다음 예에서는 두 소스 간의 원격 분석 격차를 식별하는 데 사용되는 순차적 검색을 보여줍니다. $e1을 피벗으로 사용하면 10분 이내에 두 번째 방화벽에서 해당 이벤트가 발생하지 않는 기본 방화벽 이벤트를 검색합니다. 이는 조사 중에 네트워크 트래픽의 '블랙홀'을 수동으로 찾거나 로깅 실패를 찾는 데 매우 효과적인 방법입니다.

$e1.metadata.product_name = "firewall_1"
$e1.principal.hostname = $host

$e2.metadata.product_name = "firewall_2"
$e2.principal.hostname = $host

match:
// $e1 is the pivot; the 10-minute window starts at the $e1 timestamp
  $host over 10m after $e1

condition:
  $e1 and !$e2

대시보드

다음 예에서는 대시보드 뷰를 위해 설계된 가시성 격차 분석을 제공합니다. 보조 이벤트가 기본 이벤트를 따르지 않는 인스턴스를 집계하면 시간 경과에 따른 로깅 파이프라인의 안정성을 시각화할 수 있습니다. 이러한 '누락된' 이벤트를 표시하면 네트워크 가시성의 지속적인 데드존이나 특정 호스트 이름의 구성 문제를 식별하는 데 도움이 됩니다.

$e1.metadata.product_name = "firewall_1"
$e1.principal.hostname = $host

$e2.metadata.product_name = "firewall_2"
$e2.principal.hostname = $host

match:
// $e1 is the pivot; the 10-minute window starts at the $e1 timestamp
  $host over 10m after $e1

condition:
  $e1 and !$e2

멀티 이벤트 쿼리

  • 사용 사례: 특정 시간 내에 이벤트가 여러 번 발생하는 동안 단일 항목 (예: 사용자 또는 호스트)을 추적하여 빈도가 높거나 무차별 대입 활동을 식별합니다.

  • 핵심 로직: match 섹션을 사용하여 특정 변수별로 이벤트를 그룹화하고 condition 섹션을 사용하여 정의된 시간 범위 내에서 기준점 수 (예: #e >= 10)를 확인합니다.

일반적인 멀티 이벤트 규칙에는 다음이 포함됩니다.

  • 이벤트를 구분하는 이벤트 변수입니다.
  • 이벤트를 그룹화해야 하는 시간 범위를 지정하는 match 섹션
  • 발견 항목을 트리거하고 여러 이벤트의 존재 여부를 확인하는 조건을 지정하는 condition 섹션

검색에서 다중 이벤트 쿼리는 쿼리에 두 개 이상의 이벤트가 있는 경우로 정의됩니다. 규칙의 경우 이를 정의하는 방법은 두 가지입니다.

  • 여러 이벤트: (예: event1 = successful login, event2 = failed login).

  • 조건 기반 트리거: 여러 이벤트가 기준 (예: event1 > 10)을 충족하는 경우에만 트리거되도록 조건이 명시됩니다. 이 유형의 규칙에는 outcome 섹션도 포함되어야 합니다.

예: 빈도가 높은 로그인 감지

규칙

다음 규칙은 10분 이내에 최소 10번 이상 로그인한 사용자를 검색합니다.

rule MultiEventRule {
meta:
  author = "noone@altostrat.com"

events:
  $e.metadata.event_type = "USER_LOGIN"
  $e.principal.user.userid = $user

match:
  $user over 10m

condition:
  #e >= 10
}

검색

다음 예에서는 다중 이벤트 통계 검색을 사용하여 빈도가 높은 로그인 활동을 식별합니다. 단일 사용자가 10분 (10m) 내에 10개 이상의 로그인 이벤트를 생성하는 인스턴스에 플래그를 지정합니다.

$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $user

match:
  $user by 10m

condition:
  #e >= 10

대시보드

다음 예에서는 다중 이벤트 검색을 사용하여 계정 도용 가능성을 모니터링합니다. 10분 슬라이딩 윈도우 내에서 로그인 시도를 상호 연관시켜 특정 사용자와 호스트가 여러 번의 로그인 실패 후 성공한 사례를 식별하므로 위험도가 높은 인증 패턴을 실시간으로 시각화할 수 있습니다.

$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $user

match:
  $user by 10m

condition:
  #e >= 10

계산된 결과가 있는 멀티 이벤트 쿼리

  • 사용 사례: 조건부 로직을 적용하여 애셋 심각도 또는 네트워크 볼륨에 따라 risk_score를 설정합니다.

  • 핵심 로직: outcome 섹션을 사용하여 변수를 계산하고 조건 섹션을 사용하여 해당 변수로 필터링합니다.

예: 무차별 대입 후 로그인 성공

다음 예시에서는 outcome 섹션을 사용하여 match 기간 내의 이벤트를 집계합니다. 이 쿼리는 표준 다중 이벤트 쿼리와 동일한 출력을 생성하지만 계산된 변수를 감지 로직에 통합하는 방법을 보여줍니다.

규칙

rule PossibleBruteForceThenSuccessfulLogin {
meta:
  author = "Alex"
  description = "Detects multiple failed login attempts followed by a successful login for the same user and host within a 10-minute window."
  severity = "High"
  tactic = "Credential Access"

events:
  // Define the first type of event: Failed Login
  // We use $failed to represent any event matching these criteria.
  $failed.metadata.event_type = "USER_LOGIN"
  $failed.security_result.action = "FAIL"
  // Extract common fields to correlate on
  $failed.target.user.userid = $user
  $failed.principal.hostname = $hostname

  // Define the second type of event: Successful Login
  // We use $success to represent any event matching these criteria.
  $success.metadata.event_type = "USER_LOGIN"
  $success.security_result.action = "ALLOW"
  // Correlate using the same user and hostname placeholders
  $success.target.user.userid = $user
  $success.principal.hostname = $hostname

match:
  // This section is key for multi-event rules. It groups events:
  // - By the common placeholder variables: $user and $hostname.
  // - Within a time window: by 10m.
  // The rule will evaluate all events matching $failed or $success that share the same $user and $hostname within any given 10-minute period.
  $user, $hostname by 10m

outcome:
  // Calculate aggregate values from the events within the match window.
  $failed_login_count = count($failed.metadata.id)
  $successful_login_count = count($success.metadata.id)

condition:
  // The conditions that must be met *within each matched group* ($user, $hostname over 10m).
  // - #failed >= 5: There must be 5 or more events matching the $failed criteria.
  // - #success >= 1: There must be at least 1 event matching the $success criteria.
  #failed >= 5 and #success >= 1
}

검색

// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname

// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname

match:
  // This section is key for multi-event rules. It groups events:
  // - By the common placeholder variables: $user and $hostname.
  // - Within a sliding time window: over 10m.
  // The rule will evaluate all events matching $failed or $success that share
  // the same $user and $hostname within any given 10-minute period.
  $user, $hostname over 10m

대시보드

// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname

// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname

match:
  // This section is key for multi-event rules. It groups events:
  // - By the common placeholder variables: $user and $hostname.
  // - Within a sliding time window: over 10m.
  // The rule will evaluate all events matching $failed or $success that share
  // the same $user and $hostname within any given 10-minute period.
  $user, $hostname over 10m

예: 시간 창 호스트 일치

규칙

다음 규칙에서는 두 가지 이벤트를 확인하여 $hostname 값을 가져옵니다. $hostname 값이 5분 (5m) 이상 일치하면 심각도 점수가 적용됩니다. match 섹션에 기간을 포함하면 규칙이 지정된 기간 내에 확인합니다.

rule OutcomeRuleMultiEvent {
meta:
  author = "Google Cloud Security"
events:
  $u.udm.principal.hostname = $hostname
  $asset_context.graph.entity.hostname = $hostname

  $severity = $asset_context.graph.entity.asset.vulnerabilities.severity

match:
  $hostname over 5m

outcome:
  $risk_score =
    max(
        100
      + if($hostname = "my-hostname", 100, 50)
      + if($severity = "HIGH", 10)
      + if($severity = "MEDIUM", 5)
      + if($severity = "LOW", 1)
    )

  $asset_id_list =
    array(
      if($u.principal.asset_id = "",
          "Empty asset id",
          $u.principal.asset_id
      )
    )

  $asset_id_distinct_list = array_distinct($u.principal.asset_id)

  $asset_id_count = count($u.principal.asset_id)

  $asset_id_distinct_count = count_distinct($u.principal.asset_id)

condition:
  $u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
}

검색

 // Define the first type of event: Failed Login
 // We use $failed to represent any event matching these criteria.
 $failed.metadata.event_type = "USER_LOGIN"
 $failed.security_result.action = "FAIL"
 // Extract common fields to correlate on
 $failed.target.user.userid = $user
 $failed.principal.hostname = $hostname

 // Define the second type of event: Successful Login
 // We use $success to represent any event matching these criteria.
 $success.metadata.event_type = "USER_LOGIN"
 $success.security_result.action = "ALLOW"
 // Correlate using the same user and hostname placeholders
 $success.target.user.userid = $user
 $success.principal.hostname = $hostname

match:
 // This section is key for multi-event rules. It groups events:
 // - By the common placeholder variables: $user and $hostname.
 // - Within a sliding time window: over 10m.
 // The rule will evaluate all events matching $failed or $success that share
 // the same $user and $hostname within any given 10-minute period.
 $user, $hostname over 10m

outcome:
 // Calculate aggregate values from the events within the match window.
 $failed_login_count = count($failed.metadata.id)
 $successful_login_count = count($success.metadata.id)
 ```

대시보드

// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname

// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname

match:
 // This section is key for multi-event rules. It groups events:
 // - By the common placeholder variables: $user and $hostname.
 // - Within a sliding time window: over 10m.
 // The rule will evaluate all events matching $failed or $success that share
 // the same $user and $hostname within any given 10-minute period.
 $user, $hostname over 10m

outcome:
  // Calculate aggregate values from the events within the match window.
  $failed_login_count = count($failed.metadata.id)
  $successful_login_count = count($success.metadata.id)

복합 감지

복합 탐지는 복합 규칙을 사용하여 위협 탐지를 강화합니다. 이러한 복합 규칙은 다른 규칙의 감지를 입력으로 사용합니다. 이를 통해 개별 규칙에서 감지하지 못할 수 있는 복잡한 위협을 감지할 수 있습니다. 자세한 내용은 컴포지트 감지 개요를 참고하세요.

주제 예시
고위험 필터링 관리 권한 사용자 감지
집계 및 기준점 설정 위험 집계
전술 집계 MITRE 전술 집계
순차적 복합 감지 무차별 대입 시도 후 로그인 성공
컨텍스트 인식 감지 위협 인텔리전스 보강
동시 발생 감지 권한 에스컬레이션 및 정보 유출 동시 발생

고위험 필터링

사용 사례: 관리 계정과 관련된 활동과 같은 고위험 속성에 대한 기존 감지를 필터링합니다.

핵심 로직: 기존 발견 항목 내의 결과 또는 메타데이터 필드에서 작동합니다.

위험도가 높은 필터링 복합 감지는 결과 변수나 규칙 메타데이터와 같은 감지 결과 내 필드에서 작동하는 가장 간단한 형태의 복합 감지입니다. 관리자 사용자 또는 프로덕션 환경과 같이 위험이 더 높을 수 있는 조건에 대한 감지를 필터링하는 데 도움이 됩니다.

예: 관리 권한 사용자 감지

규칙

다음 복합 규칙은 행위자가 관리 권한 사용자로 식별되고 표준화된 위험 점수가 적용된 기존 감지를 검색합니다.

rule composite_admin_detection {
meta:
  rule_name = "Detection with Admin User"
  author = "Google Cloud Security"
  description = "Composite rule that looks for any detections where the actor is an admin user"
  severity = "Medium"

events:
  $rule_name = $d.detection.detection.rule_name
  $principal_user = $d.detection.detection.variables["principal_users"]
  $principal_user = /admin|root/ nocase

match:
  $principal_user over 1h
outcome:
  $risk_score = 75
  $upstream_rules = array_distinct($rule_name)

condition:
  $d
}

검색

다음 통계 검색은 권한이 높은 계정의 활동을 식별하고 집계합니다. 'admin' 또는 'root' 사용자와 관련된 감지를 트리거한 모든 고유한 규칙 이름을 표시하도록 설계되었습니다.

이 특정 쿼리에서는 선택한 기간 내의 모든 감지에 대해 단일 통계 분석을 실행하기 위해 기간이 삭제됩니다. 또한 기존 감지 데이터에 초점을 맞춘 집계되지 않은 검색이므로 이벤트 섹션, 이벤트 변수, 조건 섹션은 필요하지 않습니다.

$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_users"]
$principal_user = /admin|root/ nocase

match:
  $principal_user

outcome:
  $upstream_rules = array_distinct($rule_name)

대시보드

이 대시보드 쿼리를 사용하면 관리자 관련 활동을 가장 자주 감지하는 특정 규칙을 시각화할 수 있습니다. 환경 전반의 감지 추세를 대략적으로 파악할 수 있도록 설계되었습니다.

이전 예시와 비교하여 match 변수와 outcome 집계가 변경되었음을 확인하세요. 이 쿼리는 규칙 이름별로 결과를 그룹화하고 각 규칙에 대해 감지된 관리자 사용자 수를 계산합니다.

$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_users"]
$principal_user = /admin|root/ nocase

match:
  $rule_name

outcome:
  $admin_detections = count($principal_user)

집계 및 기준점 설정

사용 사례: 알림을 많이 생성하거나 시간이 지남에 따라 위험 점수가 크게 누적되는 사용자 또는 호스트를 식별합니다.

핵심 로직: sum() 또는 count_distinct()을 사용하여 집계된 감지 데이터를 분석합니다.

집계 복합 감지 규칙을 사용하면 호스트 이름이나 사용자 이름과 같은 공유 속성을 기반으로 감지 결과를 그룹화하고 집계된 데이터를 분석할 수 있습니다. 일반적인 사용 사례는 다음과 같습니다.

  • 보안 알림 또는 집계된 위험이 많은 사용자를 식별합니다.
  • 관련 탐지를 집계하여 비정상적인 활동 패턴이 있는 호스트를 감지합니다.

예: 위험 집계

규칙

이 규칙은 48시간 동안 단일 사용자의 위험 점수를 집계합니다. 여러 감지에서 누적된 위험이 특정 기준점을 초과하는 사용자를 식별합니다.

업데이트된 논리에서 detection.detection.outcomesmatchoutcome 변수를 모두 저장하는 맵 필드 변수로 대체됩니다. 또한 각 발견 항목에는 이미 캡처된 정확히 하나의 일치 변수 값이 포함되어 있으므로 $principal_users 결과 변수가 삭제됩니다.

rule composite_risk_aggregation {
meta:
  rule_name = "Risk Aggregation Composite"
  author = "Google Cloud Security"
  description = "Composite detection that aggregates risk of a user over 48 hours"
  severity = "High"

events:
  $rule_name = $d.detection.detection.rule_name
  $principal_user = $d.detection.detection.outcomes["principal_users"]
  $risk = $d.detection.detection.risk_score

match:
  $principal_user over 48h

outcome:
  $risk_score = 90
  $cumulative_risk = sum($risk)
  $upstream_rules = array_distinct($rule_name)

condition:
  $d and $cumulative_risk > 500
}

검색

이 통계 검색은 감지 데이터를 집계하여 48시간 동안의 사용자의 총 위험을 계산합니다. 각 윈도우의 주 사용자별로 하나의 행을 출력하여 여러 감지 유형에 걸쳐 계정 위험을 개략적으로 보여줍니다.

이 변형에서는 이벤트 변수가 필요하지 않습니다. 규칙 엔진은 주 사용자가 없는 감지를 자동으로 필터링하지만, 이 검색에서는 결과에 채워진 데이터만 포함되도록 명시적 필터 ($principal_user != "")가 필요합니다. 기본적으로 쿼리는 특정 사용자에 대해 하나 이상의 감지가 있는 경우에만 결과를 반환합니다.

$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_user"]
$principal_user != ""
$risk = detection.detection.risk_score

match:
  $principal_user over 48h

outcome:
  $risk_score = 90
  $cumulative_risk = sum($risk)
  $upstream_rules = array_distinct($rule_name)

condition:
  $cumulative_risk > 500

대시보드

이 변형은 시간 경과에 따른 사용자 위험 및 탐지 활동을 표시하는 대시보드를 위해 특별히 설계되었습니다. 데이터를 개별 버킷으로 집계하므로 트리거된 고유 규칙의 수 또는 사용자별 총 감지 수와 같은 추세를 시각화하는 데 적합합니다.

이 쿼리에서는 윈도우가 슬라이딩 윈도우에서 텀블링 윈도우(by 48h)로 전환됩니다. 이렇게 하면 데이터 포인트가 겹치지 않는 시간 세그먼트에 매핑되어 시계열 차트의 시각화가 더 깔끔해집니다. 다른 집계되지 않은 검색과 마찬가지로 이벤트 변수는 필요하지 않으며 outcome 섹션이 확장되어 규칙 이름과 감지 ID의 개별 개수가 포함됩니다.

$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_user"]
$principal_user != ""
$risk = detection.detection.risk_score

match:
  $principal_user by 48h

outcome:
  $cumulative_risk = sum($risk)
  $rule_count = count_distinct($rule_name)
  $detection_count = count_distinct(detection.id)

condition:
  $cumulative_risk > 500

전략 집계

사용 사례: 여러 MITRE ATT&CK 전술에서 활동이 감지를 트리거하여 공격 수명 주기가 진행되고 있음을 시사하는 사용자 (예: 초기 액세스에서 유출로 전환)를 식별합니다.

주요 로직: 48시간 내에 사용자가 다양한 전략의 특정 기준점을 넘을 때만 트리거되도록 count_distinct($tactic)를 사용합니다.

예: MITRE 전술 집계

규칙

rule composite_tactic_aggregation {
meta:
  rule_name = "MITRE Tactic Aggregation Composite"
  author = "Google Cloud Security"
  description = "Composite detection that detects if a user has triggered detections over multiple mitre tactics."
  severity = "Medium"

events:
  $principal_user = $d.detection.detection.outcomes["principal_users"]
  $tactic = $d.detection.detection.outcomes["mitre_tactic"]
  $rule_name = $d.detection.detection.rule_name

match:
  $principal_user over 48h

outcome:
  $mitre_tactics_count = count_distinct($tactic)
  $mitre_tactics = array_distinct($tactic)
  $calculated_risk = 50 + (15 * $mitre_tactics_count)
  $upstream_rules = array_distinct($rule_name)

condition:
  $d and $mitre_tactics_count > 1 }

검색

다음 예는 기존 감지를 상호 연관시키고 동적 위험 가중치를 적용해야 하는 보안 개발자를 위해 설계된 검색 변형을 보여줍니다. 이 쿼리 로직은 detection 데이터 소스에서 MITRE ATT&CK 전술과 사용자 정보를 추출하고, 주 사용자를 기준으로 활동을 그룹화하고, 관찰된 전술의 다양성을 기반으로 맞춤 위험 점수를 계산합니다.

detection.detection.outcomes.key = "principal_users"
detection.detection.outcomes.key = "mitre_tactic"
$principal_user = detection.detection.outcomes["principal_users"]
$tactic = detection.detection.outcomes["mitre_tactic"]
$rule_name = detection.detection.rule_name

match:
  $principal_user

outcome:
  $mitre_tactics_count = count_distinct($tactic)
  $mitre_tactics = array_distinct($tactic)
  $upstream_rules = array_distinct($rule_name)
  $calculated_risk = 50 + (15 * $mitre_tactics_count)
  $risk_score = if($calculated_risk > 100, 100,   $calculated_risk)

대시보드

다음 예는 동일한 감지 분석 로직의 대시보드 변형을 보여줍니다. Google SecOps 대시보드 내에서 사용되는 이 쿼리를 통해 개발자는 다양한 규칙에서 감지 결과를 상호 연관시켜 위험도가 높은 사용자를 시각화할 수 있습니다. 이 로직은 기본 사용자와 MITRE 전술을 추출하고, 발견 항목을 집계하고, 상한이 적용된 위험 점수를 적용하여 대시보드 위젯 내에서 직접 조사 노력의 우선순위를 지정하는 데 도움을 줍니다.

detection.detection.outcomes.key = "principal_users"
detection.detection.outcomes.key = "mitre_tactic"
$principal_user = detection.detection.outcomes["principal_users"]
$tactic = detection.detection.outcomes["mitre_tactic"]
$rule_name = detection.detection.rule_name

match:
  $principal_user

outcome:
  $mitre_tactics_count = count_distinct($tactic)
  $mitre_tactics = array_distinct($tactic)
  $upstream_rules = array_distinct($rule_name)
  $calculated_risk = 50 + (15 * $mitre_tactics_count)
  $risk_score = if($calculated_risk > 100, 100,   $calculated_risk)
  ```

순차적 복합 감지

사용 사례: 작업 순서가 중요한 심각한 공격 패턴을 식별합니다. 예를 들어 동일한 IP 주소에서 일련의 무차별 대입 시도 알림이 발생한 후에만 성공한 계정 로그인을 감지합니다.

핵심 로직: 공통 변수 (예: $bruteforce_ip)에서 조인하고 타임스탬프 비교를 사용하여 이벤트가 올바른 순서로 발생했는지 확인하여 이전 감지와 후속 원시 UDM 이벤트를 상호 연관시킵니다.

순차적 복합 감지는 감지 순서가 중요한 관련 이벤트 패턴을 식별합니다(예: 무작위 대입 로그인 시도 감지 후 로그인 성공). 이러한 패턴에는 여러 기본 감지 또는 기본 감지와 이벤트의 조합이 포함될 수 있습니다.

예: 무차별 대입 시도 후 로그인 성공

규칙

다음 복합 규칙은 시퀀스가 중요한 관련 이벤트의 패턴을 식별합니다. 특히 24시간 내에 동일한 소스 IP에서 Google Workspace 무차별 대입 감지 후 성공적인 로그인 이벤트가 발생하는지 확인합니다.

rule composite_bruteforce_login {
meta:
  rule_name = "Bruteforce Login Composite"
  author = "Google Cloud Security"
  description = "Detects when an IP address associated with a Workspace brute force attempt successfully logs in"
  severity = "High"

events:
  $bruteforce_detection.detection.detection.rule_name = /Workspace Anomalous Failed Logins/
  $bruteforce_ip = $bruteforce_detection.detection.detection.variables["principal_ips"]

  $login_event.metadata.product_name = "login"
  $login_event.metadata.product_event_type = "login_success"
  $login_event.metadata.vendor_name = "Google Workspace"
  $login_ip = $login_event.principal.ip

  // Ensure the brute force detection and successful login occurred from the same IP
  $login_ip = $bruteforce_ip

  $target_account = $login_event.target.user.email_addresses

  // Ensure the brute force detection occurred before the successful login
  $bruteforce_detection.detection.detection_time.seconds < $login_event.metadata.event_timestamp.seconds

match:
  $bruteforce_ip over 24h

outcome:
  $risk_score = 90
  $principal_users = array_distinct($target_account)

condition:
  $bruteforce_detection and $login_event
}

검색

$bruteforce_detection.detection.detection.rule_name = /Workspace Anomalous Failed Logins/
$bruteforce_ip = $bruteforce_detection.detection.detection.variables["principal_ips"]

$login_event.metadata.product_name = "login"
$login_event.metadata.product_event_type = "login_success"
$login_event.metadata.vendor_name = "Google Workspace"
$login_ip = $login_event.principal.ip

// Ensure the brute force detection and successful login occurred from the same IP
$login_ip = $bruteforce_ip

$target_account = $login_event.target.user.email_addresses

// Ensure the brute force detection occurred before the successful login
$bruteforce_detection.detection.detection_time.seconds < $login_event.metadata.event_timestamp.seconds

match:
  $bruteforce_ip over 24h

outcome:
  $principal_users = array_distinct($target_account)

condition:
  $bruteforce_detection and $login_event

대시보드

대시보드는 원시 이벤트 데이터를 시각화하는 데 중점을 두는 반면, 복합 감지 로직은 기존 감지 알림을 후속 이벤트와 상호 연관시킵니다. 이 다층 분석은 실시간 대시보드 위젯이 아닌 감지 엔진에 최적화되어 있습니다.

컨텍스트 인식 탐지

사용 사례: 기존 탐지에 외부 위협 인텔리전스를 추가하여 알림에 알려진 악성 엔티티가 포함되어 있는지 확인합니다. 예를 들어 보안 탐지에서 플래그가 지정된 IP 주소가 글로벌 TOR 종료 노드 위협 피드에도 나열되어 있는지 확인합니다.

핵심 로직: IP 주소와 같은 공유 속성을 매칭하여 감지 결과를 GLOBAL_CONTEXT 그래프 데이터 (예: Google Cloud 위협 인텔리전스 피드)와 결합하는 복합 규칙을 사용합니다.

컨텍스트 인식 복합 탐지는 위협 피드에서 발견된 IP 주소와 같은 추가 컨텍스트로 탐지를 보강합니다.

예: 위협 인텔리전스 보강

규칙

다음 복합 규칙은 TOR 인텔 피드의 추가 컨텍스트를 기존 탐지에 자동으로 추가합니다. 이전 감지에서 발견된 IP 주소를 TOR 종료 노드 피드와 상호 연관시켜 발견 사항의 심각도와 위험 점수를 높입니다.

rule composite_tor_enrichment {
meta:
  rule_name = "Detection with IP from TOR Feed"
  author = "Google Cloud Security"
  description = "Adds additional context from the TOR intel feed to detections"
  severity = "High"

events:
  $rule_name = $d.detection.detection.rule_name

  $gcti.graph.metadata.entity_type = "IP_ADDRESS"
  $gcti.graph.metadata.vendor_name = "Google Cloud Threat Intelligence"
  $gcti.graph.metadata.source_type = "GLOBAL_CONTEXT"
  $gcti.graph.metadata.product_name = "GCTI Feed"
  $gcti.graph.metadata.threat.threat_feed_name = "Tor Exit Nodes"

  $detection_ip = $d.detection.detection.variables["principal_ips"]
  $detection_ip = $gcti.graph.entity.ip

match:
  $detection_ip, $rule_name over 1h

outcome:
  $risk_score = 80

condition:
  $d and $gcti
}

검색

``` $rule_name = $d.detection.detection.rule_name

$gcti.graph.metadata.entity_type = "IP_ADDRESS" $gcti.graph.metadata.vendor_name = "Google Cloud Threat Intelligence" $gcti.graph.metadata.source_type = "GLOBAL_CONTEXT" $gcti.graph.metadata.product_name = "GCTI Feed" $gcti.graph.metadata.threat.threat_feed_name = "Tor Exit Nodes"

$detection_ip = $d.detection.detection.variables["principal_ips"] $detection_ip = $gcti.graph.entity.ip

match: $detection_ip, $rule_name over 1h

condition: $d and $gcti ```

대시보드

동시 발생 감지

사용 사례: 특정 기간 내에 동일한 항목에 의해 트리거된 관련 전술의 조합을 감지합니다. 예를 들어 48시간 내에 권한 에스컬레이션 감지와 데이터 무단 반출 감지를 모두 트리거한 사용자를 식별합니다.

핵심 로직: match 섹션 내에서 공유된 항목 변수 (예: $pe_user)를 기준으로 조인하여 여러 개별 감지 유형을 상호 연관시키기 위해 집계 형식을 사용합니다.

동시 발생 복합 감지는 사용자가 트리거한 권한 에스컬레이션과 데이터 무단 반출 감지의 조합과 같은 관련 이벤트의 조합을 감지할 수 있는 집계의 한 형태입니다.

예: 권한 에스컬레이션 및 유출 동시 발생

규칙

다음 복합 규칙은 48시간 동안 동일한 사용자와 연결된 특정 감지 시퀀스 또는 조합(권한 에스컬레이션 후 유출)을 검색합니다.

rule composite_privesc_exfil_sequential {
meta:
  rule_name = "Privilege Escalation and Exfiltration Composite"
  author = "Google Cloud Security"
  description = "Looks for a detection sequence of privilege escalation followed by exfiltration."
  severity = "High"

events:
  $privilege_escalation.detection.detection.rule_labels["tactic"] = "TA0004"
  $exfiltration.detection.detection.rule_labels["tactic"] = "TA0010"

  $privesc_user = $privilege_escalation.detection.detection.variables["principal_users"]
  $exfil_user = $exfiltration.detection.detection.variables["principal_users"]

  $privesc_user = $exfil_user

  $privilege_escalation.detection.detection_time.seconds < $exfiltration.detection.detection_time.seconds

match:
  $privesc_user over 48h

outcome:
  $risk_score = 75
  $privesc_rules = array_distinct($privilege_escalation.detection.detection.rule_name)
  $exfil_rules = array_distinct($exfiltration.detection.detection.rule_name)

condition:
  $privilege_escalation and $exfiltration
}

검색

$privilege_escalation.detection.detection.rule_labels["tactic"] = "TA0004"
$exfiltration.detection.detection.rule_labels["tactic"] = "TA0010"

$privesc_user = $privilege_escalation.detection.detection.variables["principal_users"]
$exfil_user = $exfiltration.detection.detection.variables["principal_users"]

$privesc_user = $exfil_user

$privilege_escalation.detection.detection_time.seconds < $exfiltration.detection.detection_time.seconds

match:
  $privesc_user over 48h

outcome:
  $privesc_rules = array_distinct($privilege_escalation.detection.detection.rule_name)
  $exfil_rules = array_distinct($exfiltration.detection.detection.rule_name)

condition:
  $privilege_escalation and $exfiltration

대시보드

결과 및 변수 관리

이 섹션에서는 다운스트림 소비를 위해 위험을 계산하고 데이터를 정규화하는 예를 보여줍니다.

주제 예시
결과 조건문 계산된 위험 점수로 필터링
결과가 있는 단일 이벤트 쿼리 특정 시점 심각도 태그 지정
네트워크 기반 위험 점수 네트워크 기반 위험 점수 규칙
다중 이벤트 로직 리팩터링 (리팩터링 전) 결과 리팩터링 (리팩터링 전)
다중 이벤트 로직 리팩터링 (리팩터링 후) 결과 리팩터링 (리팩터링 후)
함수-자리표시자 할당

outcome 섹션이 있는 쿼리

YARA-L 2.0 규칙에 선택적인 outcome 섹션을 추가하여 각 발견 항목에 대한 추가 정보를 추출할 수 있습니다. condition 섹션에서 결과 변수에 조건부를 지정할 수도 있습니다. 감지 규칙의 outcome 섹션을 사용해서 다운스트림 소비에 대한 변수를 설정할 수 있습니다. 예를 들어 분석 중인 이벤트의 데이터를 기반으로 심각도 점수를 설정할 수 있습니다.

자세한 내용은 다음을 참조하세요.

결과 조건

사용 사례: 계산된 위험 점수를 기반으로 감지를 필터링하여 노이즈를 줄이고 신뢰도가 높거나 심각도가 높은 이벤트만 알림을 트리거하도록 합니다. 이는 특정 비즈니스 기준을 충족하지 않는 위험도가 낮은 활동을 억제하는 데 유용합니다.

핵심 로직: 조건부 수학 (예: 파일 크기 또는 시간대에 따라 위험 추가)을 사용하여 outcome 섹션에서 변수를 정의한 다음 condition 섹션에서 해당 변수를 참조하여 감지를 제한합니다.

예: 계산된 위험 점수로 필터링

규칙

condition 섹션에서 outcome 섹션에 정의된 outcome 변수를 사용할 수 있습니다. 다음 예시는 결과 조건부를 사용해서 감지에서 노이즈를 줄이기 위해 위험 점수를 필터링하는 방법을 보여줍니다.

rule OutcomeConditionalRule {
meta:
  author = "alice@example.com"
  description = "Rule that uses outcome conditionals"

events:
  $u.metadata.event_type = "FILE_COPY"
  $u.principal.file.size = $file_size
  $u.principal.hostname = $hostname

  // 1 = Sunday, 7 = Saturday.
  $dayofweek = timestamp.get_day_of_week($u.metadata.collected_timestamp.seconds)

outcome:
  $risk_score =
      if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
      if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
      if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
      if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices

condition:
  $u and $risk_score >= 10
}

검색

metadata.event_type = "FILE_COPY"
principal.file.size = $file_size
principal.hostname = $hostname

// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.collected_timestamp.seconds)

outcome:
  $risk_score =
      if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
      if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
      if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
      if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices

대시보드

이 쿼리는 각 위험 점수와 연결된 호스트를 시각화하기 위해 $hostname 결과 변수를 추가합니다.

metadata.event_type = "FILE_COPY"
principal.file.size = $file_size
principal.hostname = $hostname

// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.collected_timestamp.seconds)

outcome:
  $host = $hostname
  $risk_score =
      if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
      if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
      if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
      if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices

결과가 있는 단일 이벤트 쿼리

사용 사례: 시간 범위나 이벤트 상관관계가 필요하지 않고 사용자 목록이나 파일 속성을 기반으로 심각도 태그를 할당하는 등 즉각적인 컨텍스트로 특정 시점의 감지를 보강합니다.

핵심 로직: match 섹션이 없는 규칙에서 outcome 섹션을 사용합니다. 이렇게 하면 기준을 충족하는 모든 개별 이벤트에 대해 메타데이터를 추출하고 조건부 로직 (예: 참조 목록에 대한 사용자 확인)을 실행할 수 있습니다.

예: 특정 시점 심각도 태그 지정

규칙

다음 예에서는 단일 이벤트 규칙에서 outcome 섹션을 사용하여 다운스트림 소비를 위한 변수를 설정하는 방법을 보여줍니다. 예를 들어 파일 복사 이벤트에 관련된 특정 사용자 및 파일 크기에 따라 심각도 점수를 설정할 수 있습니다.

rule OutcomeRuleSingleEvent {
meta:
  author = "alice@example.com"
events:
  $u.metadata.event_type = "FILE_COPY"
  $u.principal.file.size = $file_size
  $u.principal.hostname = $hostname

outcome:
  $suspicious_host = $hostname
  $admin_severity = if($u.principal.user.userid in %admin_users, "SEVERE", "MODERATE")
  $severity_tag = if($file_size > 1024, $admin_severity, "LOW")

condition:
  $u
}

검색

다음 예에서는 파일 생성 이벤트를 식별하고 outcome 섹션을 사용하여 각 결과에 심각도 수준을 동적으로 할당합니다. 멀티 이벤트 규칙과 달리 이 집계되지 않은 검색에는 이벤트 변수나 match 섹션이 필요하지 않습니다. 대신 각 로그를 개별적으로 처리하여 파일 크기 및 사용자 권한에 기반한 맞춤 로직으로 보강된 1 row per event를 출력합니다.

metadata.event_type = "FILE_CREATION"
principal.file.size = $file_size
principal.hostname = $hostname

outcome:
  $suspicious_host = $hostname
  $admin_severity = if(principal.user.userid in %a1, "SEVERE", "MODERATE")
  $severity_tag = if($file_size > 1024, $admin_severity, "LOW")

대시보드

기본 의도가 개별 이벤트를 태그하고 보강하는 것이므로 이 예시에는 대시보드 변형이 적용되지 않습니다. 대시보드에서 이러한 이벤트를 집계할 수 있지만 (예: 심각도 태그별 이벤트 총수 계산) 이렇게 하면 이 집계되지 않은 검색이 표시하도록 설계된 세부적인 행 수준 세부정보가 가려집니다.

네트워크 기반 위험 점수

사용 사례: 이벤트 그룹 전체의 누적 네트워크 트래픽 양을 계산하여 위험도가 높은 데이터 전송을 식별합니다. 이를 통해 총 데이터 기준점이 특정 한도 (예: 1024바이트)를 초과하는 위협을 식별하는 동시에 관련 자산의 취약점 심각도를 고려할 수 있습니다.

핵심 로직: outcome 섹션에서 sum() 집계 함수를 사용하여 match 기간의 모든 이벤트에서 sent_bytesreceived_bytes를 결합합니다. 규칙의 경우 쿼리에서 if 문을 사용하여 합계가 정의된 기준을 초과하면 더 높은 위험 점수를 적용합니다.

예: 네트워크 기반 위험 점수 규칙

규칙

다음 예시에서는 outcome 섹션을 사용하여 네트워크 활동에 기반한 동적 위험 점수를 계산하는 방법을 보여줍니다. 이벤트 그룹에서 전송된 총 바이트를 합산하여 규칙은 특정 데이터 기준점 (1024바이트)을 초과하는 일치 항목에 더 높은 우선순위를 적용하는 동시에 관련 애셋의 취약점 심각도를 고려합니다.

rule OutcomeRuleMultiEvent {
meta:
  author = "alice@example.com"
events:
  $u.udm.principal.hostname = $hostname
  $asset_context.graph.entity.hostname = $hostname

  $severity = $asset_context.graph.entity.asset.vulnerabilities.severity

match:
  $hostname over 5m

outcome:
  $total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)

  $risk_score = if($total_network_bytes > 1024, 100, 50) +
    max(
      if($severity = "HIGH", 10)
      + if($severity = "MEDIUM", 5)
      + if($severity = "LOW", 1)
    )

  $asset_id_list =
    array(
      if($u.principal.asset_id = "",
          "Empty asset id",
          $u.principal.asset_id
      )
    )

  $asset_id_distinct_list = array_distinct($u.principal.asset_id)

  $asset_id_count = count($u.principal.asset_id)

  $asset_id_distinct_count = count_distinct($u.principal.asset_id)

condition:
  $u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
}

검색

다음 예에서는 UDM 네트워크 이벤트를 항목 컨텍스트 그래프 (ECG)의 애셋 컨텍스트와 상호 연관시키는 검색 변형을 보여줍니다. 5분 match 창을 사용하여 호스트 이름별로 네트워크 트래픽을 집계하고, 데이터 볼륨과 취약점 심각도를 기반으로 위험 점수를 계산하고, 조건부 필터를 적용하여 최종 결과 집합에서 특정 애셋 ID를 제외합니다.

$u.udm.principal.hostname = $hostname
$asset_context.graph.entity.hostname = $hostname

$severity = $asset_context.graph.entity.asset.vulnerabilities.severity

match:
  $hostname over 5m

outcome:
  $total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)

  $risk_score = if($total_network_bytes > 1024, 100, 50) +
    max(
      if($severity = "HIGH", 10)
      + if($severity = "MEDIUM", 5)
      + if($severity = "LOW", 1)
    )

  $asset_id_list =
    array(
      if($u.principal.asset_id = "",
        "Empty asset id",
        $u.principal.asset_id
      )
    )

  $asset_id_distinct_list = array_distinct($u.principal.asset_id)

  $asset_id_count = count($u.principal.asset_id)

  $asset_id_distinct_count = count_distinct($u.principal.asset_id)

condition:
  $u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")

대시보드

다음 예에서는 애셋 취약점 데이터로 실시간 네트워크 원격 분석을 보강하는 대시보드 변형을 보여줍니다. 이 쿼리를 사용하면 슬라이딩 5분 기간 동안 호스트 이름을 일치시켜 개발자가 애셋 위험 수준을 시각화하는 대시보드 위젯을 빌드할 수 있습니다. 이 로직은 네트워크 처리량과 애셋에서 발견된 가장 심각한 취약점을 기반으로 위험 점수를 동적으로 조정하여 잠재적으로 손상된 시스템의 우선순위가 지정된 뷰를 제공합니다.

$u.udm.principal.hostname = $hostname
$asset_context.graph.entity.hostname = $hostname

$severity = $asset_context.graph.entity.asset.vulnerabilities.severity

match:
  $hostname over 5m

outcome:
  $total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)

  $risk_score = if($total_network_bytes > 1024, 100, 50) +
    max(
      if($severity = "HIGH", 10)
      + if($severity = "MEDIUM", 5)
      + if($severity = "LOW", 1)
    )

  $asset_id_list =
    array(
      if($u.principal.asset_id = "",
        "Empty asset id",
        $u.principal.asset_id
      )
    )

  $asset_id_distinct_list = array_distinct($u.principal.asset_id)

  $asset_id_count = count($u.principal.asset_id)

  $asset_id_distinct_count = count_distinct($u.principal.asset_id)

condition:
  $u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")

멀티 이벤트 outcome 규칙 리팩터링 (리팩터링 전)

사용 사례: 멀티 이벤트 규칙을 싱글 이벤트 규칙으로 변환하여 시스템 성능을 개선하고 처리 지연 시간을 줄입니다. 이는 원래 결과 섹션을 사용 설정하기 위해서만 일치 섹션으로 설계되었지만 실제로 여러 개별 이벤트 간의 상관관계가 필요하지 않은 규칙에 적합합니다.

핵심 로직: match 섹션과 outcome 섹션의 집계 함수 (예: max(), sum(), count())를 삭제합니다. 이 전환을 통해 규칙은 시간 경과에 따른 이벤트 그룹화에서 이벤트가 도착할 때 각 이벤트를 개별적으로 평가하는 방식으로 변경됩니다. match 섹션이 없는 규칙) 및 멀티 이벤트 규칙 (match 섹션이 있는 규칙) 모두 match 섹션을 사용할 수 있습니다.

단일 이벤트 규칙(match 섹션이 없는 규칙) 및 멀티 이벤트 규칙(match 섹션이 있는 규칙) 모두 outcome 섹션을 사용할 수 있습니다. 이전에 결과 섹션을 사용할 수 있도록 규칙을 다중 이벤트로 설계한 경우, match 섹션을 삭제하여 해당 규칙을 선택적으로 리팩터링하면 성능을 개선할 수 있습니다. 규칙에 그룹화를 적용하는 match 섹션이 더 이상 없으므로 더 많은 감지가 수신될 수 있습니다.

예: 결과 리팩터링 (리팩터링 전)

규칙

다음 예시는 하나의 이벤트 변수만 사용하는 멀티 이벤트 결과 규칙을 보여줍니다. match 섹션을 사용하므로 규칙 엔진은 결과를 계산하기 전에 5분 동안 이벤트를 그룹화해야 하며, 이는 단일 이벤트 평가보다 더 많은 리소스를 소비합니다.

rule OutcomeMultiEventPreRefactor {
meta:
  author = "alice@example.com"
  description = "Outcome refactor rule, before the refactor"

events:
  $u.udm.principal.hostname = $hostname

match:
  $hostname over 5m

outcome:
  $risk_score = max(if($hostname = "my-hostname", 100, 50))

condition:
  $u
}

검색

통계 쿼리 동등 항목

events:
  $u.udm.principal.hostname = $hostname

match:
  $hostname over 5m

outcome:
  $risk_score = max(if($hostname = "my-hostname", 100, 50))

condition:
  $u

대시보드

events:
  $u.udm.principal.hostname = $hostname

match:
  $hostname over 5m

outcome:
  $risk_score = max(if($hostname = "my-hostname", 100, 50))

condition:
  $u

멀티 이벤트 outcome 규칙 리팩터링 (리팩터링 후)

사용 사례: 처리 속도를 개선하기 위해 쿼리 최적화 마무리 그룹화 요구사항을 삭제하면 이제 일치하는 단일 이벤트가 도착하는 즉시 쿼리가 감지를 트리거하므로 규칙 엔진의 효율성이 크게 향상됩니다.

핵심 로직: match 섹션을 삭제하고 outcome 변수 할당에서 aggregate 함수 (예: max())를 삭제합니다. if 문 내의 로직은 동일하지만 이제 그룹이 아닌 단일 이벤트에 적용됩니다.

match 섹션을 삭제하여 쿼리를 리팩터링할 수 있습니다. 참고: 이제 쿼리가 단일 이벤트가 되므로 outcome 섹션에서 집계도 삭제해야 합니다. 집계에 대한 자세한 내용은 결과 집계를 참조하세요.

예: 결과 리팩터링 (: #outcome-post-refactor)

규칙

rule OutcomeSingleEventPostRefactor {
meta:
  author = "alice@example.com"
  description = "Outcome refactor rule, after the refactor"

events:
  $u.udm.principal.hostname = $hostname

// We deleted the match section.

outcome:
  // We removed the max() aggregate.
  $risk_score = if($hostname = "my-hostname", 100, 50)

condition:
  $u
}

검색

events:
  $u.udm.principal.hostname = $hostname

outcome:
  $risk_score = if($hostname = "my-hostname", 100, 50)

대시보드

events:
  $u.udm.principal.hostname = $hostname

outcome:
  $risk_score = if($hostname = "my-hostname", 100, 50)

함수-자리표시자 할당

사용 사례: 일치 섹션의 그룹화가 정확한지 확인하기 위해 데이터를 정규화합니다 (예: 이메일 도메인 표준화).

핵심 로직: re.capture() 또는 strings.concat()의 결과를 자리표시자 변수에 할당합니다.

예: 함수-자리표시자 변수 할당

함수 호출의 결과에 자리 표시자 변수를 할당하고 match 섹션, outcome 섹션, condition 섹션과 같은 규칙의 다른 섹션에 자리 표시자 변수를 사용할 수 있습니다.

규칙

rule FunctionToPlaceholderRule {
meta:
  author = "alice@example.com"
  description = "Rule that uses function to placeholder assignments"

events:
  $u.metadata.event_type = "EMAIL_TRANSACTION"

  // Use function-placeholder assignment to extract the
  // address from an email.
  // address@website.com -> address
  $email_to_address_only = re.capture($u.network.email.to , "(.*)@")

  // Use function-placeholder assignment to normalize an email:
  // address@-> address@company.com
  $email_from_normalized = strings.concat(
      re.capture($u.network.email.from , "(.*)@"),
      "@company.com"
  )

  // Use function-placeholder assignment to get the day of the week of the event.
  // 1 = Sunday, 7 = Saturday.
  $dayofweek = timestamp.get_day_of_week($u.metadata.event_timestamp.seconds)

match:
  // Use placeholder (from function-placeholder assignment) in match section.
  // Group by the normalized from email, and expose it in the detection.
  $email_from_normalized over 5m

outcome:
  // Use placeholder (from function-placeholder assignment) in outcome section.
  // Assign more risk if the event happened on weekend.
  $risk_score = max(
      if($dayofweek = 1 or $dayofweek = 7, 10, 0)
  )

condition:
  // Use placeholder (from function-placeholder assignment) in condition section.
  // Match if an email was sent to multiple addresses.
  #email_to_address_only > 1
}

검색

metadata.event_type = "EMAIL_TRANSACTION"

// Use function-placeholder assignment to extract the
// address from an email.
// address@website.com -> address
$email_to_address_only = re.capture(network.email.from , "(.*)@")

// Use function-placeholder assignment to normalize an email:
// address@??? -> address@company.com
$email_from_normalized = strings.concat(
  re.capture(network.email.to , "(.*)@"),
  "@company.com"
  )

// Use function-placeholder assignment to get the day of the week of the event.
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.event_timestamp.seconds)

match:
  // Use placeholder (from function-placeholder assignment) in match section.
  // Group by the normalized from email, and expose it in the detection.
  $email_from_normalized over 5m

outcome:
  // Use placeholder (from function-placeholder assignment) in outcome section.
  // Assign more risk if the event happened on weekend.
  $risk_score = max(
    if($dayofweek = 1 or $dayofweek = 7, 10, 0)
    )

condition:
  // Use placeholder (from function-placeholder assignment) in condition section.
  // Match if an email was sent to multiple addresses.
  #email_to_address_only > 1

대시보드

다음 예에서는 시계열 시각화에 최적화된 대시보드 변형을 보여줍니다. 분 단위 세부사항 대신 1일 텀블링 윈도우를 사용하면 이 쿼리는 장기간에 걸쳐 위험 점수를 차트로 표시하는 데 적합한 안정적이고 중복되지 않는 데이터 포인트를 생성합니다. 이 로직은 이메일 항목을 정규화하고 주말 거래에 더 높은 위험 가중치를 적용하여 장기 모니터링을 위한 의심스러운 이메일 활동의 명확한 일일 추세를 제공합니다.

metadata.event_type = "EMAIL_TRANSACTION"

// Use function-placeholder assignment to extract the
// address from an email.
// address@website.com -> address
$email_to_address_only = re.capture(network.email.from , "(.*)@")

// Use function-placeholder assignment to normalize an email:
// address@??? -> address@company.com
$email_from_normalized = strings.concat(
re.capture(network.email.to , "(.*)@"),
"@company.com"
)

// Use function-placeholder assignment to get the day of the week of the event.
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.event_timestamp.seconds)

match:
// Use placeholder (from function-placeholder assignment) in match section.
// Group by the normalized from email, and expose it in the detection.
$email_from_normalized over 5m

outcome:
// Use placeholder (from function-placeholder assignment) in outcome section.
// Assign more risk if the event happened on weekend.
$risk_score = max(
  if($dayofweek = 1 or $dayofweek = 7, 10, 0)
  )

condition:
// Use placeholder (from function-placeholder assignment) in condition section.
// Match if an email was sent to multiple addresses.
#email_to_address_only > 1

최적화 및 필터링

효과적인 규칙 최적화는 정확한 데이터 필터링을 통해 감지 엔진이 의미 있는 정보만 처리하도록 하는 데 달려 있습니다. '노이즈' 또는 불완전한 데이터를 제외하면 규칙 성능을 크게 개선하고 생성된 알림이 실행 가능하도록 할 수 있습니다.

주제 예시
0 값 제외 명시적 및 암시적 0 값 제외

0 값 제외

사용 사례: 실행 가능한 보안 데이터를 제공하지 않는 빈 문자열, null 값 또는 일반 자리표시자 계정('게스트' 등)을 명시적으로 필터링하여 규칙 정확도를 높이고 오탐을 줄입니다.

핵심 로직: match 섹션에 사용된 변수에 대해 규칙 엔진의 암시적 0 값 필터링을 활용하는 동시에 다른 이벤트 필드에 명시적 부등호 연산자 (!= "")를 사용하여 값이 입력된 데이터만 감지를 트리거하도록 합니다.

규칙 엔진은 match 섹션에 사용된 모든 자리 표시자에 대해 0 값을 암시적으로 필터링합니다. 사용 중지하려면 allow_zero_values 옵션을 사용합니다. 하지만 다른 참조된 이벤트 필드의 경우 명시적으로 조건을 지정하지 않으면 0 값이 제외되지 않습니다. 자세한 내용은 일치 섹션의 0 값을 참고하세요.

예: 명시적 및 암시적 0 값 제외

규칙

rule ExcludeZeroValues {
meta:
  author = "alice@example.com"

events:
  $e1.metadata.event_type = "NETWORK_DNS"
  $e1.principal.hostname = $hostname

  // $e1.principal.user.userid may be empty string.
  $e1.principal.user.userid != "Guest"

  $e2.metadata.event_type = "NETWORK_HTTP"
  $e2.principal.hostname = $hostname

  // $e2.target.asset_id cannot be empty string as explicitly specified.
  $e2.target.asset_id != ""

match:
  // $hostname cannot be empty string. The rule behaves as if the
  // predicate, `$hostname != ""` was added to the events section, because
  // `$hostname` is used in the match section.
  $hostname over 1h

condition:
  $e1 and $e2
}

검색

match 섹션의 자리표시자에는 암시적 0 값 필터가 없으므로 hostname가 빈 문자열일 수 없다고 명시적으로 명시해야 합니다.

$e1.metadata.event_type = "NETWORK_DNS"
$e1.principal.hostname = $hostname

// $e1.principal.user.userid may be empty string.
$e1.principal.user.userid != "Guest"

$e2.metadata.event_type = "NETWORK_HTTP"
$e2.principal.hostname = $hostname

// $e2.target.asset_id and hostname cannot be empty string as explicitly specified.
$e2.target.asset_id != ""
$hostname != ""

match:
  $hostname over 1h

대시보드

match 섹션의 자리표시자에는 암시적 0 값 필터가 없으므로 hostname가 빈 문자열일 수 없다고 명시적으로 명시해야 합니다.

$e1.metadata.event_type = "NETWORK_DNS"
$e1.principal.hostname = $hostname

// $e1.principal.user.userid may be empty string.
$e1.principal.user.userid != "Guest"

$e2.metadata.event_type = "NETWORK_HTTP"
$e2.principal.hostname = $hostname

// $e2.target.asset_id and hostname cannot be empty string as explicitly specified.
$e2.target.asset_id != ""
$hostname != ""

match:
  $hostname over 1h

도움이 더 필요하신가요? 커뮤니티 회원 및 Google SecOps 전문가에게 문의하여 답변을 받으세요.