התחביר של קטע התוצאה

נתמך ב:

בקטע 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_score משמש להקצאת רמת סיכון. אם לא מגדירים את הערך הזה, המערכת משתמשת בערך ברירת המחדל לזיהוי או להתראה. אפשר להגדיר ערכי ברירת מחדל בהגדרות.

כדי להבטיח עקביות בפלטפורמה, מומלץ להשתמש בטווחי הניקוד הבאים כשמקצים risk_score לזיהויים בהתאמה אישית. ההתאמה הזו עוזרת ליצור סטנדרטיזציה של תהליכי העבודה של תגובה והגדרת עדיפות להתראות.

חוּמרה טווח הניקוד תיאור דוגמה
התראה – קריטית ‫90-100 פשרה פעילה עם פוטנציאל להשפיע מעבר לחשבון משתמש יחיד או לנקודת קצה יחידה. נדרשת בדיקה מיידית. הכלי Mimikatz הופעל בבקר הדומיין.
התראות – גבוה ‫80-89 התפשרות פעילה על נקודת קצה או ישות יחידה. צריך לקבל בדיקה מיידית. שרת ייצור שמתקשר עם C2 עדכני ומוכר.
התראות – בינוני ‫50 - 79 בעיה אפשרית באבטחה שנדרשת חקירה לגביה. לא אושר שהייתה פריצה, אבל אפשר להעביר את הבעיה לטיפול ברמה גבוהה יותר. פרטי כניסה שנחשפו, ללא סימני שימוש לרעה.
לא נשלחת התראה – נמוך ‫20-49 אירוע אבטחה עם השפעה נמוכה, שכשמשלבים אותו עם אינדיקטורים או תצפיות אחרים, יכול להוביל לאירוע משמעותי יותר. בדרך כלל לא נדרשת בדיקה, אפשר לשלב עם זיהויים אחרים באמצעות כללים מורכבים כדי ליצור התראה. סריקת יציאות פנימית.
תצפיות שלא מפעילות התראות ‫1 עד 19 באופן כללי, זיהויים שמבוססים על מידע נועדו ליצור מודעות למצב של איום. בדרך כלל לא נדרשת בדיקה. אפשר לשלב אותה עם זיהויים אחרים באמצעות כללים מורכבים כדי ליצור התראות. אירוע התחברות, ללא סימנים לשימוש לרעה.

מכיוון ש-risk_score הוא משתנה של תוצאה, הכללים יכולים לבטא ניואנסים בהתאם לגורמים כמו מודיעין איומי סייבר או תנאים מקבילים אחרים.

אפשר להשתמש בחישוב של ציון סיכונים של ישויות כדי ליצור התראות מבוססות-סיכון כמעט בזמן אמת. מידע נוסף זמין במאמר סקירה כללית של ניתוח סיכונים.

משתנה התוצאה risk_entity_to_score

כברירת מחדל, Google SecOps מקצה את חישוב של ציון סיכונים של זיהוי לכל הישויות באירועים שנדגמו. היא גם מקצה את הניקוד לכל הישויות שמופיעות בקטעים match ו-outcome של הכלל. כדי להקצות את ציון הסיכון לישויות ספציפיות במקום זאת, צריך לציין את משתנה התוצאה risk_entity_to_score בנוסף ל-risk_score. חישוב של ציון סיכונים תומך בישויות user ו-asset. אין תמיכה בסוגי הישויות RESOURCE או GROUP.

אפשר ליצור כמה משתני 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://docs.cloud.google.com/chronicle/docs/yara-l/yara-l-2-0-examples#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 נכון, מחזירים את 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 בתוצאות

כשמחשבים משתני תוצאה, אפשר להשתמש במשתני 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() aggregation, שאפשר להשתמש בו כדי להמיר באופן מפורש ערך סקלרי למערך.

משתני התוצאה מטופלים כמו צבירות: אסור לצבור אותם מחדש כשמפנים אליהם בהקצאת תוצאה אחרת.

אפשר להשתמש בפונקציות הצבירה הבאות:

פונקציית צבירה תיאור
max() הפונקציה מחזירה את הערך המקסימלי מבין כל הערכים האפשריים. הפונקציה פועלת רק עם מספרים שלמים ומספרים עשרוניים.
min() הפונקציה מחזירה את המינימום מכל הערכים האפשריים. הפונקציה פועלת רק עם מספרים שלמים ומספרים עשרוניים.
sum() הפונקציה מחזירה את הסכום של כל הערכים האפשריים. הפונקציה פועלת רק עם מספרים שלמים ומספרים עשרוניים.
count_distinct() הפונקציה אוספת את כל הערכים האפשריים, ואז מחזירה את מספר הערכים האפשריים הייחודיים.
count() הפונקציה פועלת כמו count_distinct(), אבל מחזירה ספירה לא ייחודית של ערכים אפשריים.
array_distinct() הפונקציה אוספת את כל הערכים האפשריים השונים, ואז מחזירה רשימה של הערכים האלה. קודם מתבצעת ביטול כפילויות כדי ליצור רשימה ייחודית, ואז מתבצעת חיתוך. בחיפוש Google, הרשימה נחתכת למקסימום של 1,000 רכיבים אקראיים. במרכזי הבקרה ובכללים, הרשימה נחתכת למקסימום של 25 רכיבים אקראיים.
array() הפונקציה פועלת כמו array_distinct(), אבל מחזירה רשימה של ערכים לא ייחודיים. בחיפוש Google, הרשימה נחתכת למקסימום של 1,000 רכיבים אקראיים. במרכזי הבקרה ובכללים, הרשימה נחתכת למקסימום של 25 רכיבים אקראיים.

פונקציית צבירה חשובה כשכלל כולל קטע condition שמציין שצריכים להתקיים כמה אירועים, כי פונקציית צבירה תפעל על כל האירועים שיצרו את הזיהוי.

דוגמה: תנאי לכמה אירועים

הדוגמה הבאה מציגה תנאי לכמה אירועים. אם בקטע של התוצאה והתנאי מופיעים:

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 מופיעים במאמר בנושא יצירת ניתוח נתונים מבוסס-הקשר.

המאמרים הבאים

מידע נוסף

הבעיה עדיין לא נפתרה? קבלת תשובות מחברי הקהילה וממומחי Google SecOps.