Masalah umum YARA-L 2.0
Dokumen ini ditujukan untuk engineer deteksi yang ingin men-debug logika aturan dan mengoptimalkan eksekusi YARA-L 2.0. Dokumen ini menjelaskan cara menangani perilaku mesin non-standar, seperti unnesting kolom, perluasan Cartesian product dalam agregasi, dan konsistensi tertunda pengayaan. Dengan mengikuti metode ini, Anda dapat mencegah error logika yang menyebabkan nilai hasil yang terlalu tinggi atau deteksi yang terlewat.
YARA-L 2.0 menggunakan model eksekusi yang memperluas kolom berulang menjadi baris peristiwa individual selama evaluasi. Karena transformasi ini terjadi di tingkat mesin, mereferensikan beberapa kolom berulang atau melakukan aritmetika pada jenis Unified Data Model (UDM) yang tidak ditandatangani memerlukan solusi sintaksis untuk menghindari error compiler, error runtime, atau set hasil yang salah. Dokumen ini menguraikan batasan teknis tersebut dan pola logika yang menyelesaikannya.
Sebelum memulai
Pastikan akun Anda memiliki hak teknis berikut sebelum menguji atau mengubah aturan YARA-L 2.0:
Peran IAM yang diperlukan
roles/chronicle.viewer(Security Operations Viewer): Untuk melihat aturan dan metadata deteksi yang ada.roles/chronicle.editor(Security Operations Editor): Untuk mengubah logika aturan dan menyimpan perubahan.
Izin yang diperlukan
chronicle.rules.runTest: Diperlukan untuk menjalankan fitur Jalankan Pengujian pada data historis.chronicle.detections.get: Untuk memeriksa output peristiwa yang tidak bertingkat di dasbor deteksi.
Terminologi utama
- UDM (Unified Data Model): Skema yang dinormalisasi yang digunakan untuk menyusun semua telemetri keamanan yang diserap di seluruh platform.
- Unnesting: Perluasan tingkat mesin dari satu peristiwa UDM yang berisi kolom berulang (array) menjadi beberapa baris. Setiap baris mewakili elemen unik dari array, yang dapat menyebabkan penggandaan baris selama evaluasi aturan.
- T₀ (eksekusi awal): Eksekusi pertama aturan pada telemetri yang masuk. Hal ini terjadi selama fase "streaming", sering kali sebelum proses pengayaan latar belakang (seperti penyesuaian GeoIP atau ASN) diselesaikan.
Agregasi hasil dengan unnesting kolom berulang
Jika aturan merujuk ke kolom berulang dalam variabel peristiwa dengan beberapa elemen, setiap elemen akan dibagi menjadi baris peristiwa terpisah.
Misalnya, dua alamat IP di kolom berulang target.ip pada peristiwa $e dibagi menjadi dua instance $e, masing-masing dengan nilai target.ip yang berbeda.
rule outbound_ip_per_app {
meta:
events:
$e.principal.application = $app
match:
$app over 10m
outcome:
$outbound_ip_count = count($e.target.ip) // yields 2.
condition:
$e
}
Data peristiwa: Sebelum dan setelah unnesting
Tabel di bagian ini menunjukkan cara satu peristiwa yang berisi array alamat IP diubah menjadi dua data yang berbeda.
Sebelum unnesting
Tabel berikut menunjukkan data peristiwa sebelum memisahkan kolom berulang:
| metadata.id | principal.application | target.ip |
|---|---|---|
aaaaaaaaa |
Google SecOps |
[192.0.2.20, 192.0.2.28] |
Setelah unnesting
Tabel berikut menunjukkan data peristiwa setelah membatalkan pengelompokan kolom berulang:
| metadata.id | principal.application | target.ip |
|---|---|---|
aaaaaaaaa |
Google SecOps |
192.0.2.20 |
aaaaaaaaa |
Google SecOps |
192.0.2.28 |
Kolom berulang bertingkat (Cartesian product)
Jika aturan merujuk ke kolom berulang yang bertingkat dalam kolom lain, seperti security_results.action, unnesting terjadi di kedua tingkat (induk dan turunan) secara bersamaan. Hal ini menghasilkan Cartesian product dari semua elemen.
Dalam contoh berikut, peristiwa $e dengan dua nilai berulang pada security_results dan dua nilai berulang pada security_results.actions di-un-nest menjadi empat instance.
rule security_action_per_app {
meta:
events:
$e.principal.application = $app
match:
$app over 10m
outcome:
$security_action_count = count($e.security_results.actions) // yields 4.
condition:
$e
}
Data peristiwa sebelum unnesting bertingkat
Data asli menyimpan tindakan dalam struktur array bertingkat.
| metadata.id | principal.application | security_results |
|---|---|---|
aaaaaaaaa |
Google SecOps |
[ { actions: [ ALLOW, FAIL ] }, { actions: [ CHALLENGE, BLOCK ] } ] |
Data peristiwa setelah unnesting bertingkat
Setelah perluasan, setiap tindakan unik akan menjadi barisnya sendiri, yang dapat menyebabkan jumlah yang tidak terduga dalam agregasi non-distinct.
| metadata.id | principal.application | security_results.actions |
|---|---|---|
aaaaaaaaa |
Google SecOps |
IZINKAN |
aaaaaaaaa |
Google SecOps |
GAGAL |
aaaaaaaaa |
Google SecOps |
TANTANGAN |
aaaaaaaaa |
Google SecOps |
BLOKIR |
Dampak pada kolom yang tidak terkait
Perilaku unnesting dalam evaluasi aturan ini dapat menghasilkan agregasi hasil yang tidak terduga saat aturan mereferensikan satu atau beberapa kolom berulang dengan kolom induk yang juga merupakan kolom berulang. Agregasi non-distinct
seperti sum(), array(), dan count() tidak dapat memperhitungkan nilai duplikat di
kolom lain pada peristiwa yang sama yang dihasilkan oleh perilaku unnesting.
Dalam contoh berikut, peristiwa $e memiliki satu nama host (google.com), tetapi hasilnya (hostnames)
menggabungkan empat instance yang tidak bertingkat dari peristiwa $e yang sama, masing-masing dengan nilai
principal.hostname duplikat. Hasil ini menghasilkan empat nama host (bukan satu)
karena peng-unnest-an nilai berulang pada security_results.actions.
rule security_action_per_app {
meta:
events:
$e.principal.application = $app
match:
$app over 10m
outcome:
$hostnames = array($e.principal.hostname) // yields 4.
$security_action_count = count($e.security_results.action) // yields 4.
condition:
$e
}
Data peristiwa sebelum unnesting dengan kolom yang tidak terkait
Nama host adalah nilai tunggal, tetapi berada di samping hasil keamanan berulang.
| metadata.id | principal.application | principal.hostname | security_results |
|---|---|---|---|
aaaaaaaaa |
Google SecOps |
google.com |
[ { action: [ ALLOW, FAIL ] }, { action: [ CHALLENGE, BLOCK ] } ] |
Data peristiwa setelah unnesting dengan kolom yang tidak terkait
Nama host kini diduplikasi di empat baris, sehingga fungsi array() mengambilnya empat kali.
| metadata.id | principal.application | principal.hostname | security_results.action |
|---|---|---|---|
aaaaaaaaa |
Google SecOps |
google.com |
IZINKAN |
aaaaaaaaa |
Google SecOps |
google.com |
GAGAL |
aaaaaaaaa |
Google SecOps |
google.com |
TANTANGAN |
aaaaaaaaa |
Google SecOps |
google.com |
BLOKIR |
Solusi untuk perilaku unnesting
Untuk memastikan nilai hasil Anda akurat saat unnesting terjadi, gunakan versi yang berbeda dari agregasi yang Anda pilih. Fungsi berikut mengabaikan baris duplikat yang dibuat oleh unnesting:
max()min()array_distinct()count_distinct()
Agregasi hasil dengan beberapa variabel peristiwa
Jika aturan berisi beberapa variabel peristiwa, ada item terpisah dalam agregasi untuk setiap kombinasi peristiwa yang disertakan dalam deteksi. Misalnya, jika contoh aturan berikut dijalankan terhadap peristiwa yang tercantum:
events:
$e1.field = $e2.field
$e2.somefield = $ph
match:
$ph over 1h
outcome:
$some_outcome = sum(if($e1.otherfield = "value", 1, 0))
condition:
$e1 and $e2
event1:
// UDM event 1
field="a"
somefield="d"
event2:
// UDM event 2
field="b"
somefield="d"
event3:
// UDM event 3
field="c"
somefield="d"
Jumlah dihitung dari setiap kombinasi peristiwa, sehingga Anda dapat menggunakan kedua variabel peristiwa dalam penghitungan nilai hasil. Elemen berikut digunakan dalam penghitungan:
1: $e1 = event1, $e2 = event2
2: $e1 = event1, $e2 = event3
3: $e1 = event2, $e2 = event1
4: $e1 = event2, $e2 = event3
5: $e1 = event3, $e2 = event1
5: $e1 = event3, $e2 = event2
Hal ini menghasilkan potensi jumlah maksimum 6, meskipun $e2 hanya dapat sesuai dengan 3 peristiwa yang berbeda.
Hal ini memengaruhi jumlah, hitungan, dan array. Untuk count dan array, penggunaan count_distinct atau array_distinct dapat menyelesaikan masalah, tetapi tidak ada solusi untuk sum.
Tanda kurung di awal ekspresi
Memulai ekspresi dengan tanda kurung tidak didukung dan akan memicu error penguraian di editor aturan.
Sintaksis tidak valid
parsing: error with token: ")"
invalid operator in events predicate
Contoh berikut menghasilkan jenis error ini:
($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) / 3600 > 1
Variasi sintaksis yang valid
Variasi sintaksis berikut menampilkan hasil yang sama, tetapi dengan sintaksis yang valid:
$event.metadata.ingested_timestamp.seconds / 3600 -
$event.metadata.event_timestamp.seconds / 3600 > 1
1 / 3600 * ($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) > 1
1 < ($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) / 3600
Array indeks dalam hasil memerlukan agregasi
Mengindeks array secara langsung dalam bagian outcome untuk kolom berulang tidak diizinkan. Hal ini memerlukan variabel placeholder sementara.
outcome:
$principal_user_dept = $suspicious.principal.user.department[0]
Solusi
Ambil indeks array tertentu ke dalam variabel placeholder dalam bagian events, lalu referensikan placeholder tersebut dalam hasil Anda.
events:
$principal_user_dept = $suspicious.principal.user.department[0]
outcome:
$principal_user_department = $principal_user_dept
Kondisi OR dengan ketiadaan
Jika Anda menerapkan kondisi OR di antara dua variabel peristiwa yang terpisah dan jika
aturan cocok dengan ketiadaan, aturan akan berhasil dikompilasi, tetapi dapat menghasilkan
deteksi positif palsu.
Misalnya, sintaksis aturan berikut dapat mencocokkan peristiwa yang memiliki $event_a.field = "something" meskipun seharusnya tidak:
events:
not ($event_a.field = "something" **or** $event_b.field = "something")
condition:
$event_a and #event_b >= 0
Solusi
Pisahkan pemeriksaan ketiadaan menjadi blok-blok individual untuk setiap variabel guna mempertahankan integritas logika.
events:
not ($event_a.field = "something")
not ($event_b.field = "something")
condition:
$event_a and #event_b >= 0
Aritmetika dengan kolom peristiwa yang tidak ditandatangani
Jika Anda menggunakan literal bilangan bulat dalam operasi aritmetika (+, -, *) atau modulo (%) dengan kolom UDM bilangan bulat tanpa tanda tangan, Anda akan mendapatkan error. Literal bilangan bulat standar ditetapkan secara default ke bilangan bulat 64-bit bertanda (INT64), yang tidak kompatibel dengan kolom UDM yang ditentukan sebagai bilangan bulat 64-bit tidak bertanda (UINT64), seperti network.received_bytes, network.sent_bytes, dan principal.file.size.
Batasan pengetikan yang ketat ini berlaku untuk bagian events dan outcome, termasuk di dalam agregasi sum() atau max() dan ekspresi pembagi. Pemeriksa sintaksis YARA-L memperlakukan bilangan bulat bertanda tangan dan tidak bertanda tangan sebagai jenis int generik. Akibatnya, aturan yang menggabungkan kolom UDM UINT64 dan literal bilangan bulat INT64 mungkin lulus validasi sintaksis waktu penyimpanan, tetapi gagal selama eksekusi aturan atau saat Anda mengklik Run Test. Jika gagal, aturan akan menghasilkan "Error Aturan" umum
(cannot complete [arithmetic/mod] operation between unsigned and signed integer).
Misalnya, perbandingan events berikut lulus validasi sintaksis saat
disimpan, tetapi gagal selama eksekusi karena $e.network.received_bytes (UINT64)
dikalikan dengan literal bilangan bulat bertanda tangan 2 (INT64):
events:
$total_bytes = $e.network.total_bytes
$total_bytes = $e.network.received_bytes * 2
Solusi
Anda dapat mengatasi ketidakcocokan jenis ini menggunakan salah satu metode berikut:
- Transmisi bilangan bulat eksplisit (
cast.as_int()ataucast.as_uint()): Konversikan kolom UDM yang tidak ditandatangani menjadi bilangan bulat yang ditandatangani menggunakancast.as_int(), atau konversikan literal bilangan bulat menjadi bilangan bulat yang tidak ditandatangani menggunakancast.as_uint(). Gunakan metode ini saat Anda memerlukan hasil bilangan bulat atau saat menggunakan operator modulo (%), yang hanya menerima operand bilangan bulat. - Pemaksaan floating point: Memaksa konstanta bilangan bulat untuk berperilaku sebagai
floatmenggunakan literal floating point, seperti2.0atau100.0. Dalam ekspresi sederhana tanpa operator pembagian lain pada baris yang sama, Anda juga dapat menggunakan operasi pembagian, seperti(2/1). Dalam ekspresi yang sudah berisi operator pembagian (/), gunakan literal floating point ataucast.as_int(), bukan pemaksaan pembagian(N/1). Beberapa karakter/pada baris yang sama dapat ditafsirkan sebagai literal ekspresi reguler, sehingga menyebabkan error penguraian selama kompilasi atau merusak penyorotan sintaksis di Editor Aturan.
Solusi di bagian events
Gunakan cast.as_int(), literal floating point, atau pemaksaan pembagian untuk memperbaiki error di bagian events:
Gunakan
cast.as_int():events: $total_bytes = $e.network.total_bytes $total_bytes = cast.as_int($e.network.received_bytes) * 2Gunakan literal floating point:
events: $total_bytes = $e.network.total_bytes $total_bytes = $e.network.received_bytes * 2.0Gunakan pemaksaan pembagian:
events: $total_bytes = $e.network.total_bytes $total_bytes = $e.network.received_bytes * (2/1)
Solusi di bagian outcome
Ekspresi outcome berikut disimpan tanpa error sintaksis, tetapi gagal saat runtime karena sum($e.network.sent_bytes) dan sum($e.network.received_bytes) menampilkan nilai UINT64 yang digabungkan dengan literal INT64 bertanda tangan 100 dan 1:
outcome:
// Saves, but fails at runtime:
$upload_ratio_pct = sum($e.network.sent_bytes) * 100 / (sum($e.network.received_bytes) + 1)
Tulis ulang ekspresi menggunakan literal floating point atau cast.as_int() agar
ekspresi tersebut disimpan dan dijalankan tanpa error:
Gunakan literal floating point:
outcome: $upload_ratio_pct = sum($e.network.sent_bytes) * 100.0 / (sum($e.network.received_bytes) + 1.0)Gunakan
cast.as_int():outcome: $upload_ratio_pct = sum(cast.as_int($e.network.sent_bytes)) * 100 / (sum(cast.as_int($e.network.received_bytes)) + 1)
Pengayaan GeoIP dan konsistensi tertunda
Sistem memprioritaskan kecepatan daripada akurasi langsung pada tahap pengayaan awal (Streaming dan Sensitif terhadap Latensi), yang dapat menyebabkan data hilang dan potensi positif palsu. Sistem akan terus memperkaya data di latar belakang, tetapi data mungkin tidak tersedia saat aturan dijalankan. Hal ini merupakan bagian dari proses konsistensi tertunda yang normal.
Untuk mencegah positif palsu yang disebabkan oleh jeda pengayaan, periksa secara eksplisit bahwa kolom tidak kosong sebelum mengevaluasi nilainya.
Misalnya, pertimbangkan peristiwa aturan ini:
$e.principal.ip_geo_artifact.network.asn = "16509" AND
$e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom"
Aturan ini mengandalkan fakta bahwa peristiwa harus memiliki $e.principal.ip_geo_artifact.network.asn = "16509" DAN $e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom" yang keduanya merupakan kolom yang diperkaya. Jika pengayaan tidak selesai tepat waktu, aturan akan menghasilkan positif palsu.
Untuk menghindari hal ini, pemeriksaan yang lebih baik untuk aturan ini adalah:
$e.principal.ip_geo_artifact.network.asn != "" AND
$e.principal.ip_geo_artifact.network.asn = "16509" AND
$e.principal.ip_geo_artifact.location.country_or_region != "" AND
$e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom"
Aturan ini menghilangkan kemungkinan peristiwa dipicu oleh IP dengan ASN 16509, tetapi berada di luar Inggris Raya. Hal ini meningkatkan presisi aturan secara keseluruhan.
Pelajari cara memecahkan masalah jeda pengayaan.
Pemecahan masalah
Bagian ini menguraikan ekspektasi performa dan memberikan perbaikan mandiri untuk masalah umum saat perilaku deteksi langsung berbeda dengan hasil pengujian.
Acara mendatang
Aturan banyak peristiwa dirancang untuk memproses peristiwa dalam urutan kronologis yang terkait dengan penyerapan. Jika Anda menentukan dan mengaktifkan aturan multi-peristiwa, aturan tersebut tidak akan membuat deteksi untuk peristiwa dengan stempel waktu mendatang, misalnya saat event.timestamp memiliki tanggal dan waktu yang ditetapkan setelah ingest.timestamp.
Jeda pengayaan
Google SecOps memprioritaskan kecepatan penyerapan untuk menampilkan pemberitahuan awal secepat mungkin. Namun, proses pengayaan latar belakang, seperti me-resolve metadata GeoIP, ASN, atau UDM, mengikuti model konsistensi tertunda.
Operasi awal (T₀)
Mesin live dapat mengevaluasi aturan sebelum pengayaan latar belakang selesai. Bergantung pada apakah logika Anda mengandalkan kolom yang diperkaya untuk deteksi atau pengecualian, hal ini dapat menyebabkan perbedaan sementara berikut:
Negatif palsu (jeda deteksi): Ini adalah hasil yang umum. Jika aturan bergantung pada kolom yang diperkaya untuk dipicu (misalnya,
target.user.department == "Finance"), dan kolom tersebut adalahnull, aturan tidak akan cocok selama eksekusi awal.Positif palsu (pengecualian tidak diterapkan): Jika aturan Anda menggunakan kolom yang diperkaya untuk memfilter aktivitas yang diketahui baik (misalnya,
NOT target.ip_geo_country == "US"), aturan tersebut dapat memicu positif palsu karena data "pengecualian" belum diterapkan.
Operasi penyesuaian
Operasi latar belakang ini mengevaluasi ulang data setelah jeda (misalnya, 4 jam atau 30 jam). Tindakan ini akan "menyelaraskan" status deteksi sebagai berikut:
Deteksi terlambat: Peristiwa yang merupakan "negatif palsu" di T₀ kini menghasilkan deteksi setelah pengayaan diselesaikan.
Koreksi: Positif palsu T₀ tetap ada dalam sistem, tetapi data yang diperkaya sepenuhnya terlihat di penampil UDM untuk triase manual.
Menjalankan perbedaan pengujian
Alat Jalankan Pengujian beroperasi pada data historis yang telah direkonsiliasi. Karena data telah diperkaya sepenuhnya saat Anda menjalankan pengujian manual, Anda dapat langsung melihat hasil "penyesuaian". Artinya, Anda tidak akan melihat negatif palsu T₀ atau positif palsu berbasis pengecualian yang terjadi selama proses awal langsung.
Perbaikan error
Gunakan tabel berikut untuk mengatasi perbedaan antara pemberitahuan langsung dan hasil pengujian.
| Masalah | Deskripsi | Perbaikan yang dapat ditindaklanjuti |
|---|---|---|
| Kegagalan pengecualian | Aturan diaktifkan meskipun ada pengecualian (misalnya, != "ASN_123") karena kolom bernilai null selama eksekusi awal. |
Tambahkan pemeriksaan bukan null ke bagian peristiwa untuk memastikan data diperkaya sebelum evaluasi, misalnya:$e.principal.ip_geo_artifact.network.asn != ""
|
| Live dibandingkan dengan pertandingan uji coba | Aturan aktif memicu pemberitahuan, tetapi Jalankan Pengujian pada data yang sama menampilkan "No Results". |
Tambahkan $e.field != "" yang memeriksa semua kolom yang diperkaya (GeoIP, ASN, File Path) untuk menyinkronkan perilaku live dan historis. |
| Metadata tidak ada | Deteksi muncul di dasbor dengan kolom GeoIP atau File Path yang kosong. |
Hal ini sudah diperkirakan untuk operasi T0. Untuk memperbaikinya, sertakan pemeriksaan field != "" atau konfigurasikan penundaan penyelesaian dalam jadwal aturan Anda agar tersedia lebih banyak waktu untuk penyerapan.
|
Validasi dan pengujian
Untuk memverifikasi bahwa aturan menangani pengayaan tertunda dengan benar, lakukan hal berikut:
Identifikasi jeda: Temukan deteksi yang Anda yakini sebagai positif palsu. Di kolom Jenis Deteksi, periksa ikon
<span class="material-icons">lightbulb</span>. Notifikasi tanpa ikon ini berasal dari proses utama yang paling sering mengalami jeda pengayaan.Perbarui logika aturan: Tambahkan pemeriksaan
field != ""untuk semua titik data yang diperkaya yang digunakan dalam logika Anda.
Contoh (jalur file):
$e.target.process.parent_process.file.full_path != ""Uji dan verifikasi:
- Gunakan fitur Jalankan Pengujian untuk memastikan logika Anda masih cocok dengan data historis yang diinginkan.
- Pastikan aturan kini hanya dipicu (atau dikecualikan dengan benar) selama proses penyesuaian setelah kolom pengayaan diisi.
Untuk mengetahui informasi selengkapnya, lihat Memahami penjadwalan eksekusi aturan dan Mengonfigurasi jadwal yang disesuaikan untuk aturan.
Perlu bantuan lain? Dapatkan jawaban dari anggota Komunitas dan profesional Google SecOps.