YARA-L 2.0 언어 개요
YARA-L 2.0은 기업 로그 데이터가 Google Security Operations 인스턴스에 수집될 때 이 데이터를 검색할 수 있는 규칙을 만들기 위해 사용되는 컴퓨터 언어입니다. YARA-L 구문은 VirusTotal에서 개발된 YARA 언어로부터 파생됩니다. 이 언어는 Google Security Operations Detection Engine과 함께 작동하며 대량의 데이터에 대해 위협 요소 및 기타 이벤트를 찾을 수 있게 해줍니다.
자세한 내용은 다음을 참조하세요.
YARA-L 2.0 예시 규칙
다음 예시는 YARA-L 2.0으로 작성된 규칙을 보여줍니다. 각 항목은 규칙 언어 내에서 이벤트의 상관관계를 지정하는 방법을 보여줍니다.
규칙 및 조정
다음 규칙은 이벤트 데이터의 특정 패턴을 확인하고 패턴이 발견되면 감지를 만듭니다. 이 규칙에는 이벤트 유형과 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
}
다른 도시의 로그인
다음 규칙은 5분 이내에 두 개 이상의 도시에서 회사에 로그인한 사용자를 검색합니다.
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
이벤트 변수:$udm
자리표시자 변수: $city
및 $user
다음은 이 규칙의 작동 방법을 설명합니다.
- 이벤트를 사용자 이름(
$user
)과 그룹으로 묶고 일치가 발견되면 이를 반환($user
)합니다. - 기간은 5분입니다. 즉, 서로 5분 이내에 발생하는 이벤트만 상관관계가 지정됩니다.
- 해당 이벤트 유형이 USER_LOGIN인 이벤트 그룹(
$udm
)을 검색합니다. - 이 이벤트 그룹에 대해 이 규칙은 사용자 ID를
$user
로 호출하고 로그인 도시를$city.
로 호출합니다. city
값(#city
로 표시됨)의 고유 숫자가 이벤트 그룹($udm
)에서 5분 기간 내에 1보다 크면 일치를 반환합니다.
빠른 사용자 만들기 및 삭제
다음 규칙은 생성되고 4시간 내에 삭제된 사용자를 검색합니다.
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
}
이벤트 변수: $create
및 $delete
일치 변수: $user
자리표시자 변수: 해당 없음
다음은 이 규칙의 작동 방법을 설명합니다.
- 이벤트를 사용자 이름(
$user
)과 그룹으로 묶고 일치가 발견되면 이를 반환($user
)합니다. - 기간은 4시간이며, 간격이 4시간 미만인 이벤트만 상관관계가 지정됩니다.
$create
가#create >= 1
과 동일한 2개의 이벤트 그룹($create
및$delete
)을 검색합니다.$create
는USER_CREATION
이벤트에 해당하며 사용자 ID를$user
로 호출합니다.$user
는 2개의 이벤트 그룹을 하나로 조인하기 위해 사용됩니다.$delete
는USER_DELETION
이벤트에 해당하며 사용자 ID를$user
로 호출합니다. 이 규칙은 두 이벤트 그룹의 사용자 식별자가 동일한 일치를 찾습니다.- 이 규칙은
$delete
의 이벤트가$create
의 이벤트보다 늦게 발생하는 경우를 찾고, 발견되면 일치를 반환합니다.
단일 이벤트 규칙
단일 이벤트 규칙은 단일 이벤트에 대한 상관관계가 있는 규칙입니다. 단일 이벤트 규칙은 다음과 같을 수 있습니다.
- 일치 섹션이 없는 모든 규칙
- 1개 이벤트 존재만 확인하는
match
섹션 및condition
섹션의 규칙(예: "$e", "#e > 0", "#e >= 1", "1 <= #e", "0 < #e")
예를 들어 다음 규칙은 사용자 로그인 이벤트를 검색하고 Google Security Operations 계정 내에 저장된 기업 데이터 내에서 발생하는 첫 번째 항목을 반환합니다.
rule SingleEventRule {
meta:
author = "noone@altostrat.com"
events:
$e.metadata.event_type = "USER_LOGIN"
condition:
$e
}
다음은 일치 섹션이 있는 단일 이벤트 규칙의 예시입니다. 이 규칙은 5분 이내에 한 번 이상 로그인한 사용자를 검색합니다. 사용자 로그인 이벤트의 단순한 존재를 확인합니다.
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
}
rule MultiEventRule{
meta:
author = "alice@example.com"
description = "Rule with outcome condition and simple existence condition on one event variable"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $user
match:
$user over 10m
outcome:
$num_events_in_match_window = count($e.metadata.id)
condition:
#e > 0 and $num_events_in_match_window >= 10 // Could be rewritten as #e >= 10
}
여러 이벤트 규칙
여러 이벤트 규칙을 사용하여 지정된 기간 동안 많은 이벤트를 그룹화하고 이벤트 간 상관관계를 찾습니다. 일반적인 여러 이벤트 규칙에는 다음이 포함됩니다.
- 이벤트를 그룹화해야 하는 시간 범위를 지정하는
match
섹션 - 발견 항목을 트리거하고 여러 이벤트의 존재 여부를 확인하는 조건을 지정하는
condition
섹션
예를 들어 다음 규칙은 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
}
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 주소가 5분 내에 안전한 것으로 알려진 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
}
규칙의 정규 표현식
다음 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
}
슬라이딩 기간 규칙 예시
다음 YARA-L 2.0 슬라이딩 창 예시는 firewall_1
이벤트 후 firewall_2
이벤트의 부재를 검색합니다. after
키워드는 피벗 이벤트 변수 $e1
과 함께 사용되어 이벤트의 상관관계를 지정할 때 10분 후에만 각 firewall_1
이벤트를 검사하도록 지정합니다.
rule SlidingWindowRuleExample {
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:
$host over 10m after $e1
condition:
$e1 and !$e2
}
0 값 제외 예시
규칙 엔진은 match
섹션에 사용된 모든 자리 표시자에 대해 0 값을 암시적으로 필터링합니다.
자세한 내용은 match
섹션의 0 값 처리를 참조하세요.
이는 allow_zero_values에 설명된 대로 allow_zero_values
옵션을 사용하여 사용 중지할 수 있습니다.
하지만 다른 참조된 이벤트 필드의 경우 명시적으로 조건을 지정하지 않으면 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
}
outcome
섹션이 있는 규칙 예시
YARA-L 2.0 규칙에 선택적인 outcome
섹션을 추가하여 각 발견 항목에 대한 추가 정보를 추출할 수 있습니다. 조건 섹션에서 결과 변수에 조건부를 지정할 수도 있습니다. 감지 규칙의 outcome
섹션을 사용해서 다운스트림 소비에 대한 변수를 설정할 수 있습니다. 예를 들어 분석 중인 이벤트의 데이터를 기반으로 심각도 점수를 설정할 수 있습니다.
자세한 내용은 다음을 참조하세요.
결과 섹션이 있는 멀티 이벤트 규칙:
다음 규칙에서는 두 가지 이벤트를 확인하여 $hostname
값을 가져옵니다. $hostname
값이 5분 이상 일치하면 심각도 점수가 적용됩니다. 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")
}
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")
}
결과 섹션이 있는 단일 이벤트 규칙:
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.userid in %admin_users, "SEVERE", "MODERATE")
$severity_tag = if($file_size > 1024, $admin_severity, "LOW")
condition:
$u
}
멀티 이벤트 결과 규칙을 단일 이벤트 결과 규칙으로 리팩터링
단일 이벤트 규칙(match
섹션이 없는 규칙) 및 멀티 이벤트 규칙(match
섹션이 있는 규칙) 모두 outcome
섹션을 사용할 수 있습니다.
이전에 결과 섹션을 사용할 수 있도록 규칙을 다중 이벤트로 설계한 경우, match
섹션을 삭제하여 해당 규칙을 선택적으로 리팩터링하면 성능을 개선할 수 있습니다. 규칙에 그룹화를 적용하는 match
섹션이 더 이상 없으므로 더 많은 감지가 수신될 수 있습니다. 이 리팩터링은 다음 예시에 표시된 것처럼 1개 이벤트 변수를 사용하는 규칙에만 가능합니다.
하나의 이벤트 변수만 사용하는 멀티 이벤트 결과 규칙(리팩터링에 적합함):
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
}
match
섹션을 삭제하여 규칙을 리팩터링할 수 있습니다. 이제 규칙이 단일 이벤트가 되므로 outcome
섹션에서 집계도 삭제해야 합니다. 집계에 대한 자세한 내용은 결과 집계를 참조하세요.
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
}
자리 표시자 규칙 예시 함수
함수 호출의 결과에 자리 표시자 변수를 할당하고 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.from , "(.*)@")
// Use function-placeholder assignment to normalize an email:
// uid@??? -> uid@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, 10, 0) +
if($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
}
결과 조건부 예시 규칙
condition
섹션에서 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
}