YARA-L 2.0 언어 구문
이 섹션에서는 YARA-L 구문의 주요 요소들에 대해 설명합니다. YARA-L 2.0 언어 개요도 참조하세요.
규칙 구조
YARA-L 2.0의 경우 변수 선언, 정의, 사용을 다음 순서로 지정해야 합니다.
- meta
- events
- match(선택사항)
- outcome(선택사항)
- condition
- options(선택사항)
다음은 규칙의 일반적인 구조를 보여줍니다.
rule <rule Name>
{
meta:
// Stores arbitrary key-value pairs of rule details, such as who wrote
// it, what it detects on, version control, etc.
events:
// Conditions to filter events and the relationship between events.
match:
// Values to return when matches are found.
outcome:
// Additional information extracted from each detection.
condition:
// Condition to check events and the variables used to find matches.
options:
// Options to turn on or off while executing this rule.
}
비고
2개의 슬래시 문자(// comment
)를 사용하여 설명을 지정하거나 C에서와 같이 슬래시와 별표 문자(/* comment */
)를 사용하여 여러 줄에 걸친 설명을 지정할 수 있습니다.
리터럴
음수가 아닌 정수(소수점 제외), 문자열, 부울, 정규식 리터럴이 지원됩니다.
문자열 및 정규식 리터럴
YARA-L 2.0에서는 다음 인용 문자를 사용하여 문자열을 묶을 수 있습니다. 하지만 인용된 텍스트는 사용 대상에 따라 다르게 해석됩니다.
큰따옴표(")—일반 문자열에 사용됩니다. 이스케이프 문자를 포함해야 합니다.
예: 'hello\tworld'—\t가 탭 문자로 해석됩니다.뒤쪽 인용부호(`)—모든 문자를 문자 그대로 해석하기 위해 사용됩니다.
예: `hello\tworld`—\t가 탭 문자로 해석되지 않습니다.
정규 표현식의 경우 두 가지 옵션이 있습니다.
re.regex()
함수 없이 정규 표현식을 직접 사용하려면 정규 표현식 리터럴에 /regex/
를 사용합니다.
re.regex()
함수를 사용할 때 문자열 리터럴을 정규식 리터럴로 사용할 수도 있습니다. 큰따옴표 문자열 리터럴의 경우 어색해보일 수도 있는 백슬래시 문자로 백슬래시 문자를 이스케이프 처리해야 합니다.
예를 들어 다음 정규 표현식은 서로 동일합니다.
re.regex($e.network.email.from, `.*altostrat\.com`)
re.regex($e.network.email.from, ".*altostrat\\.com")
$e.network.email.from = /.*altostrat\.com/
가독성을 위해서는 정규 표현식의 문자열에 뒤쪽 인용부호 문자를 사용하는 것이 좋습니다.
연산자
YARA-L에서는 다음 연산자를 사용할 수 있습니다.
연산자 | 설명 |
= | 같음/선언 |
!= | 같지 않음 |
< | 미만 |
<= | 이하 |
> | 초과 |
>= | 이상 |
변수
YARA-L 2.0에서는 모든 변수가 $<variable name>
으로 표현됩니다.
다음 유형의 변수를 정의할 수 있습니다.
이벤트 변수—정규화된 형태(UDM) 또는 항목 이벤트의 이벤트 그룹을 나타냅니다.
events
섹션에서 이벤트 변수의 조건을 지정합니다. 이름, 이벤트 소스, 이벤트 필드를 사용하여 이벤트 변수를 식별합니다. 허용되는 소스는udm
(정규화된 이벤트) 및graph
(항목 이벤트)입니다. 소스가 생략된 경우udm
이 기본 소스로 설정됩니다. 이벤트 필드는 일련의 .<field name>으로 표현됩니다(예: $e.field1.field2). 일련의 이벤트 필드는 항상 최상위 소스(UDM 또는 Entity)로 시작됩니다.일치 변수—
match
섹션에 선언됩니다. 일치 변수는 쿼리의 그룹화 필드가 됩니다. 여기에서 일치 변수의 각 고유 집합에 대해 그리고 각 기간에 대해 하나의 행이 반환됩니다. 규칙으로 일치 항목이 발견되면 일치 변수 값이 반환됩니다. 각 일치 변수가events
섹션에서 나타내는 대상을 지정하세요.자리표시자 변수—
events
섹션에서 선언되고 정의됩니다. 자리표시자 변수는 일치 변수와 비슷합니다. 하지만condition
섹션에서 자리표시자 변수를 사용하여 일치 조건을 지정할 수 있습니다.
일치 변수 및 자리표시자 변수를 사용하여 전이적 조인 조건을 통해 이벤트 필드 간의 관계를 선언할 수 있습니다. 자세한 내용은 이벤트 섹션 구문을 참조하세요.
Keywords
YARA-L 2.0의 키워드는 대소문자를 구분하지 않습니다. 예를 들어 and
또는 AND
는 동일합니다. 변수 이름이 키워드와 충돌하지 않아야 합니다. 예를 들어 $AND
또는 $outcome
은 잘못되었습니다.
다음은 감지 엔진 규칙의 키워드입니다. rule
, meta
, match
, over
, events
, condition
, outcome
, options
, and
, or
, not
, nocase
, in
, regex
, cidr
, before
, after
, all
, any
, if
, max
, min
, sum
, array
, array_distinct
, count
, count_distinct
지도
구조체 및 라벨
일부 UDM 필드는 구조체 또는 라벨 데이터 유형을 사용합니다.
구조체와 라벨 모두에서 특정 키-값 쌍을 검색하려면 표준 맵 구문을 사용합니다.
// A Struct field.
$e.udm.additional.fields["pod_name"] = "kube-scheduler"
// A Label field.
$e.metadata.ingestion_labels["MetadataKeyDeletion"] = "startup-script"
지원 케이스
이벤트 및 결과 섹션
// Using a Struct field in the events section
events:
$e.udm.additional.fields["pod_name"] = "kube-scheduler"
// Using a Label field in the outcome section
outcome:
$value = array_distinct($e.metadata.ingestion_labels["MetadataKeyDeletion"])
자리표시자에 맵 값 할당
$placeholder = $u1.metadata.ingestion_labels["MetadataKeyDeletion"]
조인 조건에서 맵 필드 사용
// using a Struct field in a join condition between two udm events $u1 and $u2
$u1.metadata.event_type = $u2.udm.additional.fields["pod_name"]
지원되지 않는 케이스
any
또는 all
키워드를 맵에 결합
예를 들어 다음은 현재 지원되지 않습니다.
all $e.udm.additional.fields["pod_name"] = "kube-scheduler"
함수
이 섹션에서는 Chronicle이 Detection Engine에서 지원하는 YARA-L 2.0 함수를 설명합니다.
이러한 함수는 규칙의 다음 영역에서 사용될 수 있습니다.
events
섹션- 결과 섹션의 조건부
BOOL_CLAUSE
문자열 함수
Chronicle은 다음 문자열 조작 함수를 지원합니다.
- strings.concat(a, b)
- strings.coalesce(a, b)
- strings.to_lower(stringText)
- strings.to_upper(stringText)
- strings.base64_decode(encodedString)
다음 섹션에서는 각 함수를 사용하는 방법을 설명합니다.
문자열 또는 정수 값 연결
문자열 2개, 정수 값 2개 또는 이 둘의 조합의 연결을 반환합니다.
strings.concat(a, b)
이 함수는 문자열 또는 정수일 수 있는 2개의 인수를 사용하고 문자열로 연결된 2개의 값을 반환합니다. 정수는 연결 전 문자열로 변환됩니다. 인수는 리터럴 또는 이벤트 필드일 수 있습니다. 두 인수 모두 필드이고 두 속성이 동일한 이벤트에서 온 속성이어야 합니다.
다음 예시에는 문자열 변수와 문자열 리터럴이 인수로 포함됩니다.
"google-test" = strings.concat($e.principal.hostname, "-test")
다음 예시에는 문자열 변수와 정수 값 변수가 인수로 포함되어 있습니다. principal.hostname과 principal.port는 모두 동일한 이벤트 $e에서 생성되며, 연결되어 문자열을 반환합니다.
"google80" = strings.concat($e.principal.hostname, $e.principal.port)
다음 예시에서는 이벤트 $e1의 principal.port와 이벤트 $e2의 principal.hostname을 연결하려고 시도합니다. 인수가 서로 다른 이벤트 변수이므로 컴파일러 오류가 반환됩니다.
// returns a compiler error
"test" = strings.concat($e1.principal.port, $e2.principal.hostname)
문자열 값 병합
빈 문자열로 평가되지 않는 첫 번째 표현식의 값을 반환합니다(예: '0이 아닌 값'). 두 인수 모두 빈 문자열로 평가되면 함수 호출은 빈 문자열을 반환합니다.
strings.coalesce(a, b)
인수는 리터럴, 이벤트 필드 또는 함수 호출일 수 있습니다. 두 인수 모두 STRING 유형이어야 합니다. 두 인수 모두 필드이고 두 속성이 동일한 이벤트에서 온 속성이어야 합니다.
다음 예시에는 문자열 변수와 문자열 리터럴이 인수로 포함됩니다. (1) $e.network.email.from
이 suspicious@gmail.com
이거나 (2) $e.network.email.from
이 비어 있고 $e.network.email.to
가 suspicious@gmail.com
이면 조건이 true로 평가됩니다.
"suspicious@gmail.com" = strings.coalesce($e.network.email.from, $e.network.email.to)
다음 예시에는 중첩된 병합 호출이 포함되어 있습니다. 이 조건은 $e
이벤트에서 null이 아닌 첫 번째 IP 주소를 참조 목록 ip_watchlist
의 값과 비교합니다.
이 호출에서 인수가 병합되는 순서는 규칙 조건에 열거되는 순서와 동일합니다.
$e.principal.ip
가 먼저 평가됩니다.$e.src.ip
가 다음에 평가됩니다.$e.target.ip
가 다음에 평가됩니다.- 마지막으로, 이전 IP 필드가 설정되지 않으면 문자열 'IP 없음'이 기본값으로 반환됩니다.
strings.coalesce(
strings.coalesce($e.principal.ip, $e.src.ip),
strings.coalesce($e.target.ip, "No IP")
) in %ip_watchlist
다음 예시에서는 이벤트 $e1
및 이벤트 $e2
의 principal.hostname
을 병합하려고 시도합니다.
인수가 서로 다른 이벤트 변수이므로 컴파일러 오류가 반환됩니다.
// returns a compiler error
"test" = strings.coalesce($e1.principal.hostname, $e2.principal.hostname)
문자열을 대문자 또는 소문자로 변환
이러한 함수는 모든 문자를 대문자 또는 소문자로 변경한 후 문자열 텍스트를 반환합니다.
- strings.to_lower(stringText)
- strings.to_upper(stringText)
"test@google.com" = strings.to_lower($e.network.email.from)
"TEST@GOOGLE.COM" = strings.to_upper($e.network.email.to)
Base64로 문자열 디코딩
인코딩된 문자열을 base64로 디코딩한 버전이 포함된 문자열을 반환합니다.
strings.base64_decode(encodedString)
이 함수는 하나의 base64 인코딩 문자열을 인수로 사용합니다. encodedString이 올바른 base64 인코딩 문자열이 아니면 함수가 encodedString을 있는 그대로 반환합니다.
이 예시에서는 principal.domain.name이 'test' 문자열의 base64 인코딩인 'dGVzdA=='인 경우 True를 반환합니다.
"test" = strings.base64_decode($e.principal.domain.name)
정규식 함수
Chronicle은 다음 정규 표현식 함수를 지원합니다.
- re.regex(stringText, regex)
- re.capture(stringText, regex)
- re.replace(stringText, replaceRegex, replacementText)
RegExp 일치
다음 구문 중 하나를 사용하여 YARA-L 2.0에서 정규 표현식 일치를 정의할 수 있습니다.
- YARA 구문 사용–이벤트와 관련되어 있습니다.
다음은 이 구문의 일반적인 표현입니다.
$e.field = /regex/
- YARA-L 구문 사용–다음 구문에서 함수로 사용됩니다.
- 정규 표현식이 적용되는 필드입니다.
- 문자열로 지정된 정규 표현식입니다. 문자열 다음에
nocase
한정자를 사용하여 검색 시 대소문자를 무시하도록 지정할 수 있습니다. 다음은 이 구문의 일반적인 표현입니다.re.regex($e.field, `regex`)
YARA-L 2.0에서 정규 표현식을 정의할 때는 다음 사항에 유의하세요.
- 어느 경우에든 제공된 정규 표현식과 일치하는 하위 문자열이 문자열에 포함되어 있으면 조건자가 true입니다. 정규 표현식의 시작 또는 끝 부분에
.*
를 추가하는 것은 불필요합니다. - 정확한 문자열 또는 프리픽스나 서픽스만 일치하는 항목을 찾으려면 정규 표현식에
^
(시작) 및$
(종료) 앵커 문자를 포함하세요. 예를 들어/^full$/
은"full"
과 정확하게 일치하지만,/full/
은"fullest"
,"lawfull"
,"joyfully"
와 일치할 수 있습니다. - UDM 필드에 줄바꿈 문자가 포함된 경우
regexp
는 UDM 필드의 첫 번째 줄만 일치합니다. 전체 UDM 필드 일치를 적용하려면 정규 표현식에(?s)
를 추가합니다. 예를 들어/.*allUDM.*/
을/(?s).*allUDM.*/
로 바꿉니다.
RegExp 캡처
인수에 제공된 정규 표현식 패턴을 사용하여 문자열에서 데이터를 캡처(추출)합니다.
re.capture(stringText, regex)
이 함수에는 두 개의 인수가 사용됩니다.
- stringText: 검색할 원래 문자열입니다.
- regex: 검색할 패턴을 나타내는 정규 표현식입니다.
정규 표현식은 0 또는 1 캡처 그룹을 괄호로 포함할 수 있습니다. 정규 표현식에 0 캡처 그룹이 포함된 경우 함수가 첫 번째 전체 일치 하위 문자열을 반환합니다. 정규 표현식에 1 캡처 그룹이 포함된 경우 캡처 그룹의 첫 번째 일치 하위 문자열을 반환합니다. 캡처 그룹을 2개 이상 정의하면 컴파일 오류가 반환됩니다.
이 예시에서 if $e.principal.hostname에 "aaa1bbaa2"가 포함된 경우에는 함수가 첫 번째 인수를 반환하기 때문에 다음이 True입니다. 이 예시에는 캡처 그룹이 없습니다.
"aaa1" = re.capture($e.principal.hostname, "a+[1-9]")
이 예시에서는 이메일에서 @ 기호 다음에 있는 모든 내용을 캡처합니다. $e.network.email.from 필드가 test@google.com
이면 이 예시는 google.com을 반환합니다. 이 예시에는 캡처 그룹 한 개가 포함되어 있습니다.
"google.com" = re.capture($e.network.email.from , "@(.*)")
정규 표현식이 텍스트의 하위 문자열과 일치하지 않으면 함수는 빈 문자열을 반환합니다. 빈 문자열을 제외하여 일치하는 항목이 없는 이벤트를 생략할 수 있습니다. 이는 re.capture()
를 불일치로 사용하는 경우에 특히 중요합니다.
// Exclude the empty string to omit events where no match occurs.
"" != re.capture($e.network.email.from , "@(.*)")
// Exclude a specific string with an inequality.
"google.com" != re.capture($e.network.email.from , "@(.*)")
RegExp 교체
정규 표현식 교체를 수행합니다.
re.replace(stringText, replaceRegex, replacementText)
이 함수에는 3개의 인수가 있습니다.
- stringText: 원래 문자열입니다.
- replaceRegex: 검색할 패턴을 나타내는 정규 표현식입니다.
- replacementText: 각 일치 항목에 삽입할 텍스트입니다.
원본 stringText에서 파생된 새 문자열을 반환합니다. 여기서 replaceRegex의 패턴과 일치하는 모든 하위 문자열은 replacementText의 값으로 바뀝니다. replacementText 내에 백슬래시로 이스케이프 처리된 숫자(\1 ~ \9)를 사용하여 replaceRegex 패턴에서 괄호로 묶인 해당 그룹과 일치하는 텍스트를 삽입할 수 있습니다. 전체 일치 텍스트를 나타내려면 \0을 사용합니다.
이 함수는 겹치지 않는 일치 항목을 교체하며 발견된 첫 번째 일치 항목을 교체하는 데 우선순위를 둡니다. 예를 들어 re.replace("banana", "ana", "111")는 문자열 'b111na'를 반환합니다.
이 예시에서는 이메일에서 @
기호 다음에 있는 모든 것을 캡처하고 com
을 org
로 바꾼 후 해당 결과를 반환합니다. 중첩 함수 사용을 확인하세요.
"email@google.org" = re.replace($e.network.email.from, "com", "org")
이 예시에서는 replacementText 인수에 백슬래시로 이스케이프 처리된 숫자를 사용하여 replaceRegex 패턴과의 일치를 참조합니다.
"test1.com.google" = re.replace(
$e.principal.hostname, // holds "test1.test2.google.com"
"test2\.([a-z]*)\.([a-z]*)",
"\\2.\\1" // \\1 holds "google", \\2 holds "com"
)
빈 문자열과 re.replace()
를 처리할 때는 다음 사항에 유의하세요.
빈 문자열을 replaceRegex
로 사용:
// In the function call below, if $e.principal.hostname contains "name",
// the result is: 1n1a1m1e1, because an empty string is found next to
// every character in `stringText`.
re.replace($e.principal.hostname, "", "1")
빈 문자열을 바꾸려면 "^$"
를 replaceRegex
로 사용:
// In the function call below, if $e.principal.hostname contains the empty
// string, "", the result is: "none".
re.replace($e.principal.hostname, "^$", "none")
날짜 함수
Chronicle은 다음 날짜 관련 함수를 지원합니다.
timestamp.get_minute(unix_seconds [, time_zone])
timestamp.get_hour(unix_seconds [, time_zone])
timestamp.get_day_of_week(unix_seconds [, time_zone])
timestamp.get_week(unix_seconds [, time_zone])
timestamp.current_seconds()
Chronicle은 음의 정수를 unix_seconds 인수로 지원합니다. 음의 정수는 Unix epoch 이전 시간을 나타냅니다. 오버플로를 일으키는 값과 같은 잘못된 정수를 제공하면 함수가 -1을 반환합니다. 이것은 일반적이지 않은 시나리오입니다.
YARA-L 2는 음의 정수 리터럴을 지원하지 않으므로 < 또는 > 연산자를 사용하여 이 조건을 확인해야 합니다. 예를 들면 다음과 같습니다.
0 > timestamp.get_hour(123)
시간 추출
[0, 59] 범위의 정수를 반환합니다.
timestamp.get_minute(unix_seconds [, time_zone])
다음 함수는 하루 시간을 나타내는 [0, 23] 범위의 정수를 반환합니다.
timestamp.get_hour(unix_seconds [, time_zone])
다음 함수는 일요일부터 시작되는 한 주의 요일을 나타내는 [1, 7] 범위의 정수를 반환합니다. 예를 들어 1 = 일요일, 2 = 월요일입니다.
timestamp.get_day_of_week(unix_seconds [, time_zone])
다음 함수는 해당 연도의 주를 나타내는 [0, 53] 범위의 정수를 반환합니다. 주는 일요일부터 시작됩니다. 해당 연도의 첫 번째 일요일 이전의 날짜는 주 0에 포함됩니다.
timestamp.get_week(unix_seconds [, time_zone])
이러한 시간 추출 함수는 동일한 인수를 갖습니다.
- unix_seconds는 Unix epoch를 기준으로 하는 초 수(예:
$e.metadata.event_timestamp.seconds
) 또는 해당 값을 포함하는 자리표시자입니다. - time_zone은 선택사항이고 time_zone을 나타내는 문자열입니다. 생략한 경우 기본값은 'GMT'입니다. 문자열 리터럴을 사용하여 시간대를 지정할 수 있습니다. 옵션은 다음과 같습니다.
- TZ 데이터베이스 이름, 예: 'America/Los_Angeles'. 자세한 내용은 이 페이지의 'TZ 데이터베이스 이름' 열을 참조하세요.
- UTC의 시간대 오프셋(
(+|-)H[H][:M[M]]
형식)입니다(예: '-08:00').
이 예시에서는 time_zone 인수가 생략되었으므로 기본적으로 'GMT'로 지정됩니다.
$ts = $e.metadata.collected_timestamp.seconds
timestamp.get_hour($ts) = 15
이 예시에서는 문자열 리터럴을 사용하여 time_zone을 정의합니다.
$ts = $e.metadata.collected_timestamp.seconds
2 = timestamp.get_day_of_week($ts, "America/Los_Angeles")
다음은 시간 추출 함수에 두 번째 인수로 전달할 수 있는 다른 올바른 time_zone 지정자 예시입니다.
"America/Los_Angeles"
또는"-08:00"
. ("PST"
는 지원되지 않음)"America/New_York"
또는"-05:00"
. ("EST"
는 지원되지 않음)"Europe/London"
"UTC"
"GMT"
현재 타임스탬프
Unix 초로 현재 시간을 나타내는 정수를 반환합니다. 발견 항목 타임스탬프와 대략적으로 동일하고 규칙이 실행된 시간을 기반으로 합니다.
timestamp.current_seconds()
다음 예시에서는 인증서가 24시간을 초과하여 만료된 경우 True를 반환합니다. 현재 Unix 초를 빼고 크거나 같음 연산자를 사용하여 비교하는 방식으로 시간 차이를 계산합니다.
86400 < timestamp.current_seconds() - $e.network.tls.certificate.not_after
수학 함수
절댓값
정수 표현식의 절댓값을 반환합니다.
math.abs(intExpression)
이 예시는 지정된 시간에서 5분을 초과하는 경우(초 단위, Unix 에포크 기준) 이벤트가 지정된 시간 이전 또는 이후에 발생했는지 여부에 관계없이 true를 반환합니다. math.abs
호출은 여러 변수 또는 자리표시자에 종속될 수 없습니다. 예를 들어 아래 예시에서 1643687343
의 하드코딩된 시간 값을 $e2.metadata.event_timestamp.seconds
로 바꿀 수 없습니다.
300 < math.abs($e1.metadata.event_timestamp.seconds - 1643687343)
Net 함수
IP 서브네트워크 검색
제공된 IP 주소가 지정된 서브네트워크 내에 있으면 true를 반환합니다.
net.ip_in_range_cidr(ipAddress, subnetworkRange)
YARA-L을 사용하면 net.ip_in_range_cidr()
문을 사용하여 서브네트워크 내에서 모든 IP 주소로 UDM 이벤트를 검색할 수 있습니다. IPv4 및 IPv6 모두 지원됩니다.
IP 주소 범위로 검색하려면 IP UDM 필드 및 클래스 없는 도메인 간 라우팅(CIDR) 범위를 지정합니다. YARA-L은 단일 및 반복되는 IP 주소 필드를 모두 처리할 수 있습니다.
IPv4 예시:
net.ip_in_range_cidr($e.principal.ip, "192.0.2.0/24")
IPv6 예시:
net.ip_in_range_cidr($e.network.dhcp.yiaddr, "2001:db8::/32")
net.ip_in_range_cidr()
문을 사용하는 예시 규칙은 IP 주소 범위 내의 단일 이벤트 예시 규칙을 참조하세요.
배열 함수
배열 길이
반복 필드 요소의 수를 반환합니다.
arrays.length($e.principal.ip) = 2
경로를 따라 반복 필드가 여러 개 있으면 반복 필드 요소의 총 개수를 반환합니다.
arrays.length($e.intermediary.ip) = 3
자리표시자 할당 함수
events
섹션의 함수 호출 결과를 자리표시자에 할당할 수 있습니다. 예를 들면 다음과 같습니다.
$placeholder = strings.concat($e.principal.hostname, "my-string").
그런 다음 match
, condition
, outcome
섹션에서 자리표시자 변수를 사용할 수 있습니다.
그러나 자리표시자 할당 함수에는 두 가지 제한사항이 있습니다.
자리표시자 할당 함수의 모든 자리표시자는 이벤트 필드가 포함된 표현식에 할당해야 합니다. 예를 들어 다음은 유효한 예시입니다.
$ph1 = $e.principal.hostname $ph2 = $e.src.hostname // Both $ph1 and $ph2 have been assigned to an expression containing an event field. $ph1 = strings.concat($ph2, ".com")
$ph1 = $e.network.email.from $ph2 = strings.concat($e.principal.hostname, "@gmail.com") // Both $ph1 and $ph2 have been assigned to an expression containing an event field. $ph1 = strings.to_lower($ph2)
그러나 아래 예시는 유효하지 않습니다.
$ph1 = strings.concat($e.principal.hostname, "foo") $ph2 = strings.concat($ph1, "bar") // $ph2 has NOT been assigned to an expression containing an event field.
함수 호출은 단 하나의 이벤트에 의존해야 합니다. 그러나 동일한 이벤트의 두 개 이상의 필드를 함수 호출 인수에 사용할 수 있습니다. 예를 들어 다음은 유효합니다.
$ph = strings.concat($event.principal.hostname, "string2")
$ph = strings.concat($event.principal.hostname, $event.src.hostname)
하지만 다음은 유효하지 않습니다.
$ph = strings.concat("string1", "string2")
$ph = strings.concat($event.principal.hostname, $anotherEvent.src.hostname)
참조 목록 구문
참조 목록 동작 및 참조 목록 구문에 대한 자세한 내용은 참조 목록 페이지를 참조하세요.
events
또는 outcome
섹션에서 참조 목록을 사용할 수 있습니다. 다음은 규칙에 다양한 유형의 참조 목록을 사용하기 위한 구문입니다.
// STRING reference list
$e.principal.hostname in %string_reference_list
// REGEX reference list
$e.principal.hostname in regex %regex_reference_list
// CIDR reference list
$e.principal.ip in cidr %cidr_reference_list
아래와 같이 not
연산자와 nocase
연산자를 참조 목록과 함께 사용할 수도 있습니다.
nocase
연산자는 STRING 목록 및 REGEX 목록과 호환됩니다.
// Exclude events whose hostnames match substrings in my_regex_list.
not $e.principal.hostname in regex %my_regex_list
// Event hostnames must match at least 1 string in my_string_list (case insensitive).
$e.principal.hostname in %my_string_list nocase
성능상의 이유로 Detection Engine은 참조 목록 사용을 제한합니다.
- 특수 연산자 유무에 관계없이 규칙의 최대
in
문: 7개 regex
연산자가 있는 최대in
문: 4개cidr
연산자가 있는 최대in
문: 2개
메타 섹션 구문
메타 섹션은 각 줄이 키-값 쌍을 정의하는 여러 줄로 구성됩니다. 키 부분은 인용 부호가 없는 문자열이어야 하고 값 부분은 인용 부호가 있는 문자열이어야 합니다.
<key> = "<value>"
다음은 올바른 meta
섹션 줄의 예시입니다.
meta:
author = "Chronicle"
severity = "HIGH"
이벤트 섹션 구문
events
섹션에서 조건자를 나열하여 다음을 지정합니다.
- 각 일치 또는 자리표시자 변수가 나타내는 대상
- 조건부 단순 바이너리 표현식
- 조건부 함수 표현식
- 조건부 참조 목록 표현식
- 논리 연산자
변수 선언
변수 선언의 경우 다음 구문을 사용합니다.
<EVENT_FIELD> = <VAR>
<VAR> = <EVENT_FIELD>
다음 예시에 표시된 것처럼 두 항목은 서로 동일합니다.
$e.source.hostname = $hostname
$userid = $e.principal.user.userid
이 선언에서 이 변수는 이벤트 변수에 대해 지정된 필드를 나타냅니다. 이벤트 필드가 반복되는 필드이면 일치 변수가 해당 배열의 임의 값을 나타낼 수 있습니다. 또한 단일 일치 또는 자리표시자 변수에 여러 이벤트 필드를 지정할 수 있습니다. 이것은 전이적 조인 조건입니다.
예를 들면 다음과 같습니다.
$e1.source.ip = $ip
$e2.target.ip = $ip
위 구문은 아래 구문과 동일합니다.
$e1.source.ip = $ip
$e1.source.ip = $e2.target.ip
변수가 사용된 경우 변수 선언을 통해 변수를 선언해야 합니다. 선언 없이 변수가 사용된 경우 컴파일 오류로 간주됩니다.
조건부 단순 바이너리 표현식
조건으로 사용할 단순 바이너리 표현식의 경우 다음 구문을 사용합니다.
<EXPR> <OP> <EXPR>
표현식은 이벤트 필드, 변수, 리터럴, 함수 표현식일 수 있습니다.
예를 들면 다음과 같습니다.
$e.source.hostname = "host1234"
$e.source.port < 1024
1024 < $e.source.port
$e1.source.hostname != $e2.target.hostname
$e1.metadata.collected_timestamp.seconds > $e2.metadata.collected_timestamp.seconds
$port >= 25
$host = $e2.target.hostname
"google-test" = strings.concat($e.principal.hostname, "-test")
"email@google.org" = re.replace($e.network.email.from, "com", "org")
양쪽 모두 리터럴이면 컴파일 오류로 간주됩니다.
조건부 함수 표현식
일부 함수는 events
섹션에서 개별 조건자로 사용될 수 있는 부울 값을 반환합니다. 이러한 함수는 다음과 같습니다.
re.regex()
net.ip_in_range_cidr()
예를 들면 다음과 같습니다.
re.regex($e.principal.hostname, `.*\.google\.com`)
net.ip_in_range_cidr($e.principal.ip, "192.0.2.0/24")
조건부 참조 목록 표현식
이벤트 섹션에서 참조 목록을 사용할 수 있습니다. 자세한 내용은 참조 목록 섹션을 참조하세요.
논리 연산자
다음 예시에 표시된 것처럼 events
섹션에서 논리적 and
및 논리적 or
연산자를 사용할 수 있습니다.
$e.metadata.event_type = "NETWORK_DNS" or $e.metadata.event_type = "NETWORK_DHCP"
($e.metadata.event_type = "NETWORK_DNS" and $e.principal.ip = "192.0.2.12") or ($e.metadata.event_type = "NETWORK_DHCP" and $e.principal.mac = "AB:CD:01:10:EF:22")
not $e.metadata.event_type = "NETWORK_DNS"
기본적으로 우선순위(가장 높은 것에서 가장 낮은 순)는 not
, and
, or
입니다.
예를 들어 "a or b and c"
는 "a or (b and c)"
와 동일합니다. 필요에 따라 괄호를 사용하여 우선순위를 변경할 수 있습니다.
events
섹션에서 모든 조건자는 기본적으로 함께 and
로 연결된 것으로 간주됩니다.
이벤트 연산자
열거형 유형의 연산자를 사용할 수 있습니다. 규칙에 적용하여 성능을 단순화하고 최적화(참조 목록 대신 연산자 사용)할 수 있습니다.
다음 예시에서 USER_UNCATEGORIZED' 및 'USER_RESOURCE_DELETION'은 15000와 15014에 해당하므로 규칙은 나열된 모든 이벤트를 찾습니다.
$e.metadata.event_type >= "USER_CATEGORIZED" and $e.metadata.event_type <= "USER_RESOURCE_DELETION"
이벤트 목록
- USER_RESOURCE_DELETION
- USER_RESOURCE_UPDATE_CONTENT
- USER_RESOURCE_UPDATE_PERMISSIONS
- USER_STATS
- USER_UNCATEGORIZED
특수키
nocase
문자열 값 또는 정규 표현식 사이에 비교 표현식이 있으면 대소문자 표현을 무시하기 위해 표현식 끝에 nocase를 추가할 수 있습니다.
$e.principal.hostname != "http-server" nocase
$e1.principal.hostname = $e2.target.hostname nocase
$e.principal.hostname = /dns-server-[0-9]+/ nocase
re.regex($e.target.hostname, `client-[0-9]+`) nocase
필드 유형이 열거된 값인 경우에는 사용할 수 없습니다. 아래 예시는 잘못된 예시이고 컴파일 오류를 일으킵니다.
$e.metadata.event_type = "NETWORK_DNS" nocase
$e.network.ip_protocol = "TCP" nocase
반복 필드
any, all
UDM 및 Entity에서 일부 필드는 반복 필드로 레이블이 지정되어 값 또는 다른 메시지 유형의 목록임을 나타냅니다.
YARA-L에서 반복 필드의 각 요소는 개별적으로 취급됩니다. 즉, 반복 필드가 규칙에 사용되었으면 필드의 각 요소에 대해 이 규칙을 평가합니다.
이로 인해 예기치 않은 동작이 발생할 수 있습니다. 예를 들어 규칙의 events
섹션에 $e.principal.ip = "1.2.3.4"
및 $e.principal.ip = "5.6.7.8"
이 모두 있으면 "1.2.3.4"
및 "5.6.7.8"
이 principal.ip
에 둘 다 있더라도 규칙이 어떠한 일치도 생성하지 않습니다.
전체적으로 반복 필드를 평가하려면 any
및 all
연산자를 사용할 수 있습니다. any
가 사용된 경우에는 반복 필드의 값이 조건을 충족할 때 조건자가 true로 평가됩니다.
all
이 사용된 경우에는 반복된 필드의 모든 값이 조건을 충족할 때 조건자가 true로 평가됩니다.
any $e.target.ip = "127.0.0.1"
all $e.target.ip != "127.0.0.1"
re.regex(any $e.about.hostname, `server-[0-9]+`)
net.ip_in_range_cidr(all $e.principal.ip, "10.0.0.0/8")
any
및 all
연산자는 반복 필드에만 사용할 수 있습니다. 또한 반복 필드를 자리표시자 변수에 할당하거나 다른 이벤트의 필드와 조인할 때는 사용할 수 없습니다.
예를 들어 any $e.principal.ip = $ip
및 any $e1.principal.ip = $e2.principal.ip
는 유효한 구문이 아닙니다. 반복 필드를 일치시키거나 조인하려면 $e.principal.ip = $ip
를 사용합니다. 반복 필드의 요소마다 일치 변수 값이나 조인이 하나씩 있습니다.
any
또는 all
을 사용하여 조건을 작성할 때 not
을 사용하여 조건을 부정하는 것은 부정 연산자를 사용하는 것과 의미가 동일하지 않을 수 있습니다.
예를 들면 다음과 같습니다.
not all $e.principal.ip = "192.168.12.16"
은 일부 IP 주소가"192.168.12.16"
과 일치하지 않는지 확인합니다. 즉, 규칙은"192.168.12.16"
과 일치하지 않는 IP가 있는지 확인합니다.all $e.principal.ip != "192.168.12.16"
은 모든 IP 주소가"192.168.12.16"
과 일치하지 않는지 확인합니다. 즉, 규칙은 어떤 IP 주소도"192.168.12.16"
과 일치하는 않는 것을 확인합니다.
배열 색인 생성
반복 필드에서 배열 색인 생성을 수행할 수 있습니다. n번째 반복 필드 요소에 액세스하려면 표준 목록 구문(요소 색인이 0부터 생성됨)을 사용합니다. 범위를 벗어난 요소는 기본값을 반환합니다.
$e.principal.ip[0] = "192.168.12.16"
$e.principal.ip[999] = ""
요소가 1,000개 미만이면true
를 반환합니다.
색인은 음수가 아닌 정수 리터럴이어야 합니다. int 유형의 값(예: int로 설정된 자리표시자)은 계산되지 않습니다. 배열 색인 생성은 any/all과 결합할 수 없습니다. 배열 색인 생성은 map 구문과 결합할 수 없습니다. 필드 경로에 반복 필드가 여러 개 있으면 모든 반복 필드가 배열 색인 생성을 사용해야 합니다.
다음은 잘못된 구문의 모든 예시입니다.
- intermediary가 반복 필드이고 배열 색인 생성을 사용하려고 시도하고 있기 때문에
$e.intermediary.ip[0]
가 잘못되었습니다. -1
이 양수 정수가 아니기 때문에$e.principal.ip[-1]
가 잘못되었습니다.- any/all은 배열 색인과 결합할 수 없기 때문에
any $e.intermediary.ip[0]
가 잘못되었습니다. - 배열 색인 생성은 map 구문과 결합할 수 없기 때문에
$e.additional.fields[0]["key"]
가 잘못되었습니다.
이벤트 변수 조인 요구사항
규칙에서 사용되는 모든 이벤트 변수는 다음 방법 중 하나로 다른 모든 이벤트 변수와 조인해야 합니다.
조인된 두 이벤트 변수(예:
$e1.field = $e2.field
)의 이벤트 필드 간에 동등 비교를 통해 직접 확인할 수 있습니다. 표현식에 산술 또는 함수 호출을 포함해서는 안 됩니다.이벤트 필드만 포함된 전이적 조인을 통해 간접적으로 확인할 수 있습니다('전이적 조인'의 정의는 변수 선언 참조). 표현식에 산술 또는 함수 호출을 포함해서는 안 됩니다.
예를 들어 $e1, $e2 및 $e3이 규칙에 사용된다고 가정하면 다음 events
섹션이 유효합니다.
events:
$e1.principal.hostname = $e2.src.hostname // $e1 joins with $e2
$e2.principal.ip = $e3.src.ip // $e2 joins with $e3
events:
// all of $e1, $e2 and $e3 are transitively joined via the placeholder variable $ip
$e1.src.ip = $ip
$e2.target.ip = $ip
$e3.about.ip = $ip
events:
$e1.principal.hostname = $e2.src.hostname // $e1 joins with $e2
// Function to event comparison is not a valid join condition for $e1 and $e2,
// but the whole events section is valid because we have a valid join condition in the first line.
re.capture($e1.src.hostname, ".*") = $e2.target.hostname
하지만 다음은 잘못된 events
섹션의 예입니다.
events:
// Event to function comparison is an invalid join condition for $e1 and $e2.
$e1.principal.hostname = re.capture($e2.principal.application, ".*")
events:
// Event to arithmetic comparison is an invalid join condition for $e1 and $e2.
$e1.principal.port = $e2.src.port + 1
events:
$e1.src.ip = $ip
$e2.target.ip = $ip
$e3.about.ip = "192.1.2.0" //$e3 is not joined with $e1 or $e2.
events:
$e1.src.ip = $ip
// Function to placeholder comparison is an invalid transitive join condition.
re.capture($e2.target.ip, ".*") = $ip
events:
$e1.src.port = $port
// Arithmetic to placeholder comparison is an invalid transitive join condition.
$e2.principal.port + 800 = $port
일치 섹션 구문
match
섹션에서 일치 조건을 확인하기 전 그룹 이벤트에 대해 일치 변수를 나열합니다. 이러한 필드는 각 일치 항목과 함께 반환됩니다.
- 각 일치 변수가
events
섹션에서 나타내는 대상을 지정하세요. over
키워드 다음에 이벤트와 상관시키기 위해 사용할 시간 범위를 지정합니다. 시간 범위 바깥의 이벤트는 무시됩니다.<number><m/h/d>
구문을 사용하여 시간 범위를 지정합니다.여기서
m/h/d
는 각각 분, 시간, 일을 나타냅니다.지정할 수 있는 최소 시간은 1분입니다.
지정할 수 있는 최대 시간은 48시간입니다.
다음은 올바른 match
예시입니다.
$var1, $var2 over 5m
이 문은 규칙으로 일치 항목이 발견될 때 $var1
및 $var2
(events
섹션에 정의됨)를 반환합니다. 지정된 시간은 5분입니다. 서로 5분 이상 떨어진 이벤트는 상관되지 않으며, 따라서 규칙에서 무시됩니다.
올바른 match
예시는 다음과 같습니다.
$user over 1h
이 문은 규칙으로 일치 항목이 발견되었을 때 $user
를 반환합니다. 지정된 시간은 1시간입니다. 서로 1시간 이상 떨어진 이벤트는 상관되지 않습니다. 이러한 이벤트는 규칙에서 발견 항목으로 고려되지 않습니다.
올바른 match
예시는 다음과 같습니다.
$source_ip, $target_ip, $hostname over 2m
이 문은 규칙으로 일치 항목이 발견될 때 $source_ip
, $target_ip
, $hostname
을 반환합니다. 지정된 시간은 2분입니다. 서로 2시간 이상 떨어진 이벤트는 상관되지 않습니다. 이러한 이벤트는 규칙에서 발견 항목으로 고려되지 않습니다.
다음 예시에서는 잘못된 match
섹션을 보여줍니다.
var1, var2 over 5m // invalid variable name
$user 1h // missing keyword
슬라이딩 기간
기본적으로 YARA-L 2.0 규칙은 홉 창을 사용하여 평가됩니다. 엔터프라이즈 이벤트 데이터의 시간 범위는 겹치는 홉 창 집합으로 분할됩니다. 각 창에는 match
섹션에 지정된 기간이 포함됩니다. 그런 후 각 홉 창 내의 이벤트에 대해 상관관계가 지정됩니다. 홉 창에서는 e1
이 e2
이후 최대 2분 뒤에 발생하는 등 특정 순서로 발생하는 이벤트를 검색하는 것이 가능하지 않습니다. e1
이벤트 발생과 e2
이벤트 발생은 서로 홉 창 기간 내에 있을 때만 상관관계가 지정됩니다.
또한 슬라이딩 기간을 사용하여 규칙을 평가할 수도 있습니다. 슬라이딩 창을 사용하면 match
섹션에 지정된 기간의 슬라이딩 창이 지정된 피벗 이벤트 변수로 시작하거나 종료될 때 생성됩니다. 그런 후 각 슬라이딩 창 내에서 이벤트에 대해 상관관계가 지정됩니다. 이렇게 하면 e1
이 e2
에서 최대 2분 후에 발생하는 등 특정 순서로 발생하는 이벤트를 검색하는 것이 가능하게 됩니다. e1
이벤트 발생과 e2
이벤트 발생은 e2
이벤트 후 슬라이딩 기간 내에 e1
이벤트가 발생할 때 상관관계가 지정됩니다.
다음과 같이 규칙의 match
섹션에 슬라이딩 기간을 지정합니다.
<match-var-1>, <match-var-2>, ... over <duration> before|after <pivot-event-var>
피벗 이벤트 변수는 슬라이딩 기간의 기반이 되는 이벤트 변수입니다. before
키워드를 사용하는 경우 슬라이딩 창이 생성되고 각 피벗 이벤트가 발생하는 것으로 종료됩니다. after
키워드가 사용된 경우 각 피벗 이벤트가 발생하는 것을 시작으로 슬라이딩 기간이 생성됩니다.
다음은 슬라이딩 기간의 올바른 사용 예시입니다.
$var1, $var2 over 5m after $e1
$user over 1h before $e2
결과 섹션 구문
outcome
섹션에서는 최대 20개의 결과 변수를 임의의 이름으로 정의할 수 있습니다. 이러한 결과는 규칙에서 생성한 발견 항목에 저장됩니다. 각 발견 항목은 결과 값이 다를 수 있습니다.
결과 이름 $risk_score
는 특수합니다. 원하는 경우 이 이름으로 결과를 정의할 수 있으며, 만들 경우 이는 정수 유형이어야 합니다. 채워지면 규칙 발견 항목에서 발생하는 알림의 risk_score
가 엔터프라이즈 통계 뷰에 표시됩니다.
규칙의 결과 섹션에 $risk_score
변수를 포함하지 않으면 다음 기본값 중 하나가 설정됩니다.
- 규칙이 알림을 생성하도록 구성된 경우
$risk_score
가 40으로 설정됩니다. - 규칙이 알림을 생성하도록 구성되지 않은 경우
$risk_score
가 15로 설정됩니다.
$risk_score
값은 security_result.risk_score
UDM 필드에 저장됩니다.
결과 변수 데이터 유형
각 결과 변수의 데이터 유형은 다를 수 있으며, 해당 데이터 유형은 이를 계산하는 데 사용되는 식으로 결정됩니다. Google에서 지원하는 결과 데이터 유형은 다음과 같습니다.
- 정수
- 문자열
- 정수 목록
- 문자열 목록
일치 변수가 반복 필드에 있고 이 반복 필드에 중복 요소가 있는 경우 결과를 계산할 때 중복 요소가 여러 번 고려됩니다. 예를 들어 이 경우 sum()
을 사용하는 결과에서 예기치 않은 값이 발생할 수 있지만 max()
를 사용하는 결과에는 영향을 주지 않습니다.
조건부 로직
조건부 로직을 사용하여 결과 값을 계산할 수 있습니다. 조건부는 다음 구문 패턴을 사용하여 지정됩니다.
if(BOOL_CLAUSE, THEN_CLAUSE)
if(BOOL_CLAUSE, THEN_CLAUSE, ELSE_CLAUSE)
'if BOOL_CLAUSE가 true이면 THEN_CLAUSE 반환, 그렇지 않으면 ELSE_CLAUSE 반환'과 같은 조건부 표현식을 읽을 수 있습니다.
BOOL_CLAUSE는 부울 값으로 평가되어야 합니다. BOOL_CLAUSE 표현식은 events
섹션의 표현식과 비슷한 형식입니다. 예를 들어 다음을 포함할 수 있습니다.
비교 연산자가 있는 UDM 필드 이름입니다. 예를 들면 다음과 같습니다.
if($context.graph.entity.user.title = "Vendor", 100, 0)
events
섹션에서 정의된 자리표시자 변수입니다. 예를 들면 다음과 같습니다.if($severity = "HIGH", 100, 0)
부울을 반환하는 함수입니다. 예를 들면 다음과 같습니다.
if(re.regex($e.network.email.from, .*altostrat\.com), 100, 0)
침조 목록을 찾습니다. 예를 들면 다음과 같습니다.
if($u.principal.hostname in %my_reference_list_name, 100, 0)
THEN_CLAUSE 및 ELSE_CLAUSE는 같은 데이터 유형이어야 합니다. 정수 및 문자열은 지원됩니다.
데이터 유형이 정수인 경우 ELSE_CLAUSE를 생략할 수 있습니다. ELSE_CLAUSE가 생략되면 0으로 평가됩니다. 예를 들면 다음과 같습니다.
`if($e.field = "a", 5)` is equivalent to `if($e.field = "a", 5, 0)`
데이터 유형이 문자열인 경우 ELSE_CLAUSE를 제공해야 합니다.
수학적 연산
수학적 연산을 사용하여 규칙의 outcome
및 events
섹션에서 정수 데이터 유형을 계산할 수 있습니다. Chronicle은 계산의 최상위 연산자로 덧셈, 뺄셈, 곱셈, 나눗셈을 지원합니다.
다음 스니펫은 outcome
섹션의 계산 예시입니다.
outcome:
$risk_score = max(100 + if($severity = "HIGH", 10, 5) - if($severity = "LOW", 20, 0))
결과의 자리표시자 변수
결과 변수를 계산할 때 규칙의 이벤트 섹션에 정의된 자리표시자 변수를 사용할 수 있습니다. 이 예시에서는 규칙의 이벤트 섹션에 $email_sent_bytes
가 정의되어 있다고 가정합니다.
단일 이벤트 예시:
// No match section, so this is a single-event rule.
outcome:
// Use placeholder directly as an outcome value.
$my_outcome = $email_sent_bytes
// Use placeholder in a conditional.
$other_outcome = if($file_size > 1024, "SEVERE", "MODERATE")
condition:
$e
멀티 이벤트 예시:
match:
// This is a multi event rule with a match section.
$hostname over 5m
outcome:
// Use placeholder directly in an aggregation function.
$max_email_size = max($email_sent_bytes)
// Use placeholder in a mathematical computation.
$total_bytes_exfiltrated = sum(
1024
+ $email_sent_bytes
+ $file_event.principal.file.size
)
condition:
$email_event and $file_event
집계
결과 섹션은 멀티 이벤트 규칙(일치 섹션이 포함된 규칙) 및 단일 이벤트 규칙(일치 섹션이 포함되지 않은 규칙)에서 사용할 수 있습니다. 집계 요구사항은 다음과 같습니다.
멀티 이벤트 규칙(일치 섹션 포함)
- 결과를 계산하는 표현식은 특정 감지를 생성한 모든 이벤트에 대해 평가됩니다.
- 표현식은 집계 함수로 래핑되어야 합니다.
- 예:
$max_email_size = max($e.network.sent_bytes)
- 표현식에 반복 필드가 포함되어 있는 경우 집계는 반복 필드의 모든 요소에서 감지를 생성한 모든 이벤트에 대해 작동합니다.
- 예:
단일 이벤트 규칙(일치 섹션 없음)
- 결과를 계산하는 표현식은 특정 감지를 생성한 단일 이벤트에 대해 평가됩니다.
- 하나 이상의 반복 필드가 포함된 표현식에 집계 함수를 사용해야 합니다.
- 예:
$suspicious_ips = array($e.principal.ip)
- 집계는 반복된 필드의 모든 요소에서 작동합니다.
- 예:
- 반복된 필드가 포함되지 않은 표현식에는 집계 함수를 사용할 수 없습니다.
- 예:
$threat_status = if($e.principal.file.size > 1024, "SEVERE", "MODERATE")
- 예:
다음 집계 함수를 사용할 수 있습니다.
max()
: 가능한 모든 값의 최댓값을 반환합니다. 정수에서만 작동합니다.min()
: 가능한 모든 값의 최솟값을 반환합니다. 정수에서만 작동합니다.sum()
: 가능한 모든 값의 합계를 반환합니다. 정수에서만 작동합니다.count_distinct()
: 가능한 모든 값을 수집한 후 가능한 값의 고유한 개수를 반환합니다.count()
:count_distinct()
와 동일하게 동작하지만 가능한 값의 고유하지 않은 개수를 반환합니다.array_distinct()
: 가능한 모든 값을 수집한 후 이 값의 목록을 반환합니다. 값 목록은 25개의 임의 요소로 잘립니다.array()
:array_distinct()
와 동일하게 작동하지만 고유하지 않은 값의 목록을 반환합니다. 또한 값 목록은 25개의 임의 요소로 잘립니다.
집계 함수는 여러 이벤트가 존재해야 함을 지정하는 condition
섹션이 규칙에 포함된 경우에 중요합니다. 집계 함수는 발견 항목을 생성한 모든 이벤트에서 작동하기 때문입니다.
예를 들어 outcome
및 condition
섹션에 다음이 포함되어 있다고 가정해 보겠습니다.
outcome:
$asset_id_count = count($event.principal.asset_id)
$asset_id_distinct_count = count_distinct($event.principal.asset_id)
$asset_id_list = array($event.principal.asset_id)
$asset_id_distinct_list = array_distinct($event.principal.asset_id)
condition:
#event > 1
조건 섹션에서는 발견 항목마다 event
가 2개 이상 있어야 하므로 집계 함수는 여러 이벤트에서 작동합니다. 다음 이벤트가 하나의 발견 항목을 생성했다고 가정해 보겠습니다.
event:
// UDM event 1
asset_id="asset-a"
event:
// UDM event 2
asset_id="asset-b"
event:
// UDM event 3
asset_id="asset-b"
그러면 다음과 같은 결과가 반환됩니다.
- $asset_id_count =
3
- $asset_id_distinct_count =
2
- $asset_id_list =
["asset-a", "asset-b", "asset-b"]
` - $asset_id_distinct_list =
["asset-a", "asset-b"]
결과 섹션 사용 시 주의 사항:
기타 참고사항 및 제한사항:
outcome
섹션은events
섹션에 정의되지 않은 새 자리표시자 변수를 참조할 수 없습니다.outcome
섹션은events
섹션에 정의되지 않은 이벤트 변수를 사용할 수 없습니다.- 이벤트 필드가 속한 이벤트 변수가
events
섹션에 이미 정의되어 있으므로outcome
섹션은events
섹션에 사용되지 않은 이벤트 필드를 사용할 수 있습니다. outcome
섹션은events
섹션에서 이미 상관관계가 있는 이벤트 변수만 연결할 수 있습니다. 서로 다른 이벤트 변수의 두 이벤트 필드가 동일하면 상관관계가 발생합니다.
YARA-L 2.0 개요의 결과 섹션을 사용하여 예시를 찾을 수 있습니다. 결과 섹션에서 발견 항목 중복 제거에 대한 자세한 내용은 컨텍스트 인식 분석 만들기를 참조하세요.
조건 섹션 구문
condition
섹션에서 다음을 수행할 수 있습니다.
events
섹션에 정의된 이벤트 및 자리표시자에 대한 일치 조건을 지정합니다. 자세한 내용은 다음 이벤트 및 자리표시자 조건 섹션을 참조하세요.- (선택사항)
outcome
섹션에 정의된 결과 변수를 사용하여 일치 조건을 지정하려면and
키워드를 사용합니다. 자세한 내용은 다음 섹션인 결과 조건부를 참조하세요.
유효한 조건 패턴은 다음과 같습니다.
condition:
<event/placeholder conditionals>
condition:
<event/placeholder conditionals> and <outcome conditionals>
이벤트 및 자리표시자 조건
여기에 and
및 or
키워드와 결합된 이벤트 및 자리표시자 변수의 조건 조건자를 나열합니다.
다음 조건은 경계 조건입니다. 이 조건은 연결된 이벤트 변수를 강제로 존재하게 만듭니다. 즉, 어떤 감지 항목에서든 이벤트가 하나 이상 표시되어야 합니다.
$var // equivalent to #var > 0
#var > n // where n >= 0
#var >= m // where m > 0
다음 조건은 비경계 조건입니다. 여기에서는 연결된 이벤트 변수가 존재하지 않아도 됩니다. 즉, 감지 항목에 이벤트가 표시되지 않아도 됩니다. 이렇게 하면 변수가 존재하는지 대신 변수가 존재하지 않는지를 검색하는 부재 규칙을 만들 수 있습니다.
!$var // equivalent to #var = 0
#var >= 0
#var < n // where n > 0
#var <= m // where m >= 0
이벤트를 항목과 조인한 다음 이벤트의 부재를 확인할 수 있습니다. 다음 의사코드 예시는 events
섹션에서 이벤트 필드 $u.field
와 항목 필드 $e.graph.field
를 조인하고 condition
섹션 !$u and $e
에서 이벤트의 부재를 확인합니다.
events:
$u.field = "value" // $u is an event
$e.graph.field = "value" // $e is an entity
// ...other sections of the rule...
condition:
!$u and $e
항목의 부재는 확인할 수 없습니다. 위 예시를 살펴보면 항목의 부재를 확인하는 $u and !$e
문은 유효하지 않습니다.
다음 예시에서 변수의 특수문자 #
(이벤트 변수 또는 자리표시자 변수)은 고유 이벤트 수 또는 해당 변수의 값을 나타냅니다.
$e and #port > 50 or #event1 > 2 or #event2 > 1 or #event3 > 0
다음 부재 예시도 유효하며, $event1
에서 고유 이벤트가 2개 이상 있고 $event2
에서 고유 이벤트가 0개 있을 때 true로 평가됩니다.
#event1 > 2 and !$event2
비경계 조건이 있을 수 있는 이벤트 또는 자리표시자 변수의 유형에는 제한이 있습니다. 변수는 다음 중 하나여야 합니다.
- UDM 이벤트 변수가 2개 이상 있는 규칙의 UDM 이벤트 변수
- 비경계 조건이 없는 하나 이상의 UDM 이벤트 변수와 연결된 자리표시자 변수
다음은 잘못된 조건자 예시입니다.
$e, #port > 50 // incorrect keyword usage
$e or #port < 50 // or keyword not supported with non-bounding conditions
not $e // not keyword is not allowed for event and placeholder conditions
결과 조건
키워드 and
또는 or
를 조인하거나 또는 키워드 not
앞에 결과 변수에 대한 조건 조건자를 나열합니다.
결과 변수의 유형에 따라 결과 조건을 다르게 지정합니다.
정수:
=, >, >=, <, <=, !=
연산자와 정수 리터럴을 비교합니다. 예를 들면 다음과 같습니다.$risk_score > 10
문자열:
=
또는!=
중 하나와 문자열 리터럴을 비교합니다. 예를 들면 다음과 같습니다.$severity = "HIGH"
정수 또는 배열 목록:
arrays.contains
함수를 사용하여 조건을 지정합니다. 예를 들면 다음과 같습니다.arrays.contains($event_ids, "id_1234")
규칙 분류
일치 섹션이 있는 규칙에서 결과 조건부를 지정하면 규칙이 규칙 할당량에 대해 멀티 이벤트 규칙으로 분류됩니다. 단일 및 여러 이벤트 분류에 대한 자세한 내용은 단일 이벤트 규칙 및 여러 이벤트 규칙을 참조하세요.
카운트(#) 문자
#
문자는 condition
섹션에 사용되는 특수문자입니다. 이벤트 또는 자리표시자 변수 이름 앞에 사용될 경우 모든 events
섹션 조건을 충족시키는 고유 이벤트 또는 값 수를 나타냅니다.
값($) 문자
$
문자는 condition
섹션의 또 다른 특수문자입니다. 결과 변수 이름 앞에 사용되는 경우 해당 결과 값을 나타냅니다.
이벤트 또는 자리표시자 변수 이름 앞에 사용되는 경우(예: $event
) #event > 0
의 약식 표기입니다.
옵션 섹션 구문
options
섹션에서는 규칙에 대한 옵션을 지정할 수 있습니다. options
섹션의 구문은 meta
섹션의 구문과 비슷합니다. 하지만 키가 사전 정의된 옵션 이름 중 하나여야 하고 값이 문자열 유형으로 제한되지 않습니다.
현재까지 사용 가능한 유일한 옵션은 allow_zero_values
입니다.
allow_zero_value
— true로 설정된 경우 규칙으로 생성되는 일치는 일치 변수 값으로 0 값을 가질 수 있습니다. 이벤트 필드가 채워지지 않으면 0 값이 이벤트 필드에 지정됩니다. 이 옵션은 기본적으로 false로 설정됩니다.
다음은 올바른 options
섹션 줄입니다.
allow_zero_values = true
유형 확인
Chronicle은 개발자가 인터페이스 내에 규칙을 만들 때 YARA-L 구문에 대해 유형 확인을 수행합니다. 표시된 유형 확인 오류는 이러한 방법으로 규칙을 수정하여 올바르게 작동하는지 확인하는 데 도움이 됩니다.
다음은 잘못된 조건자 예시입니다.
// $e.target.port is of type integer which cannot be compared to a string.
$e.target.port = "80"
// "LOGIN" is not a valid event_type enum value.
$e.metadata.event_type = "LOGIN"