運算式、運算子和其他建構體
本文提供相關資訊,協助您使用運算式建構 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 or b and c」會評估為「a or (b and 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 會解讀為 Tab 鍵。
- 反引號 (`hello\tworld`):用於所有字元都應解讀為常值的情況,其中 \t 不會解讀為 Tab 鍵。
規則運算式常值
對於規則運算式常值,您有兩種做法:
如要直接使用規則運算式,而不使用
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/
Google 建議在規則運算式中使用反引號字元表示字串,方便讀取。
運算子
| 運算子 | 說明 |
| = | equal/declaration |
| != | 不等於 |
| < | 小於 |
| <= | 小於或等於 |
| > | 大於 |
| >= | 大於或等於 |
變數
在 YARA-L 中,所有變數都使用 $<variable name> 語法。YARA-L 可使用下列類型的變數。
事件變數
事件變數代表事件群組或實體事件。您可以在 events 區段中,使用名稱、事件來源和事件欄位,指定事件變數的條件。
事件來源為
udm(適用於標準化事件) 和graph(適用於實體事件)。如果省略來源,系統會將udm設為預設來源。事件欄位會以 .<欄位名稱> 鏈結表示 (例如 $e.field1.field2),且欄位鏈結一律從頂層來源 (UDM 或實體) 開始。
比對變數
「比對變數」用於 match 區段,根據指定時間範圍內的共同值將事件分組。
這些欄位會成為查詢的分組欄位,因為系統會為每組不重複的相符變數 (以及每個時間範圍) 傳回一個資料列。查詢找到相符項目時,系統會傳回相符變數值。
您可以在 events 區段中指定每個比對變數代表的內容。
預留位置變數
預留位置變數可用來擷取及儲存 UDM 事件欄位的特定值,以便在整個查詢中參照及使用。這類 ID 可用於連結不同的事件,特別是在多事件查詢中。只要將通用值 (例如 userid 或 hostname) 指派給預留位置,您就能在 match 區段中使用這個預留位置,將指定時間範圍內共用該值的事件分組。
您可以在 events 區段中定義預留位置變數,方法是將 UDM 欄位的值指派給以 $ 為前置字元的變數名稱 (例如:$targetUser = $e.target.user.userid)。
您也可以在下列部分定義預留位置變數:
condition部分指定比對條件。outcome區段,執行計算、定義指標,或從相符事件中擷取特定資料點。- 部分,依共同值將事件分組。
match
關鍵字
在 YARA-L 中,關鍵字是保留字,用於定義偵測查詢的結構和邏輯。這些運算子可用於指定查詢的不同區段、執行邏輯和數學運算,以及定義相符事件的條件。這些關鍵字無法做為查詢、字串或變數的 ID。
關鍵字不區分大小寫 (例如 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 支援 Struct 和 Label 資料類型的對應,這兩種資料類型用於部分 UDM 欄位。
如要在 Struct 和 Label 資料類型中搜尋特定鍵/值組合,請使用標準對應語法:
- 結構體欄位語法:
$e.udm.additional.fields["pod_name"] = "kube-scheduler" - 標籤欄位語法:
$e.metadata.ingestion_labels["MetadataKeyDeletion"] = "startup-script"
示例:地圖的有效和無效使用方式
以下範例說明地圖的有效和無效用法。
地圖的有效用途
在「事件」部分使用 Struct 欄位:
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"
其他類型的值
對應語法只能傳回字串值。如果是 [Struct](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 專業人員尋求答案。