Linux וכלי פיתוח
יסודות Bash לעבודת אבטחה
pipes, הפניות, משתנים, לולאות, קודי יציאה ו-set -euo pipefail, ואז שימוש בהם כדי לספור התחברויות כושלות ולחשב hash לתיקייה.
בעלים וקבוצות ב-Linux, ביטי rwx, chmod, umask ו-setuid, עם מעבדה שבודקת גישה כמשתמש שני ומוצאת הרשאות קבצים מסוכנות.
הרשאות Linux קובעות מי יכול לקרוא, לשנות ולהריץ כל קובץ במערכת. רוב הבעיות שעולות בסקירת אבטחה הן לא אקספלויטים אקזוטיים. הן קובץ קונפיגורציה שכל חשבון מקומי יכול לכתוב אליו, סקריפט ששירות root מריץ אבל משתמש רגיל יכול לערוך, או בינארי עם ביט setuid שאיש לא זוכר שהוסיף. המאמר הזה בונה את המנגנון מלמטה למעלה: בעלים, קבוצות, ביטי rwx, chmod, umask והביטים המיוחדים שהכי חשובים בסקירה. יוצרים קבצים, משנים את ההרשאות שלהם, בודקים גישה כמשתמש מקומי שני ב-VM של מעבדה ומחפשים הרשאות מסוכנות.
הרעיון המרכזי הוא הרשאה מינימלית. לתהליך צריכה להיות רק הגישה שהוא צריך, ורק האנשים והתוכנות שאמורים לשנות קובץ צריכים הרשאת כתיבה אליו. הרשאות קבצים הן המקום הראשון שבו Linux אוכף את הכלל הזה, ולכן הן הדבר הראשון שבודקים.
כל קובץ ותיקייה נושאים שלושה דברים שקובעים גישה:
מריצים את זה על כל קובץ בתיקיית הבית:
ls -l notes.txtהתו הראשון הוא סוג הקובץ (- הוא קובץ רגיל, d הוא תיקייה, l הוא קישור סמלי). תשעת התווים הבאים הם ההרשאות. שמות הבעלים והקבוצה באים אחרי מספר הקישורים.
הליבה בודקת הרשאות בכל פעם שתהליך פותח קובץ. shell, שרת web ו-cron job עוברים כולם את אותה בדיקה. אם הבדיקה נכשלת, מתקבל Permission denied. למערכת הקבצים לא משנה אם התהליך מהימן.
בהרשאות יש שלוש שלישיות, אחת לכל סוג משתמש:
Linux בודק את הסוגים לפי הסדר. אם החשבון שלך הוא הבעלים, חלים ביטי הבעלים, ומתעלמים מביטי הקבוצה והאחרים, גם כשהם היו נותנים יותר. זה מפתיע אנשים. קובץ שביטי הבעלים שלו הם --- לא ייפתח לבעלים שלו, גם אם ביטי הקבוצה הם rwx והבעלים שייך לאותה קבוצה.
חברות בקבוצה היא רשימה נפרדת. בודקים את שלך עם:
id
groupsשינוי בחברות בקבוצה נכנס בדרך כלל לתוקף בהתחברות הבאה, ולא ב-shell שבו הורצה הפקודה.
כל שלישייה מחזיקה שלושה ביטים:
| ביט | על קובץ רגיל | על תיקייה |
|---|---|---|
r (קריאה, ערך 4) |
קריאת התוכן | הצגת השמות שבפנים |
w (כתיבה, ערך 2) |
שינוי התוכן | יצירה, שינוי שם או מחיקה של רשומות |
x (הרצה, ערך 1) |
הרצה כתוכנית | כניסה לתיקייה והגעה לרשומות שלה |
שתי נקודות מכשילות מתחילים.
ראשית, הביט x של תיקייה הוא מה שמאפשר לעבור דרכה. תיקייה עם r בלי x מאפשרת לראות שמות אבל לא לפתוח אותם. תיקייה עם x בלי r מאפשרת לפתוח קובץ ששמו המדויק כבר ידוע, אבל לא להציג את התיקייה.
שנית, הרשאת כתיבה על קובץ לא מאפשרת למחוק אותו. מחיקה תלויה בהרשאות כתיבה והרצה על התיקייה שמחזיקה את הרשומה. גם קובץ בבעלותך אי אפשר למחוק אם הוא בתוך תיקייה שאין לך הרשאת כתיבה אליה.
chmod מקבל שני כתיבים לאותו דבר.
אוקטלי. כל שלישייה הופכת לספרה אחת, סכום הביטים שלה: r הוא 4, w הוא 2, x הוא 1. לכן rw- הוא 6, r-- הוא 4, r-x הוא 5 ואילו rwx הוא 7. המצב 644 פירושו קריאה וכתיבה לבעלים (6), קריאה לקבוצה (4), קריאה לאחרים (4). המצב 600 פירושו שרק הבעלים יכול לקרוא או לכתוב.
סמלי. נוקבים בסוג, באופרטור ובביטים:
u (בעלים), g (קבוצה), o (אחרים), a (כולם). בלי סוג, ההנחה היא a, אלא שביטי umask נשארים ללא שינוי.+ מוסיף ביטים, - מסיר אותם, = קובע בדיוק את הביטים האלה בסוג ומאפס את השאר.לכן chmod u=rw,go=r notes.txt נותן את אותה תוצאה כמו chmod 644 notes.txt. chmod g+w notes.txt מוסיף כתיבה לקבוצה ומשאיר את שאר הביטים כמו שהם.
אוקטלי קומפקטי וקל להדבקה בסקריפטים. סמלי בטוח יותר לשינוי בודד, כי הוא לא מוחק ביטים שלא חשבת עליהם. שניהם מופיעים בסקירה, בקובצי ניהול קונפיגורציה, ב-Dockerfiles ובסקריפטי התקנה.
chmod משנה את ההרשאות. רק הבעלים של קובץ או root יכולים להריץ את הפקודה עליו בהצלחה. כל אחד אחר מקבל Operation not permitted.
הרגל בטוח הוא לקרוא את ההרשאות, לשנות אותן ולקרוא שוב:
stat -c '%a %A %U:%G %n' notes.txt
chmod 600 notes.txt
stat -c '%a %A %U:%G %n' notes.txtstat -c מדפיס את המצב האוקטלי (%a), המצב הסמלי (%A), שמות הבעלים והקבוצה (%U, %G) ואת שם הקובץ (%n). הפורמט הזה משמש לאורך כל המעבדה.
chown משנה את הבעלים, ואת הקבוצה משנה chgrp. שינוי בעלות למשתמש אחר דורש בדרך כלל root. לא מריצים chown -R על עץ לפני שמציגים במה הוא ייגע.
כשתוכנית יוצרת קובץ, היא מבקשת מצב התחלתי. לקובץ רגיל הערך ההתחלתי הוא 666. לתיקייה הוא 777. ה-umask מסיר ביטים מהערך ההתחלתי הזה. ה-shell קובע אותו, וכל קובץ ותיקייה שה-shell ותהליכי הבן שלו יוצרים עוברים דרכו.
ברוב הפצות Linux ברירת המחדל היא 022. בקובץ, 666 פחות 022 הוא 644, כך שקבצים חדשים הם rw-r--r--. בתיקייה, 777 פחות 022 הוא 755, כך שתיקיות חדשות הן rwxr-xr-x. ה-umask רק מסיר הרשאות. מצב לא יכול להיות מתירני יותר מהערך ההתחלתי.
בודקים את הערך שלך:
umaskumask מחמיר יותר כמו 077 נותן קבצי 600 ותיקיות 700, שרק הבעלים יכול לגשת אליהם. רופף יותר כמו 002 נותן קבצי 664 ותיקיות 775, שהקבוצה יכולה לכתוב אליהם. umask שמוגדר בפרופיל shell משפיע על ה-shell הזה ועל תהליכי הבן שלו. הוא לא משנה קבצים שכבר קיימים.
מצבים אוקטליים בני ארבע ספרות מוסיפים ספרה מובילה לשלושה ביטים מיוחדים:
/tmp היא הדוגמה הקלאסית.ls -l מציג setuid בתור s במיקום ההרצה של הבעלים, ו-sticky בתור t במיקום ההרצה של האחרים. ב-Ubuntu 24.04 השורה של passwd נראית כך:
-rwsr-xr-x 1 root root 64152 May 30 2024 /usr/bin/passwdתוכנות כמו passwd צריכות setuid כי הן חייבות לכתוב לקובצי חשבון מוגנים בשם משתמש רגיל. הסיכון הוא שכל בינארי setuid של root מאפשר למשתמש רגיל להריץ קוד עם הרשאות root. באג באחד מהם, כמו השחתת זיכרון או קריאה לא בטוחה לתוכנית עזר, יכול להפוך להסלמת הרשאות מקומית. סוקרים מחזיקים רשימה קצרה של בינאריי setuid ומשווים אותה לקו בסיס ידוע. קובץ setuid חדש שאיש לא התקין בכוונה הוא ממצא שצריך תשובה.
קבצים שכל אחד יכול לכתוב אליהם הם הבעיה הנפוצה השנייה. קובץ עם o+w מאפשר לכל חשבון מקומי לשנות את התוכן שלו. אם הקובץ הזה הוא סקריפט, קונפיגורציה ששירות root קורא או בינארי בתיקייה שנמצאת במשתנה PATH, התוקף לא צריך אקספלויט. הוא עורך את הקובץ. בודקים גם תיקיות. תיקייה פתוחה לכתיבה בנתיב ש-root מריץ ממנו יכולה לאפשר לתוקף להחליף קובץ גם כשהקובץ עצמו נעול.
מריצים את זה בסביבת Linux שבשליטתך: הפצת WSL או VM שנוצר לקורס הזה. לא מריצים על שרת פרודקשן או על מחשב משותף. החלק של המשתמש השני יוצר חשבון, ולכן עושים אותו רק ב-VM המעבדה שלך.
mkdir ~/permlab && cd ~/permlab
echo 'lab secret' > notes.txt && ls -l notes.txtב-Ubuntu 24.04 תחת WSL, הקובץ החדש הציג -rw-r--r-- עם בעלים וקבוצה בשם החשבון. שם המשתמש, התאריך והקבוצה אצלך יהיו שונים. משווים את ההרשאות.
chmod 600 notes.txt && stat -c '%a %U:%G %n' notes.txt
umaskהפלט שהתקבל:
600 usurio:usurio notes.txt
0022שם החשבון אצלך יהיה שונה. 600 פירושו שרק הבעלים יכול לקרוא ולכתוב. 0022 הוא ה-umask ב-shell הנוכחי, והאפס המוביל הוא חלק מהצורה האוקטלית.
עכשיו תיקייה:
mkdir sub && chmod 750 sub && stat -c '%a %n' subהתקבל: 750 sub. לבעלים יש גישה מלאה, הקבוצה יכולה לקרוא ולהיכנס, ולמשתמשים אחרים אין כלום.
שינויים סמליים, אחד בכל פעם, עם קריאה אחרי כל אחד:
chmod u=rw,go=r notes.txt && stat -c '%a %A %n' notes.txt
chmod g+w notes.txt && stat -c '%a %A %n' notes.txt
chmod o-r notes.txt && stat -c '%a %A %n' notes.txtהתקבל:
644 -rw-r--r-- notes.txt
664 -rw-rw-r-- notes.txt
660 -rw-rw---- notes.txtכל פקודה שינתה רק את הביטים שצוינו בה.
מריצים umask ב-subshell כדי שהשינוי לא יישאר בסשן שלך:
(umask 077; touch private.txt; stat -c '%a %A %n' private.txt)
(umask 002; touch shared.txt; mkdir made_dir; stat -c '%a %A %n' shared.txt made_dir)התקבל:
600 -rw------- private.txt
664 -rw-rw-r-- shared.txt
775 drwxrwxr-x made_dirעם 077, הקובץ איבד כל ביט של קבוצה ושל אחרים. עם 002, הקבוצה קיבלה כתיבה גם על הקובץ וגם על התיקייה. התיקייה התחילה בערך 777 ואיבדה רק 002.
השלב הזה צריך חשבון שאפשר ליצור ב-VM שלך. מריצים אותו רק שם.
sudo useradd -m labuser
sudo -u labuser cat ~/permlab/notes.txtלא הרצתי את הפקודות האלה. חשבון ה-WSL צריך סיסמה עבור sudo, ולא הזנתי כזאת. מה לחפש: עם מצב 600, הפקודה השנייה אמורה להיכשל בהודעת Permission denied, כי labuser הוא לא הבעלים ולא בקבוצה.
בשלב הבא מרחיבים את הרשאות הקובץ עבור אחרים:
chmod 644 notes.txt
sudo -u labuser cat ~/permlab/notes.txtמה לחפש: התוכן מודפס רק אם labuser יכול גם להיכנס לתיקיית הבית שלך וגם לתיקייה ~/permlab. הפצות רבות יוצרות תיקיות בית במצב 755, אבל חלקן במצב 750. אם תיקיית אב מונעת x ממשתמשים אחרים, הקריאה עדיין נכשלת, גם עם קובץ קריא. בודקים עם ls -ld ~ ~/permlab. בהתקנת Ubuntu 24.04 ב-WSL שבה השתמשתי, ls -ld ~ הדפיס drwxr-x---, כלומר 750, ולכן משתמש שני היה נחסם שם גם אחרי chmod 644. זה הביט x של תיקייה שתואר קודם, בפועל.
מציגים קבצים רגילים שכל אחד יכול לכתוב אליהם תחת תיקיית הבית, בלי לחצות למערכות קבצים אחרות:
find ~ -xdev -type f -perm -o+w 2>/dev/nullבמעבדה נקייה זה לא מדפיס כלום. כדי לראות את החיפוש עובד, פותחים בכוונה קובץ אחד לכתיבה:
chmod 666 ~/permlab/notes.txt
find ~ -xdev -type f -perm -o+w 2>/dev/null
chmod 644 ~/permlab/notes.txtהתקבל: החיפוש הראשון הדפיס /home/usurio/permlab/notes.txt. אחרי התיקון, אותו חיפוש לא הדפיס כלום.
מציגים בינאריי setuid בתיקיית מערכת:
find /usr/bin -perm -4000 -type f 2>/dev/null | sortב-Ubuntu 24.04 תחת WSL התקבלו עשרה קבצים, כולל /usr/bin/passwd, /usr/bin/sudo, /usr/bin/su, /usr/bin/mount וגם /usr/bin/umount. הרשימה אצלך תלויה בהפצה ובחבילות המותקנות. בסקירה משווים את הרשימה למה שמנהל החבילות אומר שאמור להיות setuid. רשומה לא צפויה היא שאלה שצריך לענות עליה, ולא הוכחה לתקיפה.
בודקים את ה-sticky bit על תיקיות זמניות:
stat -c '%a %A %n' /tmp /var/tmpהתקבל: 1777 drwxrwxrwt בשתיהן. האות t אומרת שמשתמשים יכולים ליצור שם קבצים אבל לא למחוק קבצים ששייכים למישהו אחר.
rm -rf ~/permlab
sudo userdel -r labuseruserdel -r מוחק גם את תיקיית הבית של החשבון. מריצים אותו רק עבור חשבון המעבדה שנוצר.
אותם צעדים ראשונים ב-Git Bash ל-Windows לא התנהגו כמו Linux. אחרי chmod 600 notes.txt, stat עדיין דיווח 644, וקריאות chmod מאוחרות יותר לא שינו גם הן את הפלט. Windows שומר גישה ברשימות בקרת גישה של NTFS, ו-Git Bash ממפה רק חלק מהביטים. מעבדת Windows יכולה ללמד את הפקודות, אבל לא להראות מה מצב של Linux עושה. למאמר הזה משתמשים ב-WSL עם הפצת Linux, או ב-VM.
שימוש במצב 777 כדי לתקן שגיאת גישה. זה עובד, וזה גם מאפשר לכולם לכתוב ולהריץ את הקובץ. מאתרים איזה סוג נדחה ונותנים רק לו.
שכחת התיקייה. קובץ קריא עדיין יכול להיות בלתי נגיש אם לתיקיית אב אין x עבור המשתמש. בודקים כל תיקייה בנתיב.
שימוש בפקודה chmod -R על עץ שלם. שינויים רקורסיביים מגדירים לעיתים קרובות הרצה על קבצים רגילים או מסירים אותה מתיקיות. משתמשים בפקודה find עם -type f או -type d כדי לכוון לסוג אחד.
אמון בהרשאות של קובץ שהועתק. cp, tar וכלי ארכיון עשויים לשמור או לאפס הרשאות לפי דגלים. בודקים את התוצאה עם stat.
קריאה של מצבים סמליים כמוחלטים. chmod g+w מוסיף ביט אחד. chmod g=w מאפס קריאה והרצה לקבוצה. קל לפספס את ההבדל.
קפיצה ל-root קודם. בעיות קריאה וכתיבה רבות נפתרות עם חברות בקבוצה או מצב תיקייה, ולא עם תוכנית עזר setuid או shell של root.
סקירת הרשאות מתחילה בשאלה אחת: מי יכול לשנות את מה שתהליך בעל הרשאות קורא או מריץ? שלושה ממצאים חוזרים שוב ושוב:
בכתיבת ממצא, נוקבים בנתיב, בהרשאות, בבעלים, בקבוצה, בתהליך שקורא או מריץ אותו ובשינוי שמתקן אותו. בודקים במעבדה שלך. לא מריצים את החיפושים האלה מול מערכות שאינן בניהולך, ולא מריצים sudo -u על מחשב של מישהו אחר.
כשההרשאות הבסיסיות ברורות, לומדים רשימות בקרת גישה עם getfacl ועם setfacl, שמוסיפות רשומות לכל משתמש מעבר לבעלים, לקבוצה ולאחרים. קוראים את המדריך של chattr על דגלי immutable ו-append-only. namei -l /path/to/file מדפיס את ההרשאות של כל רכיב בנתיב. זו הדרך המהירה ביותר למצוא את התיקייה שחוסמת שירות.
להרגלי ה-shell שמאחורי הפקודות האלה, מתחילים מהמאמר הקודם של מדריך השטח על יסודות Bash לסטודנטים לאבטחה. המאמר הבא, מה זה SSH ואיך מפתחות SSH עובדים, עוסק במפתחות SSH, שתלויים באותן הרשאות: קובץ המפתח הפרטי חייב להיות קריא רק לבעלים שלו, ולקוח SSH מסרב להשתמש במפתח שההרשאות שלו פתוחות מדי.
הרשאה מינימלית מתחילה בהרשאות קבצים. תהליך שיכול לכתוב פחות גורם פחות נזק כשהוא טועה, וקובץ שאחרים לא יכולים לשנות הוא דבר אחד פחות לסקור.
Linux וכלי פיתוח
pipes, הפניות, משתנים, לולאות, קודי יציאה ו-set -euo pipefail, ואז שימוש בהם כדי לספור התחברויות כושלות ולחשב hash לתיקייה.
Linux וכלי פיתוח
איך מפתחות מארח ומשתמש של SSH עובדים, למה Ed25519 עם passphrase הוא ברירת המחדל, ואיך מגדירים ומקשיחים התחברות במפתח על VM של מעבדה בבעלותך.
Linux וכלי פיתוח
GitHub למתחילים: מה Git ו-GitHub עושים, המונחים הבסיסיים, תרגול Git מקומי ואיך בודקים פרויקט לפני שמריצים אותו.