זיהוי ובלו טים
מה זה SIEM? לוגים, שאילתות והתראות
SIEM אוסף לוגים, מנרמל אותם, מריץ חוקי קורלציה ומעלה התראות לטריאז׳. הצינור המלא עם דוגמה שאפשר להריץ.
כותבים חוק Sigma לכשלי התחברות ב-Windows, מאמתים אותו, ממירים ל-Splunk ובודקים מול אירועים שאמורים להתאים ואירועים שלא.
Sigma הוא פורמט פתוח, שלא קשור לאף יצרן, לתיאור זיהוי. כותבים את הלוגיקה פעם אחת בקובץ YAML קטן, וממיר הופך אותה לשפת השאילתות של ה-SIEM או של פלטפורמת הלוגים שרצה אצלך בפועל. ל-Splunk, ל-Elastic, ל-Microsoft Sentinel ולבקאנדים נוספים יש ממירים, ואותו חוק יכול לכוון לכמה מהם.
את הפורמט מתחזק פרויקט SigmaHQ. המפרט נמצא במאגר sigma-specification, והתיעוד של החוקים ב-sigmahq.io מסביר את השדות אחד אחד. אם יודעים לקרוא אירוע של Windows, החלק הקשה כבר מוכר. חוק Sigma הוא רק דרך לומר "האירוע הזה, עם ערכי השדות האלה" בצורה שאנשים אחרים וכלים אחרים יכולים לקרוא.
רוב לוגיקת הזיהוי נכתבת ישירות בשפת השאילתות של מוצר אחד. חיפוש של Splunk לא רץ ב-Sentinel, ושאילתת KQL לא רצה ב-Splunk. כשצוות עובר פלטפורמה, או כשקהילה משתפת זיהוי, צריך לכתוב את הלוגיקה מחדש מאפס. זה איטי, והשכתוב מכניס טעויות.
Sigma מפריד בין לוגיקת הזיהוי לשפת השאילתות. החוק מתאר את מקור הלוגים ואת התנאי, והבקאנד הופך את זה לשאילתה. יש לזה שתי תוצאות:
המאמר הזה עוסק בנקודה השנייה. חוק Sigma שעובר פרסור והמרה עדיין לא גמור: התחביר שלו תקין, וזה הכול. הוא נעשה שימושי כשאפשר להראות שהוא מתריע על האירועים הנכונים ושותק על האירועים שצריך להתעלם מהם.
זה החוק שנבנה במעבדה, עם הסבר על כל שדה.
title: Failed Logon Event
id: bd37e49d-15ab-4e88-a3fb-53594e831b27
status: experimental
description: Detects Windows Security event 4625 (an account failed to log on).
logsource:
product: windows
service: security
detection:
selection:
EventID: 4625
condition: selection
falsepositives:
- Users mistyping passwords
level: low
tags:
- attack.credential-access
- attack.t1110ה-UUID שלך יהיה שונה. צריך ליצור UUID משלך בכל ספריית UUID, למשל python -c "import uuid; print(uuid.uuid4())", ולשמור עליו גם כשעורכים את החוק בהמשך. לפי השדה id כלים אחרים עוקבים אחרי אותו חוק לאורך גרסאות.
stable, test, experimental, deprecated, unsupported. חוק חדש שלא נבדק בסביבה אמיתית מקומו בסטטוס experimental.product: windows עם service: security מצביע על לוג Security של Windows. שדות אחרים, כמו category, מאפשרים לתאר סוג של לוגים, למשל יצירת תהליכים, בלי לנקוב בערוץ המדויק.selection, הוא קבוצה של תנאים על שדות. שמות השדות הם אלה שמקור הלוגים משתמש בהם, והערכים מותאמים מול השדות האלה.selection לבדו פירושו "אירועים שמתאימים לבלוק selection". בהמשך מוסיפים בלוקי סינון ומחברים אותם עם and ועם not.informational, low, medium, high, critical. בוחרים את הרמה לפי המשמעות של התראה בסביבה שלך, בלי קשר למידת הריגוש שהטכניקה מעוררת.attack. מצביעה על טקטיקה של MITRE ATT&CK, והתגית attack.t1110 מצביעה על הטכניקה T1110, Brute Force.שתי הערות על החוק הזה. ראשית, EventID הוא שם השדה בעולם של Sigma, והוא מתייחס ל-Event ID שרואים ב-Event Viewer. שנית, level: low הוא החלטה. כשל התחברות בודד הוא דבר נפוץ. החוק בצורתו הנוכחית מתריע על כל 4625, ולכן רמה נמוכה היא נקודת הפתיחה הכנה עד שמוסיפים סף.
Sigma לא מכיר את ה-SIEM שלך. הבקאנד מכיר. הממיר קורא את הזיהוי, מפעיל processing pipeline שמשנה שמות שדות ומוסיף מגבלות של אינדקס או מקור, וכותב שאילתה בשפת היעד.
Processing pipeline הוא אוסף של כללי מיפוי. הוא עונה על שאלות כמו: מה שם השדה של Event ID ב-Splunk, באיזה אינדקס נמצאים אירועי Windows Security, ובאיזה sourcetype השאילתה צריכה לחפש. בלי pipeline, ממיר עלול לפלוט את שם השדה של Sigma כפי שהוא, ולעתים קרובות הפלט הזה לא שמיש בפלטפורמה שבשימוש.
לכל בקאנד יש pipelines משלו. חלקם חובה, והממיר מסרב להמשיך בלעדיהם אלא אם מבקשים ממנו במפורש לדלג על ה-pipeline. זה יופיע במעבדה.
הרעיון פשוט: החוק נשאר אותו חוק, וה-pipeline מתאים אותו לפלטפורמה. במעבר מ-Splunk ל-SIEM אחר מחליפים את הבקאנד ואת ה-pipeline, והזיהוי עצמו לא משתנה.
המעבדה רצה על המחשב שלך. לא צריך דומיין, domain controller או מערכת יעד כלשהי. העבודה כאן היא כתיבה והמרה של חוק. לא מייצרים כאן כשלי התחברות מול שום דבר, ואין לנסות לעשות זאת מול מערכת שאינה בבעלותך או שאין לך הרשאה בכתב לבדוק אותה.
המעבדה הורצה על Windows 11 עם Git Bash, עם Python 3.12 ועם לוג Windows Security בברירת המחדל. הפקודות זהות ב-Linux וב-macOS, חוץ מהנתיב לסביבה הווירטואלית.
יש ליצור תיקייה למעבדה, ואז להריץ:
python3 -m venv .venv
. .venv/bin/activate
pip install sigma-cliב-Windows עם Git Bash, ייתכן שהפקודה python3 לא נמצאת ב-PATH. אפשר להשתמש בנתיב המלא להתקנה של Python 3.12, או בפקודה py -3.12. בנוסף, הסביבה הווירטואלית שמה את הסקריפטים שלה בתיקייה .venv/Scripts במקום .venv/bin, ולכן מפעילים אותה כך:
. .venv/Scripts/activateבדיקת ההתקנה:
sigma versionבמחשב שעליו נכתב המאמר הותקנה החבילה sigma-cli 4.0.0 עם pysigma 2.0.2 ו-Python 3.12.10. אצלך הגרסאות עשויות להיות חדשות יותר. את פלט הגרסה צריך לרשום בהערות שלך, ולא את המספרים שכאן.
יש ליצור קובץ בשם failed_logon.yml עם התוכן מהסעיף הקודם, וליצור UUID משלך עבור השדה id. שומרים את הקובץ ב-UTF-8, בלי טאבים בהזחה של ה-YAML.
sigma check failed_logon.ymlהפקודה sigma check מפרסרת את הקובץ ומריצה ולידטורים. היא תופסת שדה חסר, תגית פגומה, סטטוס או רמה לא מוכרים, וכמה בעיות סגנון.
במחשב שעליו נכתב המאמר, השלב הזה לא הסתיים. ולידטור התגיות טוען את נתוני MITRE ATT&CK מהרשת. הבקשה החזירה HTTP 504 gateway timeout, והשגיאה חזרה בכל ניסיון. הפלט היה traceback שהסתיים בשורה RuntimeError: Failed to load MITRE ATT&CK data, וקוד היציאה היה 1.
זו תלות ברשת ולא שגיאה בחוק. אחרי שהנתונים נטענים, אמורה להופיע תוצאת מעבר או רשימת בעיות מהוולידטורים. אם הבדיקה נכשלת עם אותה הודעה על MITRE, אפשר להריץ שוב מאוחר יותר, או מרשת שמגיעה לנתונים במקור. אין לסמן את החוק כמאומת לפני שהבדיקה מסתיימת.
אם הבדיקה מדווחת על בעיות, צריך לקרוא כל אחת מהן ולתקן את החוק, ולא את הוולידטור. בעיה בתגית היא בדרך כלל טעות הקלדה, למשל attack.t1100 במקום attack.t1110.
sigma plugin install splunkבמחשב שעליו נכתב המאמר, הפקודה הדפיסה Successfully installed plugin 'splunk' ואת pySigma version is compatible with sigma-cli.
sigma convert -t splunk --without-pipeline failed_logon.ymlהפלט היה:
Parsing Sigma rules
EventID=4625כך נראה החוק לפני כל מיפוי ל-Splunk. שם השדה הוא עדיין השם של Sigma, EventID. בחיפוש ב-Splunk על אירועי Windows משתמשים בדרך כלל בשדה EventCode ובמקור, ולכן השאילתה הזו לא תמצא את האירועים הרצויים בהתקנה רגילה של ה-Windows add-on.
מנסים את אותה המרה בלי הדגל --without-pipeline:
sigma convert -t splunk failed_logon.ymlהממיר עצר והסביר שהבקאנד של Splunk דורש processing pipeline. ההודעה אמרה למשתמש להוסיף את --without-pipeline רק אם הוא יודע מה הוא עושה. כאן ה-pipeline הוא חובה, ולכן הממיר מסרב להפיק שאילתה בלעדיו. כדאי לקרוא את ההודעה הזו כמנגנון בטיחות.
עכשיו מוסיפים את ה-pipeline של Windows:
sigma list pipelines
sigma convert -t splunk -p splunk_windows failed_logon.ymlהרשימה הציגה שלושה pipelines של Splunk: splunk_windows, splunk_sysmon_acceleration, splunk_cim. ההמרה עם splunk_windows הדפיסה:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625ה-pipeline שינה שני דברים. הוא מיפה את EventID אל EventCode, והוסיף מגבלת מקור של WinEventLog:Security. התוצאה היא שאילתה שמופע Splunk עם ה-Windows add-on יכול להריץ. האינדקס וה-sourcetype אצלך עשויים להיות אחרים, אז זו נקודת התחלה, וצריך לבדוק אותה מול הנתונים שלך.
ניסיון נוסף עם ה-pipeline של CIM נכשל עם ההודעה Rule type not yet supported by the Splunk data model CIM pipeline!. לא כל חוק עובר המרה בכל pipeline. כשל כזה הוא מידע שימושי: החוק או הבקאנד לא מתאימים למיפוי שביקשת.
במאמר על לוג האירועים של Windows בחנו אירוע ב-Event Viewer. פותחים את האירוע הזה שוב ומשווים אותו לשאילתה:
Event ID. בפלט של Splunk הוא מופיע בתור EventCode, כי ה-pipeline ממפה אותו לשם שבו משתמש ה-Windows add-on.source בשאילתה, עם הערך WinEventLog:Security, מקביל לערוץ Security שקראת ב-Event Viewer.אם ה-Event ID של האירוע שלך ב-Event Viewer שונה מ-4625, החוק לא יתאים לו, וזו התנהגות נכונה. החוק עוסק בכשלי התחברות, ולא בכל אירוע בלוג.
חוק שעובר המרה הוא עדיין ניחוש עד שבודקים אותו. לבדיקה המינימלית יש שני חצאים:
בלי השליליים אין ראיה לכך שהחוק ספציפי. בלי החיוביים אין ראיה לכך שהוא עובד בכלל.
במעבדה הזו הבדיקה משתמשת בקובץ fixture קטן של אירועים סינתטיים, events.json, עם חמש רשומות: שני אירועי 4625 ושלושה אירועים שלא אמורים להתאים. הסקריפט טוען את בלוק selection של החוק ובודק כל אירוע. זו בדיקה מפושטת. היא מראה שלוגיקת ה-selection עושה את מה שכתבת, ואינה מחליפה בדיקה של השאילתה המומרת על נתונים אמיתיים.
import json, sys
import yaml
rule = yaml.safe_load(open("failed_logon.yml", encoding="utf-8"))
events = json.load(open("events.json", encoding="utf-8"))
selection = rule["detection"]["selection"]
def selection_matches(event):
return all(str(event.get(k)) == str(v) for k, v in selection.items())
failures = 0
for ev in events:
got = "match" if selection_matches(ev) else "no match"
ok = got == ev["expect"]
failures += 0 if ok else 1
print(f"{'PASS' if ok else 'FAIL'} {ev['name']:<40} expected={ev['expect']:<9} got={got}")
print(f"{len(events) - failures}/{len(events)} passed")
sys.exit(1 if failures else 0)קובץ ה-fixture נראה כך:
[
{"name": "known-bad: failed logon", "EventID": 4625, "expect": "match"},
{"name": "known-bad: failed logon, second try", "EventID": 4625, "expect": "match"},
{"name": "known-good: successful logon", "EventID": 4624, "expect": "no match"},
{"name": "known-good: logoff", "EventID": 4634, "expect": "no match"},
{"name": "known-good: process creation", "EventID": 4688, "expect": "no match"}
]הרצה:
python test_failed_logon.pyבמחשב שעליו נכתב המאמר, הפלט היה:
PASS known-bad: failed logon expected=match got=match
PASS known-bad: failed logon, second try expected=match got=match
PASS known-good: successful logon expected=no match got=no match
PASS known-good: logoff expected=no match got=no match
PASS known-good: process creation expected=no match got=no match
5/5 passedשווה לשים לב מה הבדיקה הזו מראה ומה לא. היא מראה שהחוק מתאים לאירועים שהוא צריך להתאים להם ומתעלם מאלה שהוא צריך להתעלם מהם. היא לא מראה שהחוק טוב. חוק שהיה מתאים לכל 4625 היה עובר את הבדיקה, כי כל 4625 ב-fixture אמור להתאים. הבדיקה שימושית, אבל רק כרף תחתון.
הצעד הבא, בסביבה אמיתית, הוא להריץ את שאילתת ה-Splunk המומרת על פרק זמן של לוגי Windows Security שידוע שיש בו כשלי התחברות ופעילות רגילה. סופרים את התוצאות ופותחים מדגם מהן. כל תוצאה צריכה להיות אירוע 4625. אם השאילתה מחזירה תוצאות עם Event IDs אחרים, ה-pipeline או מיפוי השדות שגויים.
החוק הזה מתריע על כל 4625. סיסמה אחת שהוקלדה לא נכון יוצרת התראה, וכך גם חשבון שירות עם סיסמה שפג תוקפה ומנסה שוב כל דקה. ניסיון brute force הוא הרבה כשלים מול אותו חשבון בזמן קצר, והגרסה הראשונה לא יודעת לבטא את זה.
Sigma מטפל בזה באמצעות correlation rules, שמוגדרים במפרט נפרד. חוק correlation לא מתאים אירועים בעצמו. הוא מצביע על חוק בסיס אחד או יותר לפי name, מקבץ את ההתאמות שלהם לפי שדה, ומחיל ספירה על חלון זמן. הסוג event_count סופר התאמות, והביטוי condition: gte: 5 פירושו חמש או יותר. שמים את שני החוקים בקובץ אחד, מפרידים ביניהם עם ---, ונותנים לחוק הבסיס name:
title: Failed Logon Event
name: failed_logon_event
id: bd37e49d-15ab-4e88-a3fb-53594e831b27
status: experimental
description: Detects Windows Security event 4625 (an account failed to log on).
logsource:
product: windows
service: security
detection:
selection:
EventID: 4625
condition: selection
falsepositives:
- Users mistyping passwords
level: low
tags:
- attack.credential-access
- attack.t1110
---
title: Many Failed Logons For One Account
id: 3f6c1d52-8a0e-4b7e-9d2a-6c41e0b7a915
status: experimental
description: Five or more failed logons for the same target account within ten minutes.
correlation:
type: event_count
rules:
- failed_logon_event
group-by:
- TargetUserName
timespan: 10m
condition:
gte: 5
falsepositives:
- Service accounts with an expired password
level: mediumשומרים בשם multi.yml וממירים עם אותו pipeline:
sigma convert -t splunk -p splunk_windows multi.ymlהפלט היה:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625
| bin _time span=10m
| stats count as event_count by _time TargetUserName
| search event_count >= 5השורה הראשונה היא חוק הבסיס. שלוש השורות שאחריה הן ה-correlation: חלוקת האירועים לחלונות של עשר דקות, ספירה לפי TargetUserName, ושמירה של הקבוצות עם חמישה או יותר. המספרים 5 ו-10 דקות הם ערכים זמניים. צריך לבחור אותם לפי הנתונים שלך, ולבדוק את התוצאה מול אותם אירועי known-good ו-known-bad. לא כל בקאנד תומך בכל סוג של correlation, ולכן כדאי לעבור על הפלט של הממיר לפני שסומכים עליו.
כדאי לשמור את הגרסה הראשונה של החוק. היא קו הבסיס, וההשוואה לגרסה עם ה-correlation מראה אם הסף עוזר.
EventID. ב-Splunk, אחרי ה-pipeline, השם הוא EventCode. ערבוב של שני השמות בחוק אחד גורם להחמצות שקטות.--without-pipeline הוא בחירה מכוונת ואינו קיצור דרך. הפלט עלול לא לרוץ בפלטפורמה שלך.level: high בחוק רועש. החומרה צריכה להתאים למשמעות של התראה. אירוע נפוץ בלי הקשר צריך להתחיל נמוך.sigma check בודקת את מבנה הקובץ. היא לא בודקת אם הזיהוי מוצא את האירועים הנכונים.אחרי שיש חוק שעובר בדיקה, המרה והטסטים שלו, הצעדים הבאים פשוטים:
|contains וגם |endswith, ואת השדה category.בקצרה: חוק הוא טענה על אירועים. כותבים את הטענה, ממירים אותה, ואז מדגימים אותה עם אירועים שאמורים להתאים ואירועים שלא.
זיהוי ובלו טים
SIEM אוסף לוגים, מנרמל אותם, מריץ חוקי קורלציה ומעלה התראות לטריאז׳. הצינור המלא עם דוגמה שאפשר להריץ.
זיהוי ובלו טים
קריאת לוג Security של Windows: מדיניות audit, אירועים 4624, 4625, 4634, 4672, 4688 ו-1102, מה Sysmon מוסיף, וניסיון התחברות כושל למצוא בעצמך.