נוזקות ופורנזיקה
למה להשתמש ב-NotHoly לניתוח malware
triage סטטי ב-sandbox שלעולם לא מריץ את הדגימה, ומודל שמסביר ומוביל ל-ATT&CK בלי לסרב. הדטונציה נשארת במעבדה שלכם.
לכתוב חוק YARA ראשון, להתאים לקובץ בדיקה לא מזיק אחד ולא לאחר, ולהבין למה כל חוק צריך בדיקות חיוביות ושליליות.
YARA הוא כלי להתאמת דפוסים. כותבים חוק שמתאר איך קובץ נראה, ו-YARA מציג את הקבצים שמתאימים לתיאור. מי שמשתמשים בו הכי הרבה הם אנליסטים של נוזקות. הם כותבים חוקים למחרוזות, למבני קבצים ולרצפי בתים, ואז סורקים תיקיות, תמונות דיסק ו-memory dumps. אותו מנגנון עובד על כל קובץ שבבעלותך, למשל תבנית שאסור שתכיל סימון פנימי, או קובץ config שאסור שיכיל טוקן.
ל-YARA אין מושג מה מסוכן. הוא מתאים את מה שהחוק אומר. חוק הוא טענה על בתים, והוא טוב בדיוק כמו הטענה הזו.
הפרויקט מתארח ב-GitHub תחת VirusTotal. מדריך הכתיבה הרשמי ב-Read the Docs הוא המקור לתחביר. VirusTotal מתחזקת גם את YARA-X, שכתוב ב-Rust ששומר על רוב שפת החוקים. השניים חופפים אבל לא זהים, ולכן צריך לקרוא את הערות התאימות לפני שמעבירים חוק מאחד לשני.
hash של קובץ עונה על שאלה צרה אחת: האם הקובץ המדויק הזה כבר מוכר? שינוי של בית אחד משנה את ה-hash. המאמר על hash של קבצים מפרט את זה. חוק YARA שואל שאלה רחבה יותר: האם הקובץ הזה מכיל את החלקים שאנחנו מצפים להם? חוק אחד יכול להתאים לקבצים רבים שחולקים מחרוזת, מבנה או דפוס בתים, גם כשאין לשניים מהם אותו hash.
השאלה הרחבה היא גם המקום שבו הצרות מתחילות. hash כמעט אף פעם לא מתאים לקובץ שהוא לא אמור להתאים לו. חוק רשלני יכול להתאים לחצי משרת קבצים. לכן המיומנות שצריך ללמוד קשורה פחות לתחביר ויותר לכתיבת חוק שמתאים למה שרוצים ולשום דבר אחר, ולהוכחה של זה עם קבצים שבשליטתך.
לכל חוק יש שם, ואחריו עד שלושה מקטעים בתוך סוגריים מסולסלים:
rule Example_Rule {
meta:
description = "What this rule is for"
strings:
$text = "some text"
condition:
$text
}שמות חוקים מורכבים מאותיות, ספרות וקווים תחתונים, ולא יכולים להתחיל בספרה. השם מופיע בכל דוח התאמה, אז כדאי לבחור שם שאומר לקורא על מה החוק.
המקטע meta מחזיק זוגות key-value בשביל אנשים: תיאור, מחבר, תאריך, קישור למחקר שמאחורי החוק. YARA אף פעם לא משתמש ב-meta כדי להחליט על התאמה. עדיין צריך לשמור עליו מדויק, כי האדם הבא שיפתח את הקובץ יסמוך עליו.
כל מחרוזת מקבלת מזהה שמתחיל בתו $. התנאי מפנה למחרוזות לפי המזהה הזה. יש שלושה סוגים.
מחרוזות טקסט נכתבות במירכאות כפולות:
$marker = "LAB-TRAINING-MARKER"מודיפיקטורים משנים את אופן ההתאמה של הטקסט. nocase מתעלם מרישיות. wide מתאים לטקסט UTF-16LE, שבו אחרי כל תו ASCII מגיע בית אפס, דבר נפוץ בבינאריים של Windows. fullword דורש שההתאמה תעמוד בפני עצמה, ולא בתוך מילה ארוכה יותר.
מחרוזות hex נכתבות בסוגריים מסולסלים ומתאימות לבתים גולמיים:
$mz = { 4D 5A }שני הבתים האלה הם החתימה MZ בתחילת קובצי הרצה רבים של Windows. ?? מתאים לכל בית בודד, [2-4] מאפשר פער של שניים עד ארבעה בתים לא ידועים, ואילו ( 90 | 91 ) מתאים לכל אחד משני הבתים.
ביטויים רגולריים נכתבים בין לוכסנים:
$version = /LAB-[A-Z]+ v[0-9]+/regex הוא הסוג הגמיש ביותר, והקל ביותר להפוך לרחב מדי. כל עוד מחרוזת טקסט או hex פשוטה יכולה לבטא את הדפוס, עדיף להשתמש בה.
התנאי הוא ביטוי בוליאני. הוא משלב מחרוזות ומאפייני קובץ לתשובה אחת: התאמה או אי־התאמה.
$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.כל חוק צריך תנאי. חוק עם מחרוזות ובלי תנאי הגיוני הוא שבור או חסר תועלת.
-s, YARA מדפיס גם כל מחרוזת שהתאימה, עם ה-offset בבתים שבו היא נמצאה.המחרוזות באות קודם והתנאי אחר כך. תנאי כמו $a and $b מחמיר, כי שתי המחרוזות חייבות להימצא לפני שהחוק יכול להתאים.
הפלט הצפוי בהמשך מתואר ולא מודבק, כי העיצוב המדויק יכול להשתנות בין גרסאות YARA. משווים את מה שרואים לתיאורים האלה.
עובדים בתיקייה ריקה. ב-Windows מריצים את הפקודות ב-Git Bash. ה-heredoc בשלב 3 לא מתנהג באותה צורה ב-PowerShell.
ב-Debian וב-Ubuntu:
sudo apt install yaraב-macOS עם Homebrew:
brew install yaraב-Windows, להוריד את קובץ ה-zip של הגרסה מהכתובת https://github.com/VirusTotal/yara/releases, לחלץ אותו ולשים את קובץ ההרצה ב-PATH שלך. הקובץ עשוי להיקרא yara64.exe. צריך לשנות את שמו לשם yara.exe, או להעתיק אותו בשם הזה, כדי שהפקודות בהמשך יעבדו כפי שהן כתובות.
בודקים את ההתקנה:
yara --versionאמור להופיע מספר גרסה. המאמר הזה לא מקבע גרסה, אז משתמשים בגרסה האחרונה ששיטת ההתקנה שלך מספקת.
mkdir yara-lab && cd yara-lab
printf 'LAB-TRAINING-MARKER v1\n' > match.txt
printf 'ordinary text file\n' > nomatch.txtשני הקבצים הם טקסט פשוט שכתבת בעצמך. הראשון אמור להתאים לחוק. השני לא.
המירכאות סביב EOF חשובות. בלעדיהן ה-shell מחליף את $m במשתנה ריק לפני ש-YARA רואה את הקובץ, והחוק כבר לא מתקמפל.
cat > lab.yar <<'EOF'
rule Lab_Training_Marker {
meta: description = "Matches the lab training marker"
strings: $m = "LAB-TRAINING-MARKER"
condition: $m
}
EOFאפשר לקרוא אותו כשלושה חלקים. ה-meta אומר בשביל מה החוק. המחרוזת אומרת שהקובץ חייב להכיל את טקסט הסימון. התנאי אומר שקובץ מתאים כשהמחרוזת הזו נמצאת לפחות פעם אחת.
yara -s lab.yar match.txtYARA אמור להדפיס את שם החוק ואת נתיב הקובץ. בגלל הדגל -s, הוא מדפיס גם שורה עבור המחרוזת שהתאימה, עם ה-offset בבתים והטקסט שמצא. הסימון מתחיל בבית הראשון של match.txt, ולכן ה-offset אמור להיות 0x0.
yara lab.yar nomatch.txtפלט צפוי: כלום. YARA מדפיס רק התאמות, כך ששקט אומר שהקובץ לא התאים.
לשקט יש משמעות רק אם הבדיקה החיובית עבדה. קודם מריצים את שלב 4. אם שלב 4 לא הדפיס כלום, החוק או ההתקנה שגויים, והשקט בשלב 5 לא אומר דבר.
כמעט־התאמה היא הקובץ השלילי השימושי ביותר, כי הוא נכשל מסיבה צרה אחת.
printf 'LAB-TRAINING\n' > near.txt
yara lab.yar near.txtפלט צפוי: כלום. בקובץ יש את תחילת הסימון אבל לא את המחרוזת המלאה, ולכן המחרוזת לא נמצאת והתנאי לא מתקיים.
yara -r lab.yar .הדגל -r סורק את התיקייה באופן רקורסיבי. בפלט אמור להופיע match.txt. כנראה יופיע גם lab.yar, קובץ החוק עצמו. קובץ החוק מכיל את טקסט הסימון, ולכן החוק מתאים למקור שלו. זו טעות נפוצה, והחלק הבא מכסה אותה. צריך לשמור חוקים בתיקייה אחרת מהנתונים שסורקים.
חוק המעבדה מתאים לסימון אימון. חוקים אמיתיים בדרך כלל צריכים אילוץ שהמחרוזת לבדה לא נותנת. נניח שרוצים רק קבצים קטנים שנושאים את הסימון:
rule Lab_Training_Marker_Small {
strings: $m = "LAB-TRAINING-MARKER"
condition: $m and filesize < 1KB
}בודקים את זה באותה דרך. match.txt אמור להתאים. nomatch.txt וגם near.txt לא אמורים להתאים. מבחינת הבדיקות, כל שינוי במחרוזות או בתנאי הוא חוק חדש, ולכן מריצים שוב את שני קובצי הבדיקה.
החוק הזה נראה סביר:
rule Too_Broad {
strings: $a = "text"
condition: $a
}הוא יתאים אל nomatch.txt, כי המשפט ordinary text file מכיל את המילה text. אפשר לבדוק את זה עם הקובץ השלילי שכבר נוצר. חוק שמתאים לו נכשל בבדיקה של עצמו.
דפוסים שמתאימים ליותר מדי:
text, error, copyright או this program.{ 00 } או { 90 }.nocase על מילה נפוצה.any of them על רשימת מחרוזות שכל אחת מהן מופיעה בקבצים רגילים.filesize < 10KB, שמתאים לרוב הקבצים הקטנים./.+/.דרכים להדק חוק:
and או עם 2 of (...), כך שאף מחרוזת נפוצה בודדת לא תכריע את התוצאה.at או עם in כשידוע איפה המחרוזת אמורה להופיע.uint16(0) == 0x5A4D.$m לפני ש-YARA קורא את הקובץ. הפירוט בשלב 3.זה הכלל החשוב ביותר במאמר. כל חוק YARA צריך את שני סוגי קובצי הבדיקה לפני שמישהו פורס אותו.
match.txt. בעבודה אמיתית הם מגיעים מדוגמאות שמותר לך להחזיק, לפי נוהלי הטיפול של הארגון שלך.near.txt.חוק עובר כשהוא מתאים לכל קובץ חיובי ולאף קובץ שלילי. שומרים את שתי הקבוצות ליד החוק, בניהול גרסאות אם הצוות שלך משתמש בו, ומריצים אותן שוב אחרי כל עריכה. חוק שעבר את הבדיקה החיובית אבל מעולם לא הורץ מול קבצים שליליים לא נבדק.
pe, שמאפשר לחוק לבדוק את ה-headers וה-sections של קובץ הרצה של Windows במקום בתים גולמיים.נוזקות ופורנזיקה
triage סטטי ב-sandbox שלעולם לא מריץ את הדגימה, ומודל שמסביר ומוביל ל-ATT&CK בלי לסרב. הדטונציה נשארת במעבדה שלכם.
נוזקות ופורנזיקה
איך hashes מזהים קבצים, למה SHA-256 החליף את MD5, איך NSRL מסנן תוכנות מוכרות, ולמה העלאת קובץ ל-VirusTotal היא שיתוף שלו.