표현식, 연산자, 기타 구조
이 문서에는 표현식을 사용하여 YARA-L 규칙과 쿼리를 빌드하는 데 도움이 되는 정보가 포함되어 있습니다.
부울 표현식
불리언 표현식은 불리언 유형의 표현식으로, 비교 표현식, 함수 표현식, 참조 목록 또는 데이터 표 표현식이 포함됩니다. YARA-L 규칙 또는 쿼리의 events 및 outcome 섹션에서 불리언 표현식을 사용할 수 있습니다.
비교 표현식
비교 표현식은 두 표현식에 비교 연산자를 적용하는 표현식입니다. 표현식은 이벤트 필드, 변수, 리터럴, 함수 표현식일 수 있습니다.
예: 비교 표현식
$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 또는 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
예: 데이터 테이블의 구문
// STRING data table $e.target.hostname in %data_table_name.column_name // REGEX data table $e.target.hostname in regex %regex_table_name.column_name // CIDR data table $e.principal.ip in cidr %cidr_table_name.column_name
예: 참조 목록 구문에서 not 및 nocase 사용
// 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
nocase 연산자는 STRING 목록 및 REGEX 목록과 호환됩니다.
성능상의 이유로 참조 목록 및 데이터 표 사용에는 다음과 같은 제한사항이 있습니다.
- 특수 연산자가 있거나 없는 쿼리의 최대
in문: 7개 regex연산자가 있는 최대in문: 4개cidr연산자가 있는 최대in문: 2개
논리식
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입니다. 예를 들어 or와 and 연산자가 표현식에 명시적으로 정의된 경우 'a 또는 b 및 c'는 'a 또는 (b 및 c)'로 평가됩니다.
events 섹션에서 연산자가 명시적으로 정의되지 않은 경우 조건자는 and 연산자를 사용하여 결합됩니다. and 연산자가 표현식에 내포된 경우 평가 순서가 다를 수 있습니다.
or이 명시적으로 정의되고 and 연산자가 암시되는 다음 비교 표현식을 고려해 보세요.
$e1.field = "bat" or $e1.field = "baz" $e2.field = "bar"
다음과 같이 해석됩니다.
($e1.field = "bat" or $e1.field = "baz") and ($e2.field = "bar")
or가 명시적으로 정의되어 있으므로 주변 술어가 그룹화되어 먼저 평가됩니다. 마지막 조건자 $e2.field = "bar" and를 사용하여 암시적으로 결합됩니다. 결과는 평가 순서 변경입니다.
열거형 유형
연산자는 열거형 유형과 함께 사용할 수 있습니다. 규칙에 적용하여 성능을 단순화하고 최적화(참조 목록 대신 연산자 사용)할 수 있습니다.
다음 예시에서 USER_UNCATEGORIZED' 및 'USER_RESOURCE_DELETION'은 15000와 15014에 해당하므로 규칙은 나열된 모든 이벤트를 찾습니다.
$e.metadata.event_type >= "USER_CATEGORIZED" and $e.metadata.event_type <= "USER_RESOURCE_DELETION"
Nocase 수정자
문자열 값 또는 정규 표현식 사이의 비교 표현식에서 대소문자를 무시하려면 다음 예와 같이 표현식 끝에 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
필드 유형이 열거된 값인 경우에는 nocase 수정자를 사용할 수 없습니다. 다음 예시는 잘못된 예시이고 컴파일 오류를 일으킵니다.
$e.metadata.event_type = "NETWORK_DNS" nocase
$e.network.ip_protocol = "TCP" nocase
댓글
의견은 쿼리에서 추가 정보를 제공하는 데 사용할 수 있습니다. 슬래시 문자를 사용하여 주석을 나타냅니다.
- 한 줄 주석의 경우 슬래시 문자 두 개 (
// comment)를 사용합니다. - 여러 줄 주석의 경우 슬래시 문자 하나와 별표 문자 (
/* comment */)를 사용합니다.
리터럴
YARA-L은 음수가 아닌 정수 및 부동 소수점 수, 문자열, 불리언, 정규 표현식 리터럴을 지원합니다. 리터럴은 쿼리 조건에 사용되는 고정 값입니다. YARA-L은 패턴 일치를 위한 정규 표현식 (슬래시로 묶임) 및 논리를 위한 불리언 (true/false)과 같은 다른 리터럴 유사 구조도 사용합니다.
문자열 리터럴
문자열 리터럴은 큰따옴표 (") 또는 역따옴표 (`)로 묶인 문자 시퀀스입니다. 문자열은 사용한 따옴표 유형에 따라 다르게 해석됩니다.
- 큰따옴표 ("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에서는 모든 변수가 $<variable name> 구문을 사용합니다. YARA-L에서는 다음 유형의 변수를 사용할 수 있습니다.
이벤트 변수
이벤트 변수는 이벤트 그룹 또는 항목 이벤트를 나타냅니다. 이름, 이벤트 소스, 이벤트 필드를 사용하여 events 섹션에서 이벤트 변수의 조건을 지정합니다.
이벤트 소스는
udm(정규화된 이벤트) 및graph(항목 이벤트)입니다. 소스가 생략된 경우udm이 기본 소스로 설정됩니다.이벤트 필드는 일련의 .<field name> (예: $e.field1.field2)으로 표현되며, 필드 체인은 항상 최상위 소스 (UDM 또는 Entity)로 시작됩니다.
일치 변수
일치 변수는 match 섹션에서 지정된 기간 내의 공통 값을 기반으로 이벤트를 그룹화하는 데 사용됩니다.
일치 변수는 쿼리의 그룹화 필드가 됩니다. 여기에서 일치 변수의 각 고유 집합에 대해 그리고 각 기간에 대해 하나의 행이 반환됩니다. 쿼리에서 일치 항목을 찾으면 일치 변수 값이 반환됩니다.
각 일치 변수가 events 섹션에서 나타내는 대상을 지정합니다.
자리표시자 변수
자리표시자 변수는 UDM 이벤트 필드에서 특정 값을 캡처하고 저장하여 쿼리 전체에서 참조하고 사용하는 데 사용됩니다. 특히 다중 이벤트 쿼리에서 서로 다른 이벤트를 연결하는 데 사용됩니다. 자리표시자에 공통 값 (예: userid 또는 hostname)을 할당하면 match 섹션에서 이 자리표시자를 사용하여 지정된 기간 내에 해당 값을 공유하는 이벤트를 그룹화할 수 있습니다.
events 섹션에서 UDM 필드의 값을 $로 시작하는 변수 이름에 할당하여 자리표시자 변수를 정의합니다 (예: $targetUser = $e.target.user.userid).
다음 섹션에서 자리표시자 변수를 정의할 수도 있습니다.
condition섹션에서 자리표시자 변수를 사용하여 일치 조건을 지정할 수 있습니다.outcome섹션을 사용하여 계산을 실행하거나, 측정항목을 정의하거나, 일치하는 이벤트에서 특정 데이터 포인트를 추출합니다.match섹션을 사용하여 공통 값으로 이벤트를 그룹화합니다.
키워드
YARA-L에서 키워드는 감지 쿼리의 구조와 논리를 정의하는 예약어입니다. 쿼리의 여러 섹션을 지정하고, 논리 및 수학 연산을 실행하고, 이벤트 일치 조건을 정의하는 데 사용됩니다. 이러한 키워드는 쿼리, 문자열 또는 변수의 식별자로 사용할 수 없습니다.
키워드는 대소문자를 구분하지 않습니다 (예: and 또는 AND은 동일함).
YARA-L 2.0 키워드의 주요 카테고리
이 목록은 완전하지는 않지만 강력한 감지 쿼리를 구성하기 위해 YARA-L 2.0에서 사용되는 기본 키워드를 포함합니다.
- 쿼리 정의:
rule: 새 YARA-L 쿼리의 정의를 시작합니다.private: 쿼리를 비공개로 지정하여 외부에서 직접 노출되거나 트리거되지 않도록 합니다.global: 쿼리를 전역으로 표시하여 광범위하게 적용해야 함을 나타냅니다.
- 질문 섹션:
meta: 질문에 관한 설명 정보의 메타데이터 섹션을 소개합니다.strings: 문자열 패턴이 정의된 섹션을 나타냅니다.condition: 쿼리 트리거링을 위한 불리언 로직이 포함된 섹션을 지정합니다.events: 이벤트 변수와 조건을 지정하는 섹션을 정의합니다.match: 기간에 걸쳐 값을 집계하는 섹션을 도입합니다.outcome: 트리거된 질문에 컨텍스트를 추가하고 점수를 매기는 섹션을 정의합니다.
- 문자열 수정자:
ascii: 문자열이 ASCII 텍스트로 일치해야 함을 지정합니다.wide: 문자열이 와이드 (UTF-16) 문자로 일치해야 함을 나타냅니다.nocase: 대소문자를 구분하지 않는 문자열 일치를 실행합니다.fullword: 문자열이 완전한 단어로 일치해야 합니다.xor: 일치 전에 문자열에 XOR 변환을 적용합니다.base64,base64wide: 일치시키기 전에 Base64 인코딩을 적용합니다.
- 논리 연산자:
and,or,not: 조건을 결합하는 표준 불리언 논리 연산자입니다.all of,any of: 조건 내에서 여러 표현식을 평가하는 데 사용됩니다.
- 비교 및 관계 연산자:
at: 문자열 일치의 정확한 오프셋을 지정합니다.contains: 문자열에 하위 문자열이 포함되어 있는지 확인합니다.startswith,endswith: 문자열이 하위 문자열로 시작하거나 끝나는지 확인합니다.icontains,istartswith,iendswith,iequals: 대소문자를 구분하지 않는 버전입니다.matches: 정규 표현식 일치에 사용됩니다.
- 데이터 유형 및 크기 지정자:
int8,uint8,int16,uint16,int32,uint32: 지정된 크기의 정수 유형입니다.int8be,uint8be,int16be,uint16be,int32be,uint32be: 정수 유형의 빅엔디언 버전입니다.filesize: 분석 중인 파일의 크기를 나타냅니다.entrypoint: 실행 파일의 진입점을 나타냅니다.
지도
YARA-L은 일부 UDM 필드에서 사용되는 구조체 및 라벨 데이터 유형의 지도를 지원합니다.
구조체와 라벨 데이터 유형에서 특정 키-값 쌍을 검색하려면 표준 맵 문법을 사용합니다.
- 구조체 필드 문법:
$e.udm.additional.fields["pod_name"] = "kube-scheduler" - 라벨 필드 구문:
$e.metadata.ingestion_labels["MetadataKeyDeletion"] = "startup-script"
예: 지도 사용의 유효한 경우와 유효하지 않은 경우
다음 예시는 지도의 유효한 사용과 잘못된 사용을 보여줍니다.
지도의 올바른 사용
이벤트 섹션에서 구조체 필드 사용:
events: $e.udm.additional.fields["pod_name"] = "kube-scheduler"
결과 섹션에서 라벨 필드 사용:
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"
기타 유형의 값
맵 문법은 문자열 값만 반환할 수 있습니다. [구조체](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) 데이터 유형의 경우 맵 문법은 값이 문자열인 키에만 액세스할 수 있습니다. 값이 정수와 같은 다른 기본 유형인 키에는 액세스할 수 없습니다.
지도에서 중복 값 처리
지도 액세스는 특정 키와 연결된 단일 값을 검색하기 위한 것입니다. 이는 표준적이고 예상되는 동작입니다.
하지만 드물고 흔하지 않은 상황에서는 map access의 컨텍스트가 실수로 여러 값을 가리킬 수 있습니다. 드문 경우지만 맵 액세스에서 여러 값을 참조하는 경우 map access는 첫 번째 값을 확정적으로 반환합니다. 라벨에 중복 키가 있거나 라벨에 상위 항목 반복 필드가 있으면 이 문제가 발생할 수 있습니다.
라벨에 중복 키가 있음
라벨 구조는 지도를 나타내지만 키 고유성을 적용하지는 않습니다. 규칙에 따라 지도에는 고유한 키가 있어야 하므로 Google SecOps에서는 라벨을 중복 키로 채우지 않는 것이 좋습니다.
예: 중복 키가 있는 라벨
쿼리 텍스트 $e.metadata.ingestion_labels["dupe-key"]는 다음 데이터 예시를 대상으로 실행되는 경우 첫 번째 가능한 값인 val1을 반환합니다.
// Disrecommended usage of label with a duplicate key:
event {
metadata{
ingestion_labels{
key: "dupe-key"
value: "val1" // This is the first possible value for "dupe-key"
}
ingestion_labels{
key: "dupe-key"
value: "val2"
}
}
}
라벨에 상위 항목 반복 필드가 있음
반복 필드에는 라벨이 하위 필드로 포함될 수 있습니다. 최상위 반복 필드의 서로 다른 두 항목에 동일한 키가 있는 라벨이 포함될 수 있습니다.
예: 상위 항목 반복 필드가 있는 라벨
쿼리 텍스트 $e.security_result.rule_labels["key"]는 다음 데이터 예시를 대상으로 실행되는 경우 첫 번째 가능한 값인 `val3`을 반환합니다.
event {
// security_result is a repeated field.
security_result {
threat_name: "threat1"
rule_labels {
key: "key"
value: "val3" // This is the first possible value for "key"
}
}
security_result {
threat_name: "threat2"
rule_labels {
key: "key"
value: "val4"
}
}
}
지도에서 결과 변수에 액세스
이 섹션에서는 문자열뿐만 아니라 원래 데이터 유형 (예: 정수, 불리언 또는 이러한 유형의 목록)으로 지도 내 결과 변수에 액세스하는 방법을 설명합니다. 이 기능을 사용하면 쿼리 로직의 유연성과 정확성을 높일 수 있습니다.
결과 데이터는 다음 필드에서 확인할 수 있습니다.
- 결과 값은
variables필드에서 원래 유형을 유지합니다. outcomes필드는 하위 호환성을 위해string버전을 저장합니다.
variables 맵을 사용하여 이러한 결과 값에 액세스하여 특정 유형을 검색하거나 배열 색인 생성을 사용하여 시퀀스의 요소에 액세스할 수 있습니다. 색인으로 시퀀스의 특정 항목에 액세스하거나 전체 시퀀스를 선택하여 각 값을 개별적으로 평가할 수 있습니다.
구문:
$d.detection.detection.variables[OUTCOME_NAME].TYPE_SUFFIX
시퀀스 구문:
$d.detection.detection.variables[OUTCOME_NAME].SEQUENCE_TYPE_SUFFIX.TYPE_VALS_SUFFIX
예: 지도에서 결과 변수에 액세스
문자열 결과에 액세스:
$my_string_outcome = $d.detection.detection.variables["outcome_ip"].string_val
이 예시에서는 문자열 값을 직접 가져옵니다 (예: outcome_ip이 단일 문자열인 경우 "1.1.1.1").
정수 결과 액세스
$my_int_outcome = $d.detection.detection.variables["outcome_port"].int64_value
이 예시에서는 정수 값 (예: 30)을 가져옵니다.
Int64Sequence를 사용하여 정수 목록에 액세스
$my_int_list = $d.detection.detection.variables["outcome_ports"].int64_seq.int64_vals
이 예에서는 정수의 전체 목록을 가져와 반복 필드 (예: [2, 3, 4])와 같이 중첩 해제합니다.
정수 목록에서 특정 요소에 액세스
$first_int = $d.detection.detection.variables["outcome_ports"].int64_seq.int64_vals[0]
이 예에서는 목록에서 첫 번째 정수를 가져옵니다 (예: 2).
문자열 목록 (StringSequence) 액세스
$my_string_list = $d.detection.detection.variables["outcome_ips"].string_seq.string_vals
이 예시에서는 문자열의 전체 목록을 가져와 반복 필드 (예: ["1.1.1.1", "2.2.2.2"])와 같이 중첩 해제합니다.
문자열 목록에서 특정 요소에 액세스
$first_ip = $d.detection.detection.variables["outcome_ips"].string_seq.string_vals[0]
이 예시에서는 목록에서 첫 번째 IP 주소 (예: "1.1.1.1")를 가져옵니다.
variables에 사용 가능한 유형 접미사
지원되는 접미사의 전체 목록은 FindingVariable을 참고하세요.
도움이 더 필요하신가요? 커뮤니티 회원 및 Google SecOps 전문가에게 문의하여 답변을 받으세요.