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)
}
액세스 단계 출력
명명된 단계의 출력은 단계 필드를 사용하여 후속 단계에서 액세스할 수 있습니다. 스테이지 필드는 스테이지의 match
및 outcome
변수에 해당하며 통합 데이터 모델 (UDM) 필드와 유사하게 사용할 수 있습니다.
다음 구문을 사용하여 단계 필드에 액세스합니다.
$<stage name>.<variable name>
액세스 기간 타임스탬프 (선택사항)
명명된 스테이지에서 홉, 슬라이딩 또는 텀블링 윈도우를 사용하는 경우 다음 예약된 필드를 사용하여 각 출력 행의 윈도우 시작 및 윈도우 끝에 액세스합니다.
$<stage name>.window_start
$<stage name>.window_end
window_start
및 window_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.ip
및 target.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.ip
및 target.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 쌍 (source
및target
)에 대해 매일 교환된 총 바이트를 계산하고 다음 단계 필드 (출력 행의 열에 해당)를 반환합니다.$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 전문가로부터 답변을 받으세요.