YARA-L에서 다단계 쿼리 만들기

다음에서 지원:

이 문서에서는 YARA-L의 다단계 쿼리를 사용하여 한 쿼리 단계의 출력을 후속 단계의 입력에 직접 제공하는 방법을 설명합니다. 이 프로세스를 사용하면 단일 모놀리식 쿼리보다 데이터 변환을 더 세부적으로 제어할 수 있습니다.

다단계 쿼리를 기존 기능과 통합

다단계 쿼리는 Google Security Operations의 다음 기존 기능과 함께 작동합니다.

  • 복합 감지 규칙: 다단계 쿼리는 복합 감지 규칙을 보완합니다. 복합 규칙과 달리 검색을 사용하는 다단계 쿼리는 결과를 실시간으로 반환할 수 있습니다.

  • 기간 및 멀티 이벤트 규칙: 다단계 쿼리를 사용하여 데이터 내의 여러 기간을 비교하여 이상치를 감지할 수 있습니다. 예를 들어 초기 쿼리 단계를 사용하여 장기간에 걸쳐 기준을 설정한 다음 후반 단계를 사용하여 해당 기준에 대한 최근 활동을 평가할 수 있습니다. 다중 이벤트 규칙을 사용하여 유사한 유형의 비교를 만들 수도 있습니다.

YARA-L의 다단계 쿼리는 대시보드검색 모두에서 지원됩니다.

조인은 여러 소스의 데이터를 상호 연관시켜 조사에 더 많은 컨텍스트를 제공합니다. 관련 이벤트, 엔티티, 기타 데이터를 연결하여 복잡한 공격 시나리오를 조사할 수 있습니다. 자세한 내용은 검색에서 조인 사용을 참고하세요.

다단계 YARA-L 구문 정의

다단계 쿼리를 구성할 때는 다음 사항에 유의하세요.

  • 제한 단계: 다단계 쿼리에는 루트 단계 외에 명명된 단계가 1~4개 포함되어야 합니다.
  • 순서 구문: 항상 루트 단계 구문을 정의하기 전에 이름이 지정된 단계 구문을 정의합니다.

다단계 YARA-L 쿼리 만들기

다단계 YARA-L 쿼리를 만들려면 다음 단계를 완료하세요.

단계 구조 및 문법

조사 > 검색으로 이동합니다. 쿼리 단계를 정의할 때는 다음 구조적 요구사항을 따르세요.

구문: 각 단계를 명명하고 다른 단계와 구분하려면 다음 구문을 사용합니다.

stage <stage name> { }

  • 중괄호: 모든 단계 구문을 중괄호 {} 안에 배치합니다.

  • 순서: 루트 단계를 정의하기 전에 이름이 지정된 모든 단계의 구문을 정의합니다.

  • 참조: 각 단계는 쿼리에서 이전에 정의된 단계를 참조할 수 있습니다.

  • 루트 단계: 쿼리에는 모든 명명된 단계 후에 처리되는 루트 단계가 있어야 합니다.

다음 예시 단계 daily_stats는 일일 네트워크 통계를 수집합니다.

stage daily_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $source = principal.hostname
  $target = target.ip
  $source != ""
  $target != ""
  $total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)
  match:
    $source, $target by day
  outcome:
    $exchanged_bytes = sum($total_bytes)
}

액세스 단계 출력

명명된 단계의 출력은 단계 필드를 사용하여 후속 단계에서 액세스할 수 있습니다. 스테이지 필드는 스테이지의 matchoutcome 변수에 해당하며 통합 데이터 모델 (UDM) 필드와 유사하게 사용할 수 있습니다.

다음 구문을 사용하여 단계 필드에 액세스합니다.

$<stage name>.<variable name>

액세스 기간 타임스탬프 (선택사항)

명명된 스테이지에서 홉, 슬라이딩 또는 텀블링 윈도우를 사용하는 경우 다음 예약된 필드를 사용하여 각 출력 행의 윈도우 시작 및 윈도우 끝에 액세스합니다.

  • $<stage name>.window_start

  • $<stage name>.window_end

window_startwindow_end은 Unix 에포크 이후 초 단위로 표현된 정수 필드입니다. 단계별 창의 크기는 다를 수 있습니다.

제한사항

다단계 쿼리에는 다음과 같은 기능 및 구조적 제약이 있습니다.

구조 및 단계 제한

  • 루트 단계: 쿼리당 하나의 루트 단계만 허용됩니다.

  • 이름이 지정된 단계: 이름이 지정된 단계는 최대 4개까지 지원됩니다.

  • 참조 단계: 단계는 동일한 쿼리에서 논리적으로 앞에 정의된 단계만 참조할 수 있습니다.

  • 조인: 모든 단계에서 데이터 테이블이 아닌 조인을 최대 4개까지 사용할 수 있습니다.

  • 결과 요구사항: 이름이 지정된 각 단계 (루트 단계 제외)에는 match 섹션 또는 outcome 섹션이 포함되어야 합니다. outcome 섹션에는 집계가 필요하지 않습니다.

창 및 호환성 한도

  • 기능 지원: 다단계 쿼리는 검색대시보드에서 지원되지만 규칙에서는 지원되지 않습니다.

  • 기간 유형: 단일 쿼리 내에서 다양한 기간 유형을 혼합하지 마세요.

  • 창 종속 항목: 홉 또는 슬라이딩 창을 사용하는 스테이지는 홉 또는 슬라이딩 창을 사용하는 다른 스테이지에 종속될 수 없습니다.

  • 텀블링 창 크기: 다양한 단계에서 텀블링 창의 크기는 다를 수 있지만 크기 차이는 720x 미만이어야 합니다.

예: 단계 집계 차이

다음 예시 창 구성은 허용되지 않습니다.

stage monthly_stats {
  metadata.event_type = "NETWORK_CONNECTION"
    $source = principal.hostname
    $target = target.ip
    $source != ""
    $target != ""
    $total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)

  match:
    $source, $target by month

  outcome:
    $exchanged_bytes = sum($total_bytes)
}

$source = $monthly_stats.source
$target = $monthly_stats.target

match:
    $source, $target by minute

monthly_stats 단계에서 월별로 데이터를 집계하고 루트 단계에서 monthly_stats의 출력을 분별로 집계하는 경우 monthly_stats의 각 행은 루트 단계의 43,200개 행에 매핑됩니다 (한 달에 43,200분이 있기 때문).

단계 및 쿼리 제한사항

다단계 쿼리 내의 각 개별 단계에는 다음과 같은 제약 조건이 있습니다.

  • 단일 단계 쿼리에 적용되는 대부분의 제한사항은 각 개별 단계에도 적용됩니다.

    • 출력 요구사항: 모든 단계는 하나 이상의 경기 또는 결과 변수 (단계 필드)를 출력해야 합니다.

    • 조인의 윈도우: 조인에 사용되는 최대 윈도우 크기 (홉, 텀블링 또는 슬라이딩)는 2일입니다.

    • 결과 변수의 최대 수:

      • 더 큰 결과 변수 한도를 허용하도록 선택하지 않은 고객의 경우 20

      • 더 큰 결과 변수 한도를 허용하도록 선택한 고객의 경우 50

    • 홉 창의 최소 및 최대 크기

    • 배열 값 결과 변수의 최대 요소 수

  • 다단계 쿼리에는 통계 쿼리와 동일한 제한사항이 적용됩니다.

    • 통계 쿼리: 120QPH (API 및 UI)

    • Google SecOps에서 뷰 검색: 분당 100개의 뷰

    • 다단계 조인은 사용자 인터페이스와 EventService.UDMSearch API에서 지원되지만 SearchService.UDMSearch API에서는 지원되지 않습니다. 조인이 없는 다단계 쿼리도 사용자 인터페이스에서 지원됩니다.

이벤트 및 전역 제한사항

최대 이벤트 수:

다단계 쿼리는 동시에 처리할 수 있는 이벤트 수가 엄격하게 제한됩니다.

  • UDM 이벤트: 최대 2개의 UDM 이벤트가 허용됩니다.

  • 엔티티 컨텍스트 그래프 (ECG) 이벤트: ECG 이벤트는 최대 1개까지 허용됩니다.

전역 쿼리 제한사항:

이러한 제한은 다단계 쿼리가 반환할 수 있는 데이터의 기간과 양을 제어하는 플랫폼 전체 제약 조건입니다.

  • 쿼리 기간의 경우 표준 쿼리의 최대 기간은 30일입니다.

  • 최대 총 결과 집합 크기는 10,000개입니다.

다단계 쿼리 예시

이 섹션의 예는 완전한 다단계 YARA-L 쿼리를 만드는 방법을 보여줍니다.

예: 비정상적으로 활성 상태인 네트워크 연결 검색 (시간)

이 다단계 YARA-L 예시는 정상보다 높은 네트워크 활동이 있는 IP 주소 쌍을 식별하여 3시간 이상 높은 활동을 유지하는 쌍을 타겟팅합니다. 쿼리에는 이름이 지정된 단계(hourly_stats)와 root 단계라는 두 가지 필수 구성요소가 포함됩니다.

hourly_stats 단계에서는 네트워크 활동 수준이 높은 principal.iptarget.ip 쌍을 검색합니다.

이 단계는 다음 필드에 대해 시간별 단일 값을 반환합니다.

  • 소스 IP 통계 (문자열): $hourly_stats.src_ip

  • 대상 IP 통계 (문자열): $hourly_stats.dst_ip

  • 이벤트 수 (정수) 통계: $hourly_stats.count

  • 표준 편차 수신 바이트 (부동 소수점): $hourly_stats.std_recd_bytes

  • 평균 수신 바이트 (부동 소수점): $hourly_stats.avg_recd_bytes

  • 시간 버킷 시작 시간 (초 단위, 유닉스 시간 기준, 정수): $hourly_stats.window_start

  • 시간 버킷 종료 시간 (초 단위, 유닉스 시간 기준, 정수): $hourly_stats.window_end

루트 단계는 hourly_stats 단계의 출력을 처리합니다. $hourly_stats로 지정된 기준점을 초과하는 활동이 있는 principal.iptarget.ip 쌍의 통계를 계산합니다. 그런 다음 활동이 많은 시간이 3시간을 초과하는 쌍을 필터링합니다.


stage hourly_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $src_ip = principal.ip
  $dst_ip = target.ip
  $src_ip != ""
  $dst_ip != ""

  match:
    $src_ip, $dst_ip by hour

  outcome:
    $count = count(metadata.id)
    $avg_recd_bytes = avg(network.received_bytes)
    $std_recd_bytes = stddev(network.received_bytes)

  condition:
    $avg_recd_bytes > 100 and $std_recd_bytes > 50
}

$src_ip = $hourly_stats.src_ip
$dst_ip = $hourly_stats.dst_ip
$time_bucket_count = strings.concat(timestamp.get_timestamp($hourly_stats.window_start), "|", $hourly_stats.count)

match:
 $src_ip, $dst_ip

outcome:
 $list = array_distinct($time_bucket_count)
 $count = count_distinct($hourly_stats.window_start)

condition:
 $count > 3

루트 단계에서 다음과 같이 일치 조건을 변경하면 다단계 쿼리에 대해 일별 윈도우 집계를 도입할 수 있습니다.

match:
 $src_ip, $dst_ip by day

예: 비정상적으로 활성 상태인 네트워크 연결 검색 (Z 점수 사용)

이 다단계 쿼리는 Z 점수 계산 (평균에서 벗어난 표준 편차 수 측정)을 사용하여 일일 평균 네트워크 활동을 오늘의 활동과 비교합니다. 이 쿼리는 내부 애셋과 외부 시스템 간의 비정상적으로 높은 네트워크 활동을 효과적으로 검색합니다.

필수사항: 계산된 Z 점수가 유효하려면 쿼리 기간이 2일 이상이어야 하며 당일이 포함되어야 합니다.

이 다단계 쿼리에는 daily_stats 단계와 root 단계가 포함되어 있으며, 이 두 단계는 함께 작동하여 네트워크 활동의 Z 점수를 계산합니다.

  • daily_stats 단계에서는 초기 일일 집계를 실행합니다. 각 IP 쌍 (sourcetarget)에 대해 매일 교환된 총 바이트를 계산하고 다음 단계 필드 (출력 행의 열에 해당)를 반환합니다.

    • $daily_stats.source: 단수, 문자열
    • $daily_stats.target: 단수, 문자열
    • $daily_stats.exchanged_bytes: 단수, 정수
    • $daily_stats.window_start: 단수, 정수
    • $daily_stats.window_end: 단수, 정수
  • 루트 단계에서는 각 IP 쌍의 daily_stats 단계 출력을 집계합니다. 전체 검색 범위에서 교환된 일일 바이트의 평균과 표준 편차를 오늘 교환된 바이트와 함께 계산합니다. 이러한 세 가지 계산된 값을 사용하여 Z-점수를 결정합니다.

  • 출력에는 오늘 모든 IP 쌍의 Z 점수가 내림차순으로 정렬되어 나열됩니다.

// Calculate the total bytes exchanged per day by source and target

stage daily_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $source = principal.hostname
  $target = target.ip
  $source != ""
  $target != ""
  $total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)
  match:
    $source, $target by day
  outcome:
    $exchanged_bytes = sum($total_bytes)
}

// Calculate the average per day over the time window and compare with the bytes
   exchanged today

$source = $daily_stats.source
$target = $daily_stats.target
$date = timestamp.get_date($daily_stats.window_start)

match:
  $source, $target

outcome:
  $today_bytes = sum(if($date = timestamp.get_date(timestamp.current_seconds()), $daily_stats.exchanged_bytes, 0))
  $average_bytes = window.avg($daily_stats.exchanged_bytes)
  $stddev_bytes = window.stddev($daily_stats.exchanged_bytes)
  $zscore = ($today_bytes - $average_bytes) / $stddev_bytes

order:
  $zscore desc

단계에서 집계되지 않은 변수 내보내기

이름이 지정된 단계에는 집계되지 않은 outcome 섹션이 포함될 수 있습니다. 즉, 해당 outcome 섹션 내에 정의된 변수는 스테이지에서 직접 출력되므로 후속 스테이지에서 그룹화된 집계 없이 스테이지 필드로 액세스할 수 있습니다.

예: 집계되지 않은 변수 내보내기

이 예에서는 집계되지 않은 변수를 내보내는 방법을 보여줍니다. 다음 로직을 참고하세요.

  • top_5_bytes_sent 단계에서는 네트워크 활동이 가장 많은 5개의 이벤트를 검색합니다.

  • top_5_bytes_sent 단계는 출력 행의 열에 해당하는 다음 단계 필드를 출력합니다.

    • $top_5_bytes_sent.bytes_sent: 단수, 정수
    • $top_5_bytes_sent.timestamp_seconds: 단수, 정수
  • root 단계에서는 네트워크 활동이 가장 많은 5개 이벤트의 최신 타임스탬프와 가장 이른 타임스탬프를 계산합니다.

stage top_5_bytes_sent {
  metadata.event_type = "NETWORK_CONNECTION"
  network.sent_bytes > 0

  outcome:
    $bytes_sent = cast.as_int(network.sent_bytes)
    $timestamp_seconds = metadata.event_timestamp.seconds

  order:
    $bytes_sent desc 
  
  limit:
    5
}

outcome:
  $latest_timestamp = timestamp.get_timestamp(max($top_5_bytes_sent.timestamp_seconds))
  $earliest_timestamp = timestamp.get_timestamp(min($top_5_bytes_sent.timestamp_seconds))

다단계 쿼리에서 윈도우화 구현

다단계 쿼리는 명명된 단계에서 모든 유형의 윈도우 (홉, 슬라이딩, 텀블링)를 지원합니다. 명명된 단계에 윈도우가 포함된 경우 각 출력 행의 윈도우 시작 및 윈도우 종료는 다음 예약된 필드를 사용하여 액세스할 수 있습니다.

  • $<stage name>.window_start
  • $<stage name>.window_end

예: 홉 윈도우

다음 예는 다단계 쿼리에서 홉 윈도우를 사용하는 방법을 보여줍니다.

  • hourly_stats 단계에서는 동일한 시간 내에 네트워크 활동이 많은 IP 쌍을 검색합니다.

  • hourly_stats는 출력 행의 열에 해당하는 다음 단계 필드를 출력합니다.

    • $hourly_stats.src_ip: 단수, 문자열
    • $hourly_stats.dst_ip: 단수, 문자열
    • $hourly_stats.count: 단수, 정수
    • $hourly_stats.std_recd_bytes: 단수, 부동 소수점
    • $hourly_stats.avg_recd_bytes: 단수, 부동 소수점
    • $hourly_stats.window_start: 단수, 정수
    • $hourly_stats.window_end: 단수, 정수
  • 루트 단계에서는 활동이 많은 시간이 3시간을 초과하는 IP 쌍을 필터링합니다. hourly_stats 단계에서 홉 윈도우를 사용하면 시간이 겹칠 수 있습니다.

stage hourly_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $src_ip = principal.ip
  $dst_ip = target.ip
  $src_ip != ""
  $dst_ip != ""

  match:
    $src_ip, $dst_ip over 1h

  outcome:
    $count = count(metadata.id)
    $avg_recd_bytes = avg(network.received_bytes)
    $std_recd_bytes = stddev(network.received_bytes)

  condition:
    $avg_recd_bytes > 100 and $std_recd_bytes > 50
}

$src_ip = $hourly_stats.src_ip
$dst_ip = $hourly_stats.dst_ip
$time_bucket_count = strings.concat(timestamp.get_timestamp($hourly_stats.window_start), "|", $hourly_stats.count)

match:
 $src_ip, $dst_ip

outcome:
 $list = array_distinct($time_bucket_count)
 $count = count_distinct($hourly_stats.window_start)

condition:
 $count > 3

알려진 문제

다단계 쿼리를 구현할 때는 다음 제한사항과 권장되는 해결 방법을 검토하는 것이 좋습니다.

  • 모든 다단계 쿼리는 통계 검색 쿼리와 같이 작동합니다 (출력은 집계되지 않은 이벤트 또는 데이터 테이블 행이 아닌 집계된 통계로 구성됨).

  • 한쪽의 UDM 및 항목 이벤트와의 조인 성능은 해당 데이터 세트의 크기로 인해 성능이 저하될 수 있습니다. 조인의 UDM 및 항목 이벤트를 최대한 많이 필터링하는 것이 좋습니다 (예: 이벤트 유형으로 필터링).

권장사항에 관한 일반적인 안내는 Yara-L 권장사항을 참고하고, 조인 관련 정보는 권장사항을 참고하세요.

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