איסוף יומנים של File Scanning Framework

גרסת כלי הניתוח: 3.0

נתמך ב:

במאמר הזה מוסבר איך להטמיע יומנים של File Scanning Framework ב-Google Security Operations באמצעות Google Cloud Storage V2.

File Scanning Framework (FSF)‎ הוא פתרון סריקת קבצים רקורסיבי מודולרי בקוד פתוח שפותח על ידי Emerson Electric Co.‎. הפתרון הזה משתמש בארכיטקטורת לקוח-שרת כדי לנתח קבצים וליצור תוצאות סריקה מפורטות בפורמט JSON, כולל מטא-נתונים של קבצים, התאמות של חתימות YARA, אובייקטים משניים שחולצו ומטא-נתונים ספציפיים למודול.

לפני שמתחילים

חשוב לוודא שמתקיימות הדרישות המוקדמות הבאות:

  • מופע של Google SecOps
  • פרויקט ב-GCP עם Cloud Storage API מופעל
  • הרשאות ליצירה ולניהול של מאגרי GCS
  • הרשאות לניהול מדיניות IAM בקטגוריות GCS
  • מופע של שרת FSF שנפרס עם גישת כתיבה לספריית היומן
  • גישת רוט (Root) או גישת sudo למארח השרת של FSF

יצירת קטגוריה של Google Cloud Storage

  1. נכנסים אל מסוף Google Cloud.
  2. בוחרים פרויקט או יוצרים פרויקט חדש.
  3. בתפריט הניווט, עוברים אל Cloud Storage > Buckets.
  4. לוחצים על Create bucket.
  5. מספקים את פרטי ההגדרה הבאים:

    הגדרה ערך
    Name your bucket (שם הקטגוריה) מזינים שם ייחודי בעולם (לדוגמה, fsf-logs-secops).
    סוג המיקום בוחרים לפי הצרכים (אזור, שני אזורים, מספר אזורים).
    Location בוחרים את המיקום (לדוגמה, us-central1).
    סוג אחסון (storage class) רגיל (מומלץ ליומנים שניגשים אליהם לעיתים קרובות).
    בקרת גישה אחיד (מומלץ).
    כלים להגנה אופציונלי: הפעלת ניהול גרסאות של אובייקטים או מדיניות שמירת נתונים.
  6. לוחצים על יצירה.

הגדרת ספריית פלט של יומני FSF

FSF כותב את תוצאות הסריקה בפורמט JSON לספריית יומן שניתנת להגדרה. מגדירים ספרייה ייעודית להעברה של נתונים ל-Google SecOps.

  1. מתחברים למארח השרת של FSF באמצעות SSH.
  2. פותחים את קובץ ההגדרות של שרת ה-FSF:

    sudo nano /opt/fsf/fsf-server/conf/config.py
    
  3. מאתרים את המילון SCANNER_CONFIG.

  4. מעדכנים את הפרמטר LOG_PATH לספרייה ייעודית:

    SCANNER_CONFIG = {
        'LOG_PATH': '/var/log/fsf',
        'YARA_PATH': '/opt/fsf/fsf-server/yara/rules.yara',
        'PID_PATH': '/tmp/scanner.pid',
        'EXPORT_PATH': '/tmp',
        'TIMEOUT': 60,
        'MAX_DEPTH': 10
    }
    
  5. שומרים את הקובץ וסוגרים אותו.

  6. יוצרים את ספריית היומן עם ההרשאות המתאימות:

    sudo mkdir -p /var/log/fsf
    sudo chown -R fsf:fsf /var/log/fsf
    sudo chmod 755 /var/log/fsf
    
  7. מפעילים מחדש את שרת FSF כדי להחיל את השינויים:

    sudo systemctl restart fsf
    
  8. מוודאים ש-FSF כותב יומנים לספרייה החדשה:

    ls -lh /var/log/fsf/
    

התקנה והגדרה של Fluentd

‫Fluentd יעקוב אחרי קובצי היומן של FSF ויעביר אותם ל-Google Cloud Storage.

התקנת Fluentd

  1. במארח השרת של FSF, מתקינים את Fluentd ‏ (td-agent):

    ‫
    curl -fsSL https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-td-agent4.sh | sh
    
  2. מתקינים את פלאגין הפלט של GCS:

    sudo td-agent-gem install fluent-plugin-gcs
    
  3. מאמתים את התקנת הפלאגין:

    td-agent-gem list | grep fluent-plugin-gcs
    

יצירת חשבון שירות ב-GCP עבור Fluentd

  1. במסוף GCP, עוברים אל IAM & Admin > Service Accounts.
  2. לוחצים על יצירת חשבון שירות.
  3. מספקים את פרטי ההגדרה הבאים:
    • שם חשבון השירות: מזינים fsf-fluentd-shipper.
    • תיאור חשבון השירות: מזינים Service account for Fluentd to ship FSF logs to GCS.
  4. לוחצים על יצירה והמשך.
  5. בקטע Grant this service account access to project (מתן גישה של חשבון השירות הזה לפרויקט):
    1. לוחצים על בחירת תפקיד.
    2. מחפשים את Storage Object Admin ולוחצים עליו.
  6. לוחצים על Continue.
  7. לוחצים על סיום.

יצירת מפתח של חשבון שירות

  1. ברשימה Service Accounts (חשבונות שירות), לוחצים על חשבון השירות (fsf-fluentd-shipper).
  2. עוברים לכרטיסייה Keys.
  3. לוחצים על Add Key > Create new key.
  4. בוחרים באפשרות JSON בתור סוג המפתח.
  5. לוחצים על יצירה.
  6. קובץ ה-JSON עם המפתח יירד למחשב.
  7. מעבירים את קובץ המפתח למארח השרת של FSF:

    scp /path/to/downloaded-key.json user@fsf-server:/etc/td-agent/gcp-key.json
    
  8. מגדירים הרשאות מתאימות בקובץ המפתח:

    sudo chown td-agent:td-agent /etc/td-agent/gcp-key.json
    sudo chmod 600 /etc/td-agent/gcp-key.json
    

מתן הרשאות IAM בקטגוריית GCS

  1. עוברים אל Cloud Storage > Buckets (קטגוריות).
  2. לוחצים על שם הקטגוריה (fsf-logs-secops).
  3. עוברים לכרטיסייה Permissions.
  4. לוחצים על הענקת גישה.
  5. מספקים את פרטי ההגדרה הבאים:
    • Add principals (הוספת ישויות מורשות): מזינים את כתובת האימייל בחשבון השירות (לדוגמה, fsf-fluentd-shipper@PROJECT_ID.iam.gserviceaccount.com).
    • הקצאת תפקידים: בוחרים באפשרות אדמין של אובייקטים באחסון.
  6. לוחצים על Save.

הגדרת Fluentd

  1. במארח של שרת FSF, יוצרים קובץ הגדרה של Fluentd:

    sudo nano /etc/td-agent/td-agent.conf
    
  2. מוסיפים את ההגדרה הבאה:

    # Tail FSF JSON logs
    <source>
        @type tail
        path /var/log/fsf/*.log
        pos_file /var/log/td-agent/fsf.log.pos
        tag fsf.scan
        read_from_head true
        <parse>
            @type json
            time_key timestamp
            time_format %Y-%m-%dT%H:%M:%S.%L%z
        </parse>
    </source>
    
    # Ship to Google Cloud Storage
    <match fsf.scan>
        @type gcs
        project YOUR_GCP_PROJECT_ID
        keyfile /etc/td-agent/gcp-key.json
        bucket fsf-logs-secops
        object_key_format %{path}%{time_slice}_%{index}.%{file_extension}
        path fsf-logs/
        <buffer tag,time>
            @type file
            path /var/log/td-agent/buffer/gcs
            timekey 3600
            timekey_wait 10m
            timekey_use_utc true
            chunk_limit_size 10MB
        </buffer>
        <format>
            @type json
        </format>
        store_as json
        auto_create_bucket false
    </match>
    
  3. מחליפים את YOUR_GCP_PROJECT_ID במזהה הפרויקט בפועל ב-GCP.

  4. שומרים את הקובץ וסוגרים אותו.

  5. יוצרים את ספריית המאגר:

    sudo mkdir -p /var/log/td-agent/buffer/gcs
    sudo chown -R td-agent:td-agent /var/log/td-agent/buffer
    
  6. מפעילים מחדש את Fluentd כדי להחיל את ההגדרה:

    sudo systemctl restart td-agent
    
  7. מפעילים את Fluentd כדי להתחיל בהפעלה:

    sudo systemctl enable td-agent
    
  8. מוודאים ש-Fluentd פועל:

    sudo systemctl status td-agent
    

אימות של העברת יומנים

  1. בודקים אם יש שגיאות ביומני Fluentd:

    sudo tail -f /var/log/td-agent/td-agent.log
    
  2. מפעילים סריקת FSF לצורך בדיקה כדי ליצור יומנים:

    echo "test content" > /tmp/test.txt
    /opt/fsf/fsf-client/fsf_client.py /tmp/test.txt --suppress-report
    
  3. ממתינים דקה או שתיים עד ש-Fluentd יעבד את היומנים וישלח אותם.

  4. במסוף GCP, עוברים אל Cloud Storage > Buckets.

  5. לוחצים על שם הקטגוריה (fsf-logs-secops).

  6. עוברים לקידומת fsf-logs/.

  7. מוודאים שקובצי ה-JSON נוצרים עם חותמות זמן.

  8. מורידים קובץ ובודקים אותו כדי לוודא שהוא מכיל תוצאות סריקה של FSF בפורמט JSON.

אחזור חשבון השירות של Google SecOps

‫Google SecOps משתמש בחשבון שירות ייחודי כדי לקרוא נתונים מהקטגוריה של GCS. צריך להעניק לחשבון השירות הזה גישה לדלי.

קבלת כתובת האימייל בחשבון השירות

  1. עוברים אל SIEM Settings > Feeds (הגדרות SIEM > פידים).
  2. לוחצים על הוספת פיד חדש.
  3. לוחצים על Configure a single feed (הגדרת פיד יחיד).
  4. בשדה שם הפיד, מזינים שם לפיד (לדוגמה, FSF File Scanning Logs).
  5. בוחרים באפשרות Google Cloud Storage V2 בתור סוג המקור.
  6. בוחרים באפשרות File Scanning Framework (מסגרת לסריקת קבצים) בתור סוג היומן.
  7. לוחצים על קבלת חשבון שירות. תוצג כתובת האימייל בחשבון שירות ייחודי, לדוגמה:

    secops-12345678@secops-gcp-prod.iam.gserviceaccount.com
    
  8. מעתיקים את כתובת האימייל לשימוש בשלב הבא.

  9. לוחצים על הבא.

  10. מציינים ערכים לפרמטרים הבאים של הקלט:

    • כתובת ה-URL של קטגוריית האחסון: מזינים את ה-URI של קטגוריית GCS עם נתיב הקידומת:

      gs://fsf-logs-secops/fsf-logs/
      
    • אפשרות למחיקת המקור: בוחרים את אפשרות המחיקה לפי ההעדפה שלכם:

      • אף פעם: לא נמחקים קבצים אחרי ההעברה (מומלץ לבדיקות).
      • מחיקת קבצים שהועברו: הקבצים נמחקים אחרי שההעברה מסתיימת.
      • מחיקת קבצים שהועברו וספריות ריקות: מחיקת קבצים וספריות ריקות אחרי שההעברה מסתיימת בהצלחה.

    • הגיל המקסימלי של הקובץ: כולל קבצים ששונו במספר הימים האחרון (ברירת המחדל היא 180 ימים).

    • מרחב השמות של הנכס: מרחב השמות של הנכס.

    • תוויות להוספה: התווית שתתווסף לאירועים מהפיד הזה.

  11. לוחצים על הבא.

  12. בודקים את ההגדרות של הפיד החדש במסך סיום ולוחצים על שליחה.

הענקת הרשאות IAM לחשבון השירות של Google SecOps

לחשבון השירות של Google SecOps צריך להיות התפקיד צפייה באובייקט אחסון בקטגוריה של GCS.

  1. עוברים אל Cloud Storage > Buckets (קטגוריות).
  2. לוחצים על שם הקטגוריה (fsf-logs-secops).
  3. עוברים לכרטיסייה Permissions.
  4. לוחצים על הענקת גישה.
  5. מספקים את פרטי ההגדרה הבאים:
    • Add principals (הוספת ישויות מורשות): מדביקים את כתובת האימייל בחשבון של חשבון השירות של Google SecOps.
    • הקצאת תפקידים: בוחרים באפשרות צפייה באובייקט אחסון.
  6. לוחצים על Save.

אימות ההטמעה

  1. מחכים 10-15 דקות עד שההעברה הראשונית תסתיים.
  2. ב-Google SecOps, עוברים אל SIEM Settings > Feeds (הגדרות SIEM > פידים).
  3. מאתרים את הפיד (FSF File Scanning Logs).
  4. מוודאים שהסטטוס הוא פעיל.
  5. לוחצים על שם הפיד כדי לראות את מדדי ההטמעה.
  6. מוודאים שהערך של Events ingested (אירועים שהמערכת קולטת) עולה.
  7. עוברים אל חיפוש ב-Google SecOps.
  8. מריצים שאילתת חיפוש כדי לוודא שיומני FSF נקלטים:

    metadata.log_type = "FILE_SCANNING_FRAMEWORK"
    
  9. מוודאים שתוצאות הסריקה של FSF מופיעות בתוצאות החיפוש.

פתרון בעיות

לא מופיעים יומנים ב-GCS

  • בודקים ש-FSF כותב יומנים אל /var/log/fsf/:

    ls -lh /var/log/fsf/
    tail -f /var/log/fsf/*.log
    
  • בודקים אם יש שגיאות ביומני Fluentd:

    sudo tail -f /var/log/td-agent/td-agent.log
    
  • מוודאים שמפתח חשבון השירות ב-GCP תקין ושיש לו את ההרשאות הנכונות.

  • מוודאים ששם הקטגוריה בהגדרות של Fluentd זהה לשם הקטגוריה בפועל.

שגיאות הרשאה ב-Fluentd

  • מוודאים שלחשבון השירות (fsf-fluentd-shipper) יש את התפקיד אדמין של אובייקטים באחסון בקטגוריה.
  • בודקים שנתיב המפתח בהגדרות של Fluentd נכון.
  • מוודאים שלקובץ המפתח יש בעלות והרשאות נכונות:

    ls -l /etc/td-agent/gcp-key.json
    

יומנים לא מוטמעים ב-Google SecOps

  • מוודאים שלחשבון השירות של Google SecOps יש תפקיד צפייה באובייקט אחסון בקטגוריה.
  • בודקים שערך ה-URI של מאגר הנתונים בהגדרות הפיד נכון וכולל את התו האחרון של הנתיב (סלאש).
  • מוודאים שהקבצים קיימים בקטגוריה ב-GCS בנתיב הקידומת שצוין.
  • בודקים את סטטוס הפיד בהגדרות SIEM > פידים כדי לראות אם יש הודעות שגיאה.

יומני FSF לא בפורמט הצפוי

  • מוודאים ש-FSF מוגדר לכתוב פלט JSON (התנהגות ברירת המחדל).
  • בודקים שהקטע Fluentd <parse> מוגדר עם @type json.
  • בודקים קובץ יומן באופן ידני כדי לוודא שהוא מכיל קובץ JSON תקין:

    head -n 1 /var/log/fsf/*.log | jq .
    

טבלת מיפוי UDM

שדה ביומן מיפוי UDM היגיון
CompressType_label, compressed_parents about.labels מוזג מ-CompressType_label (מפתח Compress Type, ערך מ-Object.EXTRACT_ZIP.Object_0.Compress Type אם ההודעה מכילה Compress Type) ומ-compressed_parents (מפתח Compressed Parent Files, שרשור מ-Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.additional_info.compressed_parents)
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5, Object.EXTRACT_SWF.META_BASIC_INFO.MD5, Object.EXTRACT_GZIP.META_BASIC_INFO.MD5, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5 intermediary.file.md5 הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5 אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5 אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.MD5 אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.MD5 אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5
Object.EXTRACT_EMBEDDED.Object_0.Description intermediary.file.mime_type הערך הועתק ישירות
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1, Object.EXTRACT_SWF.META_BASIC_INFO.SHA1, Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1 intermediary.file.sha1 הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1 אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1 אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.SHA1 אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1 אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256, Object.EXTRACT_SWF.META_BASIC_INFO.SHA256, Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256 intermediary.file.sha256 הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256 אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256 אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.SHA256 אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256 אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size, Object.EXTRACT_SWF.META_BASIC_INFO.Size, Object.EXTRACT_GZIP.META_BASIC_INFO.Size, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size intermediary.file.size הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.Size אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.Size אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size. הערך הזה נלקח אחרי הסרת התו .* בסוף והמרה למספר שלם לא שלילי.
Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.scan_id intermediary.resource.id הערך הועתק ישירות
Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.permalink intermediary.url הערך הועתק ישירות
Object.META_EMERSON_INFO.results intermediary.user.email_addresses מוזג מ-matched_email במערך התוצאות
Summary.Observations metadata.description המחרוזת נוצרה מאיחוד של מערך עם מפריד של ', ', והפסיק המוביל הוסר
זמן הסריקה metadata.event_timestamp ההמרה בוצעה באמצעות מסנן תאריכים בפורמט yyyy-MM-dd HH:mm:ss
מקור metadata.event_type הערך הוא SCAN_FILE אם המקור לא ריק, אחרת GENERIC_EVENT
Object.META_VT_CACHE._id metadata.product_log_id הערך הועתק ישירות
result.ad_data.message network.http.response_code הערך מחולץ כמספר שלם באמצעות תבנית grok ‏INT מהתוצאה result.ad_data.message
מקור principal.hostname הערך הועתק ישירות
Object.META_EMERSON_INFO.result_summary, Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg security_result.summary הערך מוגדר ל-Object.META_EMERSON_INFO.result_summary אם הוא קיים, אחרת ל-Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg
שם קובץ target.file.full_path הערך הועתק ישירות
Object.META_BASIC_INFO.MD5 target.file.md5 הערך הועתק ישירות
Summary.Yara target.file.mime_type הערך חולץ מהאינדקס הראשון של Summary.Yara, הומר לאותיות רישיות והוסר ממנו הערך FT_ אם Yara קיים, אחרת הערך מוגדר כ-ZIP אם EXTRACT_ZIP קיים, כ-SWF אם EXTRACT_SWF קיים, כ-GZIP אם EXTRACT_GZIP קיים וכ-CAB אם EXTRACT_CAB קיים
Object.META_BASIC_INFO.SHA1, Object.META_VT_CACHE.SHA1 target.file.sha1 ערך מ-Object.META_BASIC_INFO.SHA1 אם הוא לא ריק, אחרת מ-Object.META_VT_CACHE.SHA1
Object.META_BASIC_INFO.SHA256 target.file.sha256 הערך הועתק ישירות
Object.META_BASIC_INFO.Size target.file.size הוסר ממנו הסיומת " .*" והוא הומר למספר שלם לא שלילי
metadata.vendor_name ההגדרה היא EMERSON
metadata.product_name ההגדרה היא FILE SCANNING FRAMEWORK (מסגרת לסריקת קבצים)

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