
בעולם המחשוב המודרני, חששות אבטחה חורגים מעבר לפגיעויות של מערכות הפעלה (OS) ובאגים בתוכנה. במעמקי ההפשטות, המעבדים שלנו פיתחו מיקרו-ארכיטקטורות מורכבות - צינורות, מטמונים, מאגרי זיכרון ומנועי ביצוע - שנועדו להפיק את הביצועים המקסימליים. באופן אירוני, תכונות אלו מציגות סיכוני אבטחה חדשים ועדינים, היוצרים את מה שמכונה התקפות מיקרו-ארכיטקטוניות. התקפות אלו מנצלות את השיתוף והדליפה הלא-מכוונים של מצב מיקרו-ארכיטקטורי בין אפליקציות שפועלות במקביל, לעיתים אפילו בתוכנה מאובטחת לגמרי.
פוסט בלוג מקיף זה נועד להסביר את ההתקפות המיקרו-ארכיטקטוניות, תוך כיסוי:
בין אם אתה מתחיל, חוקר, מפתח תוכנה או מומחה לאבטחת סייבר, מדריך זה יצייד אותך להבין את ההתקפות המודרניות החזקות הללו - ואיך להגן מפניהן.
התקפות מיקרו-ארכיטקטוניות הן טכניקות ניצול המנצלות דליפות מידע בלתי מכוונות בעיצוב הנמוך של חומרת המעבד.
בניגוד לניצול תוכנה טיפוסי, התקפות מיקרו-ארכיטקטוניות אינן דורשות באגים בתוכנה או במערכת ההפעלה. במקום זאת, הן מנצלות את הדרך שבה מעבדים מודרניים מנסים למקסם ביצועים, כמו על ידי שיתוף מטמונים או שינוי סדר ההוראות.
מעבדים מודרניים משתפים מבנים קריטיים בחומרה בין אפליקציות ואפילו מכונות וירטואליות, כגון:
בגלל שמבנים אלו אינם מבודדים בצורה מושלמת, לרוב תהליך אחד יכול לצפות או להסיק את השפעות תהליך אחר. תוקפים מנצלים שיתוף לא מכוון זה כדי לחלץ סודות על ידי התבוננות באפקטים פיזיים עקיפים (כמו שינויים קלים בזמני גישות לזיכרון).
ישנן שתי קטגוריות עיקריות:
ערוצים סמויים יוצרים נתיב תקשורת בין שני פועלים (שולח ומקבל) שלא היה אמור להיות על ידי עיצוב המערכת. אפליקציה אחת משנה משאב משותף, בעוד אחרת מתבוננת בשינויים אלו כדי לשחזר הודעה.
דוגמאות:
התקפות ערוצי צד דולפות מידע רגיש בלי תקשורת ישירה. במקום זאת, הן מנצלות מידע "נשפך" עקב פעילות הקורבן.
דוגמאות:
שני הערוצים מאפשרים לתהליך אחד להסיק מידע על אחר - לעיתים כשהם חוצים גבולות מכולה, מכונה וירטואלית או משתמש.
מערכות מחשוב הטרוגניות כוללות סוגי מעבדים מרובים (מעבדים כללים, GPU, FPGA, מאיצי AI ועוד) באותה פלטפורמה, לעיתים חולקים חלק מזיכרון משותף ו/או מצב מיקרו-ארכיטקטורי.
נניח ש-GPU ו-CPU משתפים אזור מטמון. תהליך בעל הרשאות נמוכות שרץ על ה-GPU יכול "להתאים" את המטמון, ותהליך בעל הרשאות גבוהות שרץ על ה-CPU יכול ללא ידיעה לחשוף סודות דרך גישותיו לזיכרון. לאחר מכן תהליך בעל הרשאות נמוכות יכול לצפות בשינויים ולפרש מידע מוגן.
RISC-V היא ארכיטקטורת הוראות פתוחה, מודולרית, שתופסת פופולריות מהירה עבור מערכות קבועות למחקר ומסחריות. בעוד שהתקפות מיקרו-ארכיטקטוניות נבדקו היטב על x86 ו-ARM, מחקרים אחרונים מראים ש-RISC-V אף היא חשופה.
רעיון מרכזי: אף סט הוראות או חומרה פתוחה אינם חסינים - לכל CPU עם מיקרו-ארכיטקטורה משותפת יש חשיפות, אלא אם כן עברו התקשות מיוחדת.
תחום חדשני: התקפות מנוע ה-stack (מקור)
אם תוקף וקרבן משתפים CPU, על ידי ביצוע פעולות stack עם תזמונים מותאמים וצפייה בתוצאות, התוקף יכול להסיק איזו פעילות stack ביצע הקרבן לאחרונה.
Spectre ו-Meltdown (2018) הבהירו לעולם שהתקפות מיקרו-ארכיטקטוניות אינן תאוריה - הן משפיעות על מיליארדי מחשבים.
[תהליך קרבן] [תהליך תוקף]
מבצע פקודה על נתונים סודיים מתאם מטמון, מתזמן גישות
---[שיתופי מטמון פיזי]---
Prime+Probe היא התקפה קלאסית שפועלת כך:
כמו לשים מטבעות על כל המושבים בקולנוע (prime), כאשר מישהו אחר נכנס (קרבן), ואז לבדוק אילו מושבים ריקים (probe) - ולגלות היכן הקרבן ישב, מבלי להתבונן בו ישירות.
התקפות לאחרונה מתמקדות באופטימיזציה של מנוע ה-stack:
חשוב להדגיש: התקפות מעשיות על מערכות ייצור אינן חוקיות ללא הסכמתן. עם זאת, מדידות ביצועים החושפות ערוצי זמן צדדיים יכולות להתבצע על מכונות הבדיקה שלך לצרכי מחקר והגנה.
בדיקה פשוטה לזיהוי שיתוף מטמון (למשל, במכונות וירטואליות).
#!/bin/bash
buffer=/tmp/testmem
size=1024000
# הקצאת מאגר גדול
dd if=/dev/urandom of="$buffer" bs=1K count=1000
# גישה חוזרת לנפח כדי "להשתמש" במטמון
function prime_cache {
for i in $(seq 1 $size); do
tail -c +$i "$buffer" | head -c 1 >/dev/null
done
}
# תזמון גישה
function time_access {
/usr/bin/time -f "%e" dd if="$buffer" of=/dev/null bs=1K count=1000 2>&1
}
echo "מתאמה את המטמון..."
prime_cache
echo "מתזמן גישת קריאה..."
time_access
# עכשיו תבקש מתהליך אחר להפעיל עומס עבודה על כל הזיכרון ותחזור
# תשווה כדי לראות אם יש שינוי בתזמון, דבר המצב על תוכן מטמון!
פרש שינויים משמעותיים כעדות לתחזור מטמון עם תהליכים אחרים - שייתכן שמאפשר התקפות Prime+Probe.
שיטה מדויקת יותר משתמשת במודול time של פייתון וב-mnumpy` מערכים לדפוסי גישה לזיכרון חוזרים.
import numpy as np
import time
# הקצאת מערך גדול
arr = np.zeros((1024 * 1024 * 10,), dtype=np.uint8)
def probe_access():
ts = time.time()
# גישה לכל האלמנטים כדי לטעון למטמון
for i in range(0, len(arr), 64):
arr[i] += 1
te = time.time()
print(f"Access time: {te - ts:.6f} seconds")
# הרצה ראשונה: כנראה קרה (ייתכן שיתקע)
probe_access()
# הרצה שנייה: סביר שהמטמון חם
probe_access()
עכשיו, בטרמינל שני (או בתהליך נפרד), הפעל סקריפט מתשמש בזיכרון (למשל, stress-ng או דומה), שעשוי להתגם שורות מטמון. הרץ שוב את probe_access() והבחין בהבדל בזמן ההגשה.
בהינתן המשכיות התקפות מיקרו-ארכיטקטוניות, מה יכולים להגן כוחות אבטחה לעשות?
# בדיקה לתכונות מעבד קשורות לשטיפה
grep . /proc/cpuinfo | grep -E 'flush|clflush|clwb'
# ייתכן שיופיע: clflush, שמצביע על הוראות זמינות לתוכנה לנקות מטמונים
רבים מיצרני ה-CPU מציגים תכונות כגון:
עם זאת, רוב ה-CPUs הנפרסים עדיין רגישים, במיוחד בסביבת הענן או בחומרה מורכבת.
התקפות מיקרו-ארכיטקטוניות אינן עוד "סקרנות תיאורטית". ככל שמעבדים שלנו הופכים לאופטימליים יותר - ויותר משותפים - ההבדלים המשניים בעיצובים הפנימיים שלהם הופכים לכלים רבי עוצמה בידי תוקפים מיומנים.
בפרט במערכות הטרוגניות, שבהן מעבדים, GPUs ומאיצים חולקים מצב מיקרו-ארכיטקטורי, ערוצים סמויים וצדדיים אינם רק אפשריים - הם קיימים במציאות. התקפות אחרונות נגד מעבדי RISC-V ומנוע ה-stack מראות את האוניברסליות והרלוונטיות המתמשכת של סיכונים אלו, אף עבור ארכיטקטורות חדשות ואופטימיזציות.
הישאר עדכני, בדוק את הסביבות שלך, ודורש בידוד טוב יותר - הן בתוכנה והן בחומרה.
פוסט זה נועד למטרות חינוך בלבד. תמיד בדוק בסביבות בטוחות ומבוקרות.
אם מצאתם את התוכן הזה בעל ערך, תארו לעצמכם מה תוכלו להשיג עם תוכנית ההכשרה המקיפה והאליטיסטית שלנו בת 47 שבועות. הצטרפו ליותר מ-1,200 סטודנטים ששינו את הקריירה שלהם בעזרת טכניקות יחידה 8200.