תחביר של קטע התוצאה
בקטע outcome של שאילתת YARA-L מוגדרים משתני תוצאה שמציינים את הפלט של שאילתת חיפוש ושל שאילתת לוח בקרה, וכן הקשר ומידע נוספים לגבי זיהוי כשהופעל כלל. אפשר להשתמש במשתנים האלה למטרות שונות, כמו הצגת נתונים רלוונטיים בלוחות בקרה ויצירת ציוני סיכון.
הגדרת קטע התוצאה
כדי להגדיר משתנה תוצאה בקטע outcome של שאילתה יחידה, משתמשים בתו $ ואחריו בשם של משתנה. אפשר להגדיר עד 20 משתני תוצאה. השמות של המשתנים הם שרירותיים. לגבי כללים, ערכי התוצאה מחושבים ומצטברים על סמך כל זיהוי.
לכל משתנה של תוצאה מוקצה ערך באמצעות ביטוי.
הכלל הזה מחפש ניסיונות כניסה שנכשלו ממיקום חדש:
rule failed_logins
{
meta:
author = "Security Team"
description = "Detects multiple failed user logins within 10-minute windows."
severity = "HIGH"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.security_result.action = "FAIL"
$user = $e.target.user.userid
match:
$user over 10m
outcome:
$failed_login_count = count($e.metadata.id)
$first_fail_time = min($e.metadata.event_timestamp.seconds)
condition:
#e >= 5
}
בקטע outcome מתבצעות צבירות על משתני האירוע וה-placeholder: ספירת הכניסות שנכשלו, ספירת כתובות ה-IP הייחודיות וקבלת השעה שבה הכניסה נכשלה.
outcome:
$failed_login_count = count($e.metadata.id)
$first_fail_time = min($e.metadata.event_timestamp.seconds)
אם כוללים את משתנה התוצאה המיוחד $risk_score ומאכלסים אותו, הערך שלו (מספר שלם או מספר עשרוני) מוצג בדף Alerts and IoCs לגבי התראות שנוצרו על ידי השאילתה.
אם לא כוללים משתנה $risk_score בקטע outcome של שאילתה, אחת מהגדרות ברירת המחדל הבאות מוגדרת:
אם השאילתה מוגדרת ליצירת התראה, הערך של
$risk_scoreהוא 40.אם השאילתה לא מוגדרת ליצירת התראה, הערך של
$risk_scoreהוא 15.
הערך של $risk_score מאוחסן בשדה security_result.risk_score UDM.
משתנה התוצאה risk_score
Google SecOps Risk Analytics משייך באופן אוטומטי זיהויים והתראות לישויות שקשורות לזיהוי או להתראה. המשתנה risk_scoreoutcome משמש להקצאת כמות סיכון. אם הערך הזה לא מוגדר, המערכת משתמשת בערך ברירת המחדל של הזיהוי או ההתראה. אפשר להגדיר ערכי ברירת מחדל בהגדרות.
כדי לשמור על עקביות בפלטפורמה, מומלץ להשתמש בטווחי הניקוד הבאים כשמקצים risk_score לזיהויים בהתאמה אישית. ההתאמה הזו עוזרת לתקנן את תעדוף ההתראות ואת תהליכי העבודה של התגובה.
| חוּמרה | טווח הציונים | תיאור | דוגמה |
|---|---|---|---|
| התראה – קריטית | 90-100 | פשרה פעילה עם פוטנציאל להשפיע מעבר לחשבון משתמש או נקודת קצה יחידים. נדרשת בדיקה מיידית. | הפעלת Mimikatz בבקר הדומיין. |
| התראות – גבוהה | 80 - 89 | התפשרות פעילה על נקודת קצה או ישות יחידה. צריך לקבל בדיקה מיידית. | שרת ייצור שמתקשר עם C2 מוכר ועדכני. |
| התראות – בינוני | 50 - 79 | בעיה אפשרית באבטחה שדורשת חקירה. לא אושרה פריצה, אבל יכול להיות שהבעיה תועבר לטיפול ברמה גבוהה יותר. | פרטי כניסה שנחשפו, ללא סימנים לשימוש לרעה. |
| לא מופעלת התראה – נמוך | 20 - 49 | אירוע אבטחה עם השפעה נמוכה, שכשמשלבים אותו עם אינדיקטורים או תצפיות אחרים, יכול להוביל לאירוע משמעותי יותר. בדרך כלל לא נדרשת בדיקה, אפשר לשלב עם זיהויים אחרים באמצעות כללים מורכבים כדי ליצור התראה. | סריקת יציאות פנימית. |
| קריטריונים לבדיקה שלא מפעילים התראות | 1 עד 19 | בדרך כלל, זיהויים שמבוססים על מידע שמיועדים ליצירת מודעות למצב של איום. בדרך כלל לא נדרשת בדיקה, אפשר לשלב אותם עם זיהויים אחרים באמצעות כללים מורכבים כדי ליצור התראות. | אירוע התחברות, ללא סימנים לשימוש לרעה. |
מכיוון ש-risk_score הוא משתנה של תוצאה, הכללים יכולים לבטא ניואנסים בהתאם לגורמים כמו מודיעין איומי סייבר או תנאים מקבילים אחרים.
אפשר להשתמש בציוני סיכון של ישויות כדי ליצור התראות מבוססות-סיכון כמעט בזמן אמת. מידע נוסף זמין במאמר סקירה כללית של ניתוח סיכונים.
משתנה התוצאה risk_entity_to_score
בנוסף למשתנה התוצאה risk_score, אפשר גם לציין את משתנה התוצאה risk_entity_to_score. המשתנה הזה מאפשר לכם לציין במפורש אילו ישויות מזיהוי של כלל צריכות לקבל את ציון הסיכון של הזיהוי הזה.
אפשר ליצור כמה משתני risk_entity_to_score על ידי הוספת מחרוזת ייחודית למשתנה והקצאת ציון הסיכון לישויות ספציפיות. לדוגמה:
$risk_entity_to_score_source_asset = $e.principal.asset.hostname
$risk_entity_to_score_targeted_user = $e.target.user.userid
משתני התוצאה האלה מקצים את risk_score שצוין בקטע outcome של הכלל לישויות $e.principal.asset.hostname ו-$e.target.user.userid.
דוגמה: כלל שמזהה כניסות לחשבונות אדמין
הכלל הזה מזהה כניסות מוצלחות לחשבונות אדמין עם הרשאות גבוהות. היא משתמשת במילת המפתח risk_entity_to_score כדי לטרגט באופן מפורש את המשתמש הספציפי שמחובר לחשבון. השימוש במשתנה הזה מבטיח שהזיהוי יתבסס על חישוב של ציון הסיכון שרלוונטי רק למשתמש הזה, ולא לישויות אחרות שמעורבות באירוע, כמו כתובת ה-IP של המקור.
פרטים על כתיבת כלל עם כמה אירועים זמינים במאמר בנושא כלל עם כמה אירועים.
rule suspicious_admin_privilege_escalation {
// This rule matches single events. Rules can also match multiple events within
// the same time window.
meta:
// Allows for storage of arbitrary key-value pairs of rule details, such as
// who wrote it, what it detects on, and version control.
// The "author" and "severity" fields are special, since they are used as
// columns on the rules dashboard. To sort based on these fields on the
// dashboard, add them here.
// Severity value should be "Low", "Medium", or "High"
author = "analyst123"
description = "Detects suspicious login to critical admin accounts."
severity = "HIGH"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.target.user.attribute.roles.name = "ADMIN"
$e.security_result.summary = "Successful login with high-privilege access"
outcome:
// Multi-event rules require an aggregation function
// For example, risk_score = max(0)
// See https://cloud.google.com/chronicle/docs/detection/yara-l-2-0-overview#outcome_conditionals_example_rule
$risk_score = 80
$risk_entity_to_score = $e.target.user.userid
$source_ip = array_distinct($e.principal.ip)
condition:
$e
}
דוגמה: כלל שמנטר חיבורים לרשת פנימית
הכלל הזה בודק תנועה רוחבית על ידי זיהוי חיבורים לרשת בין פלחים של רשת פנימית. הוא משתמש ב-$risk_entity_to_score prefix כדי להקצות סיכון לכמה ישויות במסגרת זיהוי אחד. ציון הסיכון של המארח שיזם את הפעולה ($risk_entity_to_score_source_asset) ושל המשתמש שהיה היעד שלה ($risk_entity_to_score_targeted_user) מתעדכן. מנוע הסיכון מתעד משתני תוצאה אחרים שלא משתמשים בקידומת הספציפית הזו להקשר, אבל מתעלם מהם (ציוני הסיכון שלהם נשארים זהים).
פרטים על כתיבת כלל מרובה אירועים זמינים במאמרים בנושא כלל מרובה אירועים וכלל לדוגמה עם תנאים לתוצאה.
rule lateral_movement_network_connection {
// This rule matches single events. You can also match multiple events within
// the same time window.
meta:
// Allows for storage of arbitrary key-value pairs of rule details (for
// example, who wrote it, what it detects on, and version control).
// The "author" and "severity" fields are special, since they are used as
// columns on the rules dashboard. To sort based on these fields on the
// dashboard, add them here. Severity value should be "Low", "Medium" or "High"
author = "analyst123"
description = "Detects lateral movement attempts between internal segments."
severity = "MEDIUM"
events:
$e.metadata.event_type = "NETWORK_CONNECTION"
$e.principal.asset.hostname != ""
$e.target.user.userid != ""
// Can also use: $e.target.ip = /10\..*/
net.ip_in_range_cidr($e.target.ip, "10.0.0.0/8")
outcome:
// Multi-event rules require an aggregation function
// for example, risk_score = max(0)
// See https://docs.cloud.google.com/chronicle/docs/yara-l/yara-l-2-0-examples#outcome-conditionals-example-rule
$risk_score = 50
$risk_entity_to_score_source_asset = $e.principal.asset.hostname
$risk_entity_to_score_targeted_user = $e.target.user.userid
$target_ip_info = array_distinct($e.target.ip)
condition:
$e
}
סוגי נתונים של משתני התוצאה
לכל משתנה תוצאה יכול להיות סוג נתונים שונה, שנקבע לפי הביטוי שמשמש לחישוב שלו. סוגי נתוני התוצאות הבאים נתמכים ב-Google SecOps:
- מספר שלם
- צף
- מחרוזת
- רשימות של מספרים שלמים
- רשימות של מספרים ממשיים
- רשימות של מחרוזות
לוגיקה של משפטי תנאי
אפשר להשתמש בלוגיקה מותנית כדי לחשב את הערך של תוצאה. מגדירים תנאים באמצעות תבנית התחביר הבאה:
if(BOOL_CLAUSE, THEN_CLAUSE)
if(BOOL_CLAUSE, THEN_CLAUSE, ELSE_CLAUSE)
אפשר לקרוא ביטוי מותנה כך: 'אם BOOL_CLAUSE הוא true, אז מחזירים THEN_CLAUSE, אחרת מחזירים ELSE_CLAUSE'.
הערך של BOOL_CLAUSE חייב להיות בוליאני. ביטוי BOOL_CLAUSE דומה לביטויים שבקטע events. לדוגמה, הוא יכול לכלול:
שמות שדות ב-UDM עם אופרטור השוואה:
if($context.graph.entity.user.title = "Vendor", 100, 0)משתנה placeholder שהוגדר בקטע
events:if($severity = "HIGH", 100, 0)משתנה תוצאה נוסף שהוגדר בקטע
outcome:if($risk_score > 20, "HIGH", "LOW")פונקציות שמחזירות ערך בוליאני:
if(re.regex($e.network.email.from, `.*altostrat.com`), 100, 0)חיפוש ברשימת הפניות:
if($u.principal.hostname in %my_reference_list_name, 100, 0)השוואה בין צבירות:
if(count($login.metadata.event_timestamp.seconds) > 5, 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 אם סוג הנתונים הוא מחרוזת או אם THEN_CLAUSE הוא משתנה placeholder או משתנה תוצאה.
פעולות מתמטיות
אפשר להשתמש בפעולות מתמטיות כדי לחשב נתונים מסוג integer או float בקטעים outcomeוevents של שאילתה. Google Security Operations תומך בפעולות חיבור, חיסור, כפל, חילוק ומודולו כאופרטורים ברמה העליונה בחישוב.
קטע הקוד הבא הוא דוגמה לחישוב בקטע outcome:
outcome:
$risk_score = max(100 + if($severity = "HIGH", 10, 5) - if($severity = "LOW", 20, 0))
מותר לבצע פעולות מתמטיות על סוגי האופרנדים הבאים, כל עוד כל אופרנד וכל הביטוי האריתמטי מצטברים בצורה נכונה (ראו צבירות):
- שדות מספריים של אירועים
- משתני פלייסהולדר מספריים שמוגדרים בקטע
events - משתני תוצאה מספריים שהוגדרו בקטע
outcome - פונקציות שמחזירות מספרים שלמים או מספרים עשרוניים
- צבירות שמחזירות מספרים שלמים או מספרים עשרוניים
אסור להשתמש בפעולת מודולו על מספרים ממשיים.
משתני פלייסהולדר בתוצאות
כשמחשבים משתני תוצאה, אפשר להשתמש במשתני placeholder שהוגדרו בקטע events של השאילתה. בדוגמה הזו, נניח ש-$email_sent_bytes הוגדר בקטע events (אירועים) של הכלל:
דוגמה: אירוע יחיד ללא קטע התאמה
// No match section, so this is a single-event query. 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 query 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משתני התוצאה בביטויי הקצאת התוצאה
אפשר להשתמש במשתני תוצאה כדי לגזור משתני תוצאה אחרים, בדומה למשתני placeholder שמוגדרים בקטע events. אפשר להפנות למשתנה של תוצאה בהקצאה של משתנה אחר של תוצאה באמצעות טוקן $ ואחריו שם המשתנה. צריך להגדיר את משתני התוצאה לפני שאפשר להפנות אליהם בטקסט של השאילתה. כשמשתמשים במשתני תוצאה בביטוי של הקצאה, אסור לצבור אותם (ראו צבירות).
בדוגמה הבאה, משתנה התוצאה $risk_score מקבל את הערך שלו ממשתנה התוצאה $event_count:
דוגמה: משתנה תוצאה שנגזר ממשתנה תוצאה אחר
match: // This is a multi event query with a match section. $hostname over 5m outcome: // Aggregates all timestamp on login events in the 5 minute match window. $event_count = count($login.metadata.event_timestamp.seconds) // $event_count cannot be aggregated again. $risk_score = if($event_count > 5, "SEVERE", "MODERATE") // This is the equivalent of the 2 outcomes combined. $risk_score2 = if(count($login.metadata.event_timestamp.seconds) > 5, "SEVERE", "MODERATE") condition: $e
אפשר להשתמש במשתני תוצאה בכל סוג של ביטוי בצד שמאל של הקצאת תוצאה, חוץ מהביטויים הבאים:
- צבירות
Arrays.length()בקשות להפעלת פונקציות- עם מקשי הצירוף
anyאוall
צבירות
שדות חוזרים של אירועים הם ערכים לא סקלריים. כלומר, משתנה יחיד מצביע על כמה ערכים. לדוגמה, משתנה השדה של האירוע $e.target.ip הוא שדה חוזר ויכול להיות לו אפס, ערך אחד או כמה ערכים של כתובת IP. זהו ערך לא סקלרי. לעומת זאת, משתנה השדה של האירוע $e.principal.hostname הוא לא שדה חוזר ויש לו רק ערך אחד (כלומר, ערך סקלרי).
באופן דומה, גם שדות אירועים לא חוזרים וגם שדות אירועים חוזרים שמשמשים בקטע outcome של שאילתה עם חלון התאמה הם ערכים לא סקלריים.
דוגמה: קיבוץ אירועים עם קטע התאמה ושדה לא חוזר
השאילתה הבאה מקבצת אירועים באמצעות הקטע match ומתייחסת לשדה אירוע שלא חוזר על עצמו בקטע outcome:
rule OutcomeAndMatchWindow{
...
match:
$userid over 5m
outcome:
$hostnames = array($e.principal.hostname)
...
}כל חלון של 5 דקות שבו השאילתה מופעלת עשוי להכיל אפס, אירוע אחד או הרבה אירועים. החישוב של הקטע 'תוצאה' מתבצע על כל האירועים בחלון התאמה. כל משתנה של שדה אירוע שאליו מתייחסים בקטע
outcome יכול להצביע על אפס, על ערך אחד או על הרבה ערכים של השדה בכל אירוע בחלון ההתאמה.
לדוגמה, אם חלון של 5 דקות מכיל 5 אירועים מסוג $e, בקטע התוצאה יצוינו חמישה שמות מארחים שונים.$e.principal.hostname המשתנה של שדה האירוע
$e.principal.hostname מטופל כערך לא סקלרי בקטע outcome של השאילתה הזו.
משתני התוצאה צריכים תמיד להניב ערך סקלרי יחיד, ולכן כל ערך לא סקלרי שהקצאת התוצאה תלויה בו צריך לעבור צבירה כדי להניב ערך סקלרי יחיד. בקטע של תוצאה, הערכים הבאים הם לא סקלריים וחייבים להיות מצטברים:
- שדות אירועים (חוזרים או לא חוזרים) כשהשאילתה משתמשת בקטע
match - משתני placeholder של אירועים (חוזרים או לא חוזרים) כשהשאילתה משתמשת בקטע
match - שדות אירועים חוזרים כשהשאילתה לא משתמשת בקטע
match - placeholder לאירוע חוזר כשלא משתמשים בקטע
matchבשאילתה
אפשר להשתמש בפונקציות צבירה כדי לעטוף שדות אירועים סקלריים, פלייס הולדרים סקלריים וקבועים בשאילתות שלא כוללות קטע match. עם זאת, ברוב המקרים, הצבירות האלה מחזירות את הערך העטוף, ולכן הן מיותרות. יוצאת דופן היא הצבירה array(), שבה אפשר להשתמש כדי להמיר ערך סקלרי למערך באופן מפורש.
משתני התוצאה מטופלים כמו צבירות: אסור לצבור אותם מחדש כשמפנים אליהם בהקצאת תוצאה אחרת.
אפשר להשתמש בפונקציות הצבירה הבאות:
| פונקציית צבירה | תיאור |
|---|---|
max() |
הפונקציה מחזירה את הערך המקסימלי מכל הערכים האפשריים. היא פועלת רק עם מספרים שלמים ומספרים עשרוניים. |
min() |
הפונקציה מחזירה את המינימום מכל הערכים האפשריים. פועל רק עם מספרים שלמים ומספרים עשרוניים. |
sum() |
הפונקציה מחזירה את הסכום של כל הערכים האפשריים. פועל רק עם מספרים שלמים ומספרים עשרוניים. |
count_distinct() |
הפונקציה אוספת את כל הערכים האפשריים, ואז מחזירה את מספר הערכים האפשריים הייחודיים. |
count() |
הפונקציה פועלת כמו count_distinct(), אבל מחזירה ספירה לא ייחודית של ערכים אפשריים. |
array_distinct() |
הפונקציה אוספת את כל הערכים הייחודיים האפשריים, ואז מחזירה רשימה של הערכים האלה. הרשימה של הערכים הייחודיים נחתכת ל-1,000 רכיבים אקראיים. קודם מתבצעת הסרת הכפילויות כדי לקבל רשימה ייחודית, ואז מתבצעת החיתוך. |
array() |
הפונקציה פועלת כמו array_distinct(), אבל מחזירה רשימה לא ייחודית של ערכים. בנוסף, הוא חותך את רשימת הערכים ל-1,000 רכיבים אקראיים. |
הפונקציה aggregate חשובה כשכלל כולל קטע condition שמציין שצריכים להתקיים כמה אירועים, כי הפונקציה aggregate תפעל על כל האירועים שיצרו את הזיהוי.
דוגמה: תנאי לכמה אירועים
הדוגמה הבאה מציגה תנאי למספר אירועים. אם בקטע התוצאה והתנאי מופיעים:
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
בקטע `condition` צריך לציין יותר מ-`event` אחד לכל זיהוי, ולכן הפונקציות המצטברות יפעלו על כמה אירועים. נניח שהאירועים הבאים יצרו זיהוי אחד:
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אי אפשר להפנות למשתנה placeholder חדש שלא הוגדר כבר בקטעeventsאו בקטעoutcome.בקטע
outcomeאי אפשר להשתמש במשתני אירועים שלא הוגדרו בקטעevents.בקטע
outcomeאפשר להשתמש בשדה אירוע שלא נעשה בו שימוש בקטעevents, בתנאי שמשתנה האירוע שאליו שייך שדה האירוע כבר הוגדר בקטעevents.בקטע
outcomeאפשר לקשר רק בין משתני אירוע שכבר קושרו בקטעevents. קשרים נוצרים כשמשווים בין שני שדות אירוע ממשתני אירוע שונים.
דוגמאות לקטע outcome מופיעות במאמר סקירה כללית של YARA-L 2.0.
פרטים נוספים על ביטול כפילויות של זיהויים באמצעות הקטע outcome זמינים במאמר בנושא יצירת ניתוח נתונים מבוסס-הקשר.
המאמרים הבאים
מידע נוסף
- ביטויים, אופרטורים ומבנים שמשמשים ב-YARA-L 2.0
- פונקציות ב-YARA-L 2.0
- יצירת כללי זיהוי מורכבים
- דוגמאות: שאילתות YARA-L 2.0
הבעיה עדיין לא נפתרה? קבלת תשובות מחברי הקהילה וממומחי Google SecOps.