דילוג לתוכן
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

כתיבת חוק YARA מול קובץ בדיקה תמים

לכתוב חוק YARA ראשון, להתאים לקובץ בדיקה לא מזיק אחד ולא לאחר, ולהבין למה כל חוק צריך בדיקות חיוביות ושליליות.

מתחילים8 דקות קריאהמאת NotHoly

מה חוק YARA עושה

YARA הוא כלי להתאמת דפוסים. כותבים חוק שמתאר איך קובץ נראה, ו-YARA מציג את הקבצים שמתאימים לתיאור. מי שמשתמשים בו הכי הרבה הם אנליסטים של נוזקות. הם כותבים חוקים למחרוזות, למבני קבצים ולרצפי בתים, ואז סורקים תיקיות, תמונות דיסק ו-memory dumps. אותו מנגנון עובד על כל קובץ שבבעלותך, למשל תבנית שאסור שתכיל סימון פנימי, או קובץ config שאסור שיכיל טוקן.

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

הפרויקט מתארח ב-GitHub תחת VirusTotal. מדריך הכתיבה הרשמי ב-Read the Docs הוא המקור לתחביר. VirusTotal מתחזקת גם את YARA-X, שכתוב ב-Rust ששומר על רוב שפת החוקים. השניים חופפים אבל לא זהים, ולכן צריך לקרוא את הערות התאימות לפני שמעבירים חוק מאחד לשני.

למה צריך חוקים

hash של קובץ עונה על שאלה צרה אחת: האם הקובץ המדויק הזה כבר מוכר? שינוי של בית אחד משנה את ה-hash. המאמר על hash של קבצים מפרט את זה. חוק YARA שואל שאלה רחבה יותר: האם הקובץ הזה מכיל את החלקים שאנחנו מצפים להם? חוק אחד יכול להתאים לקבצים רבים שחולקים מחרוזת, מבנה או דפוס בתים, גם כשאין לשניים מהם אותו hash.

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

האנטומיה של חוק

לכל חוק יש שם, ואחריו עד שלושה מקטעים בתוך סוגריים מסולסלים:

yara
rule Example_Rule {
  meta:
    description = "What this rule is for"

  strings:
    $text = "some text"

  condition:
    $text
}

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

meta

המקטע meta מחזיק זוגות key-value בשביל אנשים: תיאור, מחבר, תאריך, קישור למחקר שמאחורי החוק. YARA אף פעם לא משתמש ב-meta כדי להחליט על התאמה. עדיין צריך לשמור עליו מדויק, כי האדם הבא שיפתח את הקובץ יסמוך עליו.

strings

כל מחרוזת מקבלת מזהה שמתחיל בתו $. התנאי מפנה למחרוזות לפי המזהה הזה. יש שלושה סוגים.

מחרוזות טקסט נכתבות במירכאות כפולות:

yara
$marker = "LAB-TRAINING-MARKER"

מודיפיקטורים משנים את אופן ההתאמה של הטקסט. nocase מתעלם מרישיות. wide מתאים לטקסט UTF-16LE, שבו אחרי כל תו ASCII מגיע בית אפס, דבר נפוץ בבינאריים של Windows. fullword דורש שההתאמה תעמוד בפני עצמה, ולא בתוך מילה ארוכה יותר.

מחרוזות hex נכתבות בסוגריים מסולסלים ומתאימות לבתים גולמיים:

yara
$mz = { 4D 5A }

שני הבתים האלה הם החתימה MZ בתחילת קובצי הרצה רבים של Windows. ?? מתאים לכל בית בודד, [2-4] מאפשר פער של שניים עד ארבעה בתים לא ידועים, ואילו ( 90 | 91 ) מתאים לכל אחד משני הבתים.

ביטויים רגולריים נכתבים בין לוכסנים:

yara
$version = /LAB-[A-Z]+ v[0-9]+/

regex הוא הסוג הגמיש ביותר, והקל ביותר להפוך לרחב מדי. כל עוד מחרוזת טקסט או hex פשוטה יכולה לבטא את הדפוס, עדיף להשתמש בה.

condition

התנאי הוא ביטוי בוליאני. הוא משלב מחרוזות ומאפייני קובץ לתשובה אחת: התאמה או אי־התאמה.

  • $marker מתקיים כשהמחרוזת מופיעה לפחות פעם אחת.
  • any of them וגם all of them מכסים כל מחרוזת בחוק. 2 of ($a, $b, $c) דורש שתיים משלוש.
  • $marker at 0 דורש את המחרוזת בבית הראשון. $marker in (0..512) דורש אותה איפשהו ב-512 הבתים הראשונים.
  • #marker > 3 סופר מופעים.
  • filesize < 2KB בודק את גודל הקובץ.
  • uint16(0) == 0x5A4D קורא את שני הבתים הראשונים כמספר שלם little-endian ובודק אם זו החתימה MZ.

כל חוק צריך תנאי. חוק עם מחרוזות ובלי תנאי הגיוני הוא שבור או חסר תועלת.

איך YARA קורא חוק

  1. YARA מפענח את קובץ החוק ומקמפל אותו. שגיאת תחביר עוצרת את ההרצה לפני שנקרא קובץ כלשהו.
  2. עבור כל קובץ שהוא סורק, YARA מחפש כל מחרוזת במקטע strings.
  3. הוא מעריך את התנאי לפי התוצאות משלב 2.
  4. אם התנאי מתקיים, הקובץ מתאים. עם -s, YARA מדפיס גם כל מחרוזת שהתאימה, עם ה-offset בבתים שבו היא נמצאה.

המחרוזות באות קודם והתנאי אחר כך. תנאי כמו $a and $b מחמיר, כי שתי המחרוזות חייבות להימצא לפני שהחוק יכול להתאים.

מעבדה: קובץ חיובי אחד וקובץ שלילי אחד

הפלט הצפוי בהמשך מתואר ולא מודבק, כי העיצוב המדויק יכול להשתנות בין גרסאות YARA. משווים את מה שרואים לתיאורים האלה.

עובדים בתיקייה ריקה. ב-Windows מריצים את הפקודות ב-Git Bash. ה-heredoc בשלב 3 לא מתנהג באותה צורה ב-PowerShell.

1. התקנת yara

ב-Debian וב-Ubuntu:

bash
sudo apt install yara

ב-macOS עם Homebrew:

bash
brew install yara

ב-Windows, להוריד את קובץ ה-zip של הגרסה מהכתובת https://github.com/VirusTotal/yara/releases, לחלץ אותו ולשים את קובץ ההרצה ב-PATH שלך. הקובץ עשוי להיקרא yara64.exe. צריך לשנות את שמו לשם yara.exe, או להעתיק אותו בשם הזה, כדי שהפקודות בהמשך יעבדו כפי שהן כתובות.

בודקים את ההתקנה:

bash
yara --version

אמור להופיע מספר גרסה. המאמר הזה לא מקבע גרסה, אז משתמשים בגרסה האחרונה ששיטת ההתקנה שלך מספקת.

2. יצירת קובץ חיובי וקובץ שלילי

bash
mkdir yara-lab && cd yara-lab
printf 'LAB-TRAINING-MARKER v1\n' > match.txt
printf 'ordinary text file\n' > nomatch.txt

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

3. כתיבת החוק

המירכאות סביב EOF חשובות. בלעדיהן ה-shell מחליף את $m במשתנה ריק לפני ש-YARA רואה את הקובץ, והחוק כבר לא מתקמפל.

bash
cat > lab.yar <<'EOF'
rule Lab_Training_Marker {
  meta: description = "Matches the lab training marker"
  strings: $m = "LAB-TRAINING-MARKER"
  condition: $m
}
EOF

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

4. הרצת הבדיקה החיובית

bash
yara -s lab.yar match.txt

YARA אמור להדפיס את שם החוק ואת נתיב הקובץ. בגלל הדגל -s, הוא מדפיס גם שורה עבור המחרוזת שהתאימה, עם ה-offset בבתים והטקסט שמצא. הסימון מתחיל בבית הראשון של match.txt, ולכן ה-offset אמור להיות 0x0.

5. הרצת הבדיקה השלילית

bash
yara lab.yar nomatch.txt

פלט צפוי: כלום. YARA מדפיס רק התאמות, כך ששקט אומר שהקובץ לא התאים.

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

6. הוספת כמעט־התאמה

כמעט־התאמה היא הקובץ השלילי השימושי ביותר, כי הוא נכשל מסיבה צרה אחת.

bash
printf 'LAB-TRAINING\n' > near.txt
yara lab.yar near.txt

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

7. סריקת כל התיקייה

bash
yara -r lab.yar .

הדגל -r סורק את התיקייה באופן רקורסיבי. בפלט אמור להופיע match.txt. כנראה יופיע גם lab.yar, קובץ החוק עצמו. קובץ החוק מכיל את טקסט הסימון, ולכן החוק מתאים למקור שלו. זו טעות נפוצה, והחלק הבא מכסה אותה. צריך לשמור חוקים בתיקייה אחרת מהנתונים שסורקים.

הקשחת החוק

חוק המעבדה מתאים לסימון אימון. חוקים אמיתיים בדרך כלל צריכים אילוץ שהמחרוזת לבדה לא נותנת. נניח שרוצים רק קבצים קטנים שנושאים את הסימון:

yara
rule Lab_Training_Marker_Small {
  strings: $m = "LAB-TRAINING-MARKER"
  condition: $m and filesize < 1KB
}

בודקים את זה באותה דרך. match.txt אמור להתאים. nomatch.txt וגם near.txt לא אמורים להתאים. מבחינת הבדיקות, כל שינוי במחרוזות או בתנאי הוא חוק חדש, ולכן מריצים שוב את שני קובצי הבדיקה.

להימנע מחוקים שמתאימים להכול

החוק הזה נראה סביר:

yara
rule Too_Broad {
  strings: $a = "text"
  condition: $a
}

הוא יתאים אל nomatch.txt, כי המשפט ordinary text file מכיל את המילה text. אפשר לבדוק את זה עם הקובץ השלילי שכבר נוצר. חוק שמתאים לו נכשל בבדיקה של עצמו.

דפוסים שמתאימים ליותר מדי:

  • מחרוזות קצרות, או מילים נפוצות כמו text, error, copyright או this program.
  • דפוס hex של בית אחד או קצר מאוד, כמו { 00 } או { 90 }.
  • nocase על מילה נפוצה.
  • any of them על רשימת מחרוזות שכל אחת מהן מופיעה בקבצים רגילים.
  • תנאי שהוא רק בדיקת גודל, כמו filesize < 10KB, שמתאים לרוב הקבצים הקטנים.
  • regex רופף, כמו /.+/.

דרכים להדק חוק:

  • לבחור מחרוזות ארוכות וייחודיות. לשאול אם המחרוזת תופיע במסמך שהארגון שלך כותב כל יום. אם כן, לבחור מחרוזת אחרת.
  • לדרוש יותר ממחרוזת אחת עם and או עם 2 of (...), כך שאף מחרוזת נפוצה בודדת לא תכריע את התוצאה.
  • לעגן את החיפוש עם at או עם in כשידוע איפה המחרוזת אמורה להופיע.
  • לשלב בדיקת תוכן עם בדיקת header או גודל, כמו uint16(0) == 0x5A4D.

טעויות נפוצות

  1. לבדוק רק את הקובץ החיובי. חוק שמתאים לקובץ שבשבילו נבנה מוכיח מעט. הוא עשוי להתאים להכול.
  2. לדלג על כמעט־התאמות. קבצים רגילים נדיר שנכשלים בצורה מעניינת. קובץ שכמעט מתאים הוא הבדיקה שתופסת מחרוזת רופפת מדי.
  3. להשמיט את המירכאות ב-heredoc. ה-shell מחליף את $m לפני ש-YARA קורא את הקובץ. הפירוט בשלב 3.
  4. לסרוק את התיקייה שהחוקים נמצאים בה. קובץ החוק מתאים לטקסט של עצמו.
  5. לסמוך על meta. תיאור שאומר "מזהה X" לא מזהה את X. רק קובצי בדיקה מראים את זה.
  6. לערוך בלי לבדוק שוב. כל שינוי במחרוזות או בתנאי יכול לשנות את התוצאה. מריצים שוב את שתי הבדיקות אחרי כל עריכה.

בדיקות חיוביות ושליליות לפני שמישהו פורס חוק

זה הכלל החשוב ביותר במאמר. כל חוק YARA צריך את שני סוגי קובצי הבדיקה לפני שמישהו פורס אותו.

  • קבצים חיוביים הם קבצים שהחוק חייב להתאים להם. במעבדה זה match.txt. בעבודה אמיתית הם מגיעים מדוגמאות שמותר לך להחזיק, לפי נוהלי הטיפול של הארגון שלך.
  • קבצים שליליים הם קבצים שאסור לחוק להתאים להם. כדאי לכלול מסמכים רגילים, סוגי קבצים שנפוצים בסביבה שלך, קבצים נקיים מהמערכות שמתכננים לסרוק וכמעט־התאמות כמו near.txt.

חוק עובר כשהוא מתאים לכל קובץ חיובי ולאף קובץ שלילי. שומרים את שתי הקבוצות ליד החוק, בניהול גרסאות אם הצוות שלך משתמש בו, ומריצים אותן שוב אחרי כל עריכה. חוק שעבר את הבדיקה החיובית אבל מעולם לא הורץ מול קבצים שליליים לא נבדק.

איך ממשיכים

  • לקרוא את מדריך כתיבת החוקים מתחילתו ועד סופו. הוא מכסה מודולים כמו pe, שמאפשר לחוק לבדוק את ה-headers וה-sections של קובץ הרצה של Windows במקום בתים גולמיים.
  • להריץ את אותו חוק מעבדה עם YARA-X ולהשוות את התוצאות. התיעוד של YARA-X מפרט מה תואם ומה לא.
  • לבנות קורפוס נקי: תיקייה של קבצים רגילים ממחשבים שבשליטתך. כל חוק חדש חייב לעבור אותו לפני שהוא יוצא לאנשהו.
  • לקרוא בהמשך את המאמר על SIEM. הוא מכסה את הצד השני של הזיהוי: חוקים שרצים על לוגים במקום על קבצים.

מקורות

מקורות

  1. YARA: Writing rules
  2. VirusTotal/yara on GitHub
  3. YARA-X documentation (VirusTotal)

עוד בנושא נוזקות ופורנזיקה

נוזקות ופורנזיקה

למה להשתמש ב-NotHoly לניתוח malware

triage סטטי ב-sandbox שלעולם לא מריץ את הדגימה, ומודל שמסביר ומוביל ל-ATT&CK בלי לסרב. הדטונציה נשארת במעבדה שלכם.

ביניים2 דקות קריאה