GammaCyber

לינוקס מתקדם CLI

Low-Level: C, Assembly ו-RE · 5–6 שעות

// סקירה

לינוקס מתקדם CLI — Pipes, הפניות וחיפוש

שיעור זה לוקח אתכם מ"יודע פקודות בסיסיות" ל"יכול לבנות שרשרות פקודות עוצמתיות". Pipe, Redirection, grep, find ו-xargs הם הליבה של כל עבודת CLI אמיתית — ובמיוחד ב-CTF.

✓נושאי השיעור
  • Pipe (|) — שרשור פקודות: stdout של אחת = stdin של הבאה
  • Redirection: >, >>, < — הפניית קלט ופלט לקבצים
  • stderr (2>) ו-/dev/null — השתקת שגיאות
  • grep — חיפוש וסינון טקסט, -i, -r, -n, -v, -c, Regex
  • wc — ספירת שורות, מילים ו-bytes
  • find — חיפוש קבצים לפי שם, הרשאות, גודל, זמן
  • xargs — המרת פלט pipe לארגומנטים לפקודה אחרת
  • sort, uniq, cut, awk — עיבוד טקסט מתקדם
  • שרשורי Pipes מורכבים — ניתוח לוגים ב-CTF
// פרק 1

Pipe — שרשור פקודות

הכוח האמיתי של Linux CLI: לקחת את פלט פקודה אחת ולהזרים אותו ישירות כקלט לפקודה הבאה. Pipe = | (Vertical Bar).

עקרון Unix: פקודות קטנות שמשתלבות יחד
כל פקודה עושה דבר אחד טוב. Pipe מחבר אותן לשרשרת עוצמתית. cmd1 | cmd2 | cmd3 — stdout של cmd1 = stdin של cmd2, וכן הלאה.
# דוגמה 1: כמה תהליכים של apache רצים? ps aux | grep apache | wc -l # דוגמה 2: 10 הקבצים הכבדים ביותר ב-/var/log ls -lS /var/log | head -10 # דוגמה 3: מי מחובר למערכת, ללא כפילויות? who | awk '{print $1}' | sort | uniq # דוגמה 4: חיפוש flags ב-CTF grep -r "flag{" /home/ 2>/dev/null | head -20 # דוגמה 5: שמות כל המשתמשים ממוינים cut -d: -f1 /etc/passwd | sort
הרחבה Pipe הוא תהליך מקביל — לא סדרתי! ›

Pipe לא מחכה לפקודה הראשונה לסיים. שתי הפקודות רצות בו-זמנית. הנתונים זורמים בין תהליכים דרך buffer של הkernel. לכן cat huge_file | grep pattern יעיל — grep מעבד בזמן שcat קורא.

✏תרגול עצמי2 שאלות
שאלה 1.1
מה עושה השרשרת: ps aux | grep apache | wc -l?
✓ תשובה: ג) — ps aux = כל תהליכים. | grep apache = סנן רק שורות עם "apache". | wc -l = ספור שורות (= מספר תהליכים). השרשרת = 3 פעולות, תוצאה אחת.
שאלה 1.2
מה ההבדל בין | לבין >?
✓ תשובה: א) — cmd1 | cmd2 = stdout של cmd1 → stdin של cmd2 (תהליך חי). cmd1 > file = stdout של cmd1 → נשמר לקובץ (נכתב לדיסק).
// פרק 2

Redirection — הפניית קלט ופלט

כל תוכנית ב-Linux עובדת עם שלושה ערוצים: stdin (0), stdout (1), stderr (2). Redirection שולטת לאן כל ערוץ הולך.

אופרטורערוץפעולהדוגמה
>stdout (1)כתוב לקובץ (דרוס!)ls /etc > list.txt
>>stdout (1)הוסף לסוף קובץ קייםdate >> log.txt
<stdin (0)קרא מקובץsort < names.txt
2>stderr (2)הפנה שגיאות לקובץcmd 2> errors.txt
2>&1stderr→stdoutשלח שגיאות לאותו מקום כמו stdoutcmd > out.txt 2>&1
2> /dev/nullstderr (2)השתק שגיאות (חור שחור)find / -name "*.key" 2> /dev/null
# כתוב רשימת קבצים לקובץ ls /etc > ~/etc_list.txt # הוסף תאריך לסוף לוג קיים (לא דורס!) date >> ~/security_log.txt # חיפוש קבצים — השתק "Permission denied" find / -name "*password*" 2> /dev/null # שמור stdout לקובץ, שגיאות לקובץ אחר ./script.sh > output.txt 2> errors.txt # /dev/null — "החור השחור" של Linux # כל מה שנכתב אליו נעלם לצמיתות echo "unwanted" > /dev/null # נעלם cat /dev/null # מחזיר כלום
! > דורס — >> מוסיף. זה ההבדל ›

> (כתיבה): מוחקת כל תוכן קיים בקובץ לפני כתיבה — מסוכן!

>> (הוספה): מוסיף לסוף הקובץ מבלי לפגוע בתוכן הקיים.

כלל: לוגים ורשומות = תמיד >>. כתיבה חדשה = >.
✏תרגול עצמי3 שאלות
שאלה 2.1
איזה אופרטור מוסיף פלט לסוף קובץ קיים מבלי לדרוס את התוכן הישן?
✓ תשובה: ד) >> — Append: מוסיף לסוף הקובץ. > = Override: מוחק הכל וכותב מחדש. | = Pipe: לא קובץ. < = קריאה מקובץ.
שאלה 2.2
אתם מריצים סקריפט סריקה שמייצר המון שגיאות. רוצים שהשגיאות יעלמו אבל הפלט התקין ייוצג על המסך. איזו פקודה?
✓ תשובה: ד) 2> /dev/null — ערוץ 2 = stderr = השגיאות. הניתוב שלו ל-/dev/null משמיד רק שגיאות. ערוץ 1 (stdout) ממשיך למסך. א) ו-ב) = ההפך: משתיק stdout.
שאלה 2.3 — Dry Run
מה מכיל הקובץ out.txt לאחר: echo "A" > out.txt; echo "B" >> out.txt; echo "C" > out.txt?
✓ תשובה: א) C בלבד — echo "A" > = כותב A. echo "B" >> = מוסיף B (out.txt = A,B). echo "C" > = דורס הכל, כותב C בלבד. out.txt = "C".
// פרק 3

grep — חיפוש וסינון טקסט

grep (Global Regular Expression Print) — סורק קבצים שורה אחר שורה ומחזיר רק שורות שתואמות לתבנית. אחד הכלים הכי שימושיים בכל עבודת CLI.

grep "pattern" file.txt # חיפוש בסיסי grep -i "pattern" file.txt # Case-insensitive grep -r "pattern" /etc/ # Recursive — כל ספריה grep -n "pattern" file.txt # הצג מספרי שורות grep -v "pattern" file.txt # Invert — שורות שלא מכילות grep -c "pattern" file.txt # ספור כמה שורות תואמות grep -l "pattern" *.txt # רק שמות קבצים grep -A 3 "pattern" file.txt # 3 שורות אחרי ההתאמה grep -B 2 "pattern" file.txt # 2 שורות לפני ההתאמה grep -E "pat1|pat2" file.txt # Extended Regex — OR # דוגמאות CTF: grep -r "password" /etc/ 2>/dev/null # חפש סיסמאות grep -r "flag{" /home/ 2>/dev/null # חפש CTF flags grep "FAILED" /var/log/auth.log # כניסות כושלות ps aux | grep -v grep | grep "python" # תהליכי python
🔑grep ב-CTF — שרשורים חשובים
  • grep -r "password\|pass\|secret" /etc/ 2>/dev/null
  • grep -r "flag{" / 2>/dev/null
  • grep "Accepted\|Failed" /var/log/auth.log
  • cat /etc/passwd | grep -v nologin — רק משתמשים אמיתיים
✏תרגול עצמי3 שאלות
שאלה 3.1
איזה דגל של grep מחפש ללא תלות באותיות גדולות/קטנות?
✓ תשובה: א) grep -i — -i = case-Insensitive. חיפוש "Password" יתאים גם "password", "PASSWORD", "PaSsWoRd". שימושי ב-CTF כשלא יודעים אם שם הקובץ בגדולות.
שאלה 3.2
מה עושה: grep -v "nologin" /etc/passwd?
✓ תשובה: ב) — -v = Invert: מציג שורות שלא מתאימות לתבנית. nologin = שורות של service accounts. -v מציג רק משתמשים אמיתיים (עם /bin/bash וכדומה).
שאלה 3.3 — CTF
אתם מחפשים flags בכל המערכת. איזו פקודה היעילה ביותר?
✓ תשובה: א) — grep -r "flag{" חיפוש רקורסיבי בתוכן כל הקבצים. 2>/dev/null מסתיר שגיאות Permission Denied. ב) מוצא רק קובץ בשם "flag", לא flag בתוך קובץ.
// פרק 4

find ו-wc — חיפוש קבצים וספירה

find מחפש קבצים בכל עץ ספריות לפי כל קריטריון. wc סופר שורות, מילים ו-bytes — שניהם כלי ליבה בסייבר.

find — חיפוש קבצים

# חיפוש לפי שם find / -name "flag.txt" 2>/dev/null find /home -name "*.sh" 2>/dev/null find . -name "*password*" # חיפוש לפי סוג find /tmp -type f # קבצים בלבד find /etc -type d # ספריות בלבד # חיפוש לפי הרשאות — חיוני לPrivEsc! find / -perm -4000 -type f 2>/dev/null # SUID binaries find / -perm -2000 -type f 2>/dev/null # SGID binaries find / -writable -type f 2>/dev/null # קבצים שכולם יכולים לכתוב # חיפוש לפי גודל find /home -size +10M # גדולים מ-10MB find /tmp -size -1k # קטנים מ-1KB # חיפוש לפי זמן find /etc -mtime -7 # שונו ב-7 ימים האחרונים # ביצוע פעולה על כל תוצאה find . -name "*.tmp" -exec rm {} \; find /home -name "*.log" -exec cat {} \;

wc — ספירה

wc -l file.txt # ספור שורות (הנפוץ ביותר!) wc -w file.txt # ספור מילים wc -c file.txt # ספור bytes wc file.txt # הכל: שורות מילים bytes # שימוש נפוץ — ספירת תוצאות: ps aux | grep apache | wc -l # כמה תהליכי apache? grep "Failed" auth.log | wc -l # כמה ניסיונות כושלים? find /tmp -name "*.sh" | wc -l # כמה scripts ב-/tmp?
✏תרגול עצמי3 שאלות
שאלה 4.1
אתם רוצים לגלות כמה תהליכי apache רצים. הפקודה הנכונה לסיים את השרשרת ps aux | grep apache | ___?
✓ תשובה: ד) wc -l — wc -l סופר שורות. כל תהליך = שורה אחת בפלט. wc -w סופר מילים = לא נכון. grep -c גם יעבוד אבל פחות שגרתי בשרשרת.
שאלה 4.2
ב-CTF רוצים למצוא את כל SUID binaries במערכת. איזו פקודה?
✓ תשובה: ב) — -perm -4000 = קבצים עם bit 4000 מוגדר (SUID). -type f = קבצים בלבד. 2>/dev/null = השתק Permission Denied errors. זה השרשרת הקלאסית ל-PrivEsc ב-CTF.
שאלה 4.3
מה עושה: find /etc -mtime -7?
✓ תשובה: ד) — -mtime -7 = modified time פחות מ-7 ימים = שונו בשבוע האחרון. שימושי ב-CTF לגלות קבצי config שהותקנו לאחרונה. +7 = יותר מ-7 ימים.
// פרק 5

xargs — ממיר Pipe לארגומנטים

חלק מהפקודות (rm, cat, chmod) לא מקבלות קלט מ-stdin — הן דורשות ארגומנטים ישירים. xargs לוקח פלט מ-Pipe והופך אותו לארגומנטים.

הבעיה שxargs פותר
find . -name "*.tmp" | rm — לא עובד! rm לא קורא שמות קבצים מstdin.
find . -name "*.tmp" | xargs rm — עובד! xargs ממיר את השורות לארגומנטים של rm.
# בעיה: rm לא יכול לקרוא מ-Pipe ישירות find . -name "*.tmp" | rm # ✗ לא עובד! # פתרון: xargs ממיר לארגומנטים find . -name "*.tmp" | xargs rm # ✓ עובד! # דוגמאות נוספות find /tmp -name "*.log" | xargs cat # הדפס כל לוגים find . -name "*.py" | xargs grep "password" # חפש ב-Python files find / -perm -4000 2>/dev/null | xargs ls -la # פרטי SUID files # -I {} — ציין בדיוק איפה לשים הארגומנט find . -name "*.sh" | xargs -I {} chmod +x {} # חלופה: find עם -exec (לעיתים עדיף) find . -name "*.tmp" -exec rm {} \; find . -name "*.tmp" -delete # הכי יעיל!
! שמות קבצים עם רווחים — בעיית xargs ›

אם שמות הקבצים מכילים רווחים, xargs יפרש כל מילה כארגומנט נפרד. הפתרון: find . -name "*.tmp" -print0 | xargs -0 rm — print0 משתמש בNULL כמפריד במקום רווח.

✏תרגול עצמי2 שאלות
שאלה 5.1
מצאתם 100 קבצי זבל בשם *.tmp. ניסיתם find . -name "*.tmp" | rm אבל נכשל. תיקון נכון?
✓ תשובה: ב) — xargs לוקח את שורות הפלט מ-find והופך אותן לארגומנטים לrm: בפועל מריץ rm file1.tmp file2.tmp .... חלופה טובה: find . -name "*.tmp" -delete.
שאלה 5.2
מה עושה: find . -name "*.py" | xargs grep "password"?
✓ תשובה: ב) — find מוצא כל *.py. xargs מעביר אותם לgrep. grep מחפש "password" בתוכם. מקביל ל-grep -r "password" *.py אבל גמיש יותר.
// פרק 6

עיבוד טקסט — sort, uniq, cut, awk

הכלים שמשלימים את תמונת ה-Pipe. ביחד עם grep — אלה בוני השרשרות החזקות ביותר ב-CLI.

# sort — מיון שורות sort file.txt # סדר אלפביתי sort -n file.txt # סדר מספרי sort -r file.txt # הפוך (Z→A) sort -u file.txt # מיון + הסרת כפילויות sort -k2 file.txt # מיון לפי עמודה 2 # uniq — הסרת כפילויות עוקבות (חייב sort קודם!) sort file.txt | uniq # כפילויות מוסרות sort file.txt | uniq -c # ספור כמה פעמים כל שורה sort file.txt | uniq -d # רק שורות כפולות # cut — חתוך עמודות cut -d: -f1 /etc/passwd # שמות משתמשים בלבד cut -d: -f1,7 /etc/passwd # שם + shell cut -c1-10 file.txt # תווים 1 עד 10 בכל שורה # awk — עיבוד שדות awk '{print $1}' file.txt # שדה ראשון (מופרד ברווח) awk -F: '{print $1,$6}' /etc/passwd # שם + home dir ps aux | awk '{print $2,$11}' | head # PID + command
🔑שרשורי Pipes מורכבים — ניתוח לוגים ב-CTF
  • cut -d: -f1 /etc/passwd | sort — רשימת משתמשים ממוינת
  • ps aux | awk '{print $1}' | sort | uniq -c | sort -rn — מי מריץ הכי הרבה תהליכים
  • grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head — Top IPs לbrute force
✏תרגול עצמי3 שאלות
שאלה 6.1
מה עושה: cut -d: -f1 /etc/passwd | sort?
✓ תשובה: ב) — cut -d: -f1 = חתוך לפי מפריד ":" ולקח שדה 1 = שמות משתמשים. | sort = מיין אלפביתית. תוצאה: רשימת כל המשתמשים ממוינת.
שאלה 6.2 — Dry Run מורכב
מה מציגה הפקודה: sort file.txt | uniq -c | sort -rn | head -3 כאשר file.txt מכיל: alice, bob, alice, carol, bob, alice?
✓ תשובה: ב) — sort = ממיין. uniq -c = ספור: alice×3, bob×2, carol×1. sort -rn = מיין מרובה לקטן: 3 alice, 2 bob, 1 carol. head -3 = 3 ראשונים = כולם. זו הפקודה הקלאסית לניתוח תדירות ב-CTF.
שאלה 6.3 — אתגר CTF
מה עושה: grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -5?
✓ תשובה: ג) — grep מוצא שורות "Failed password". awk שדה 11 = כתובת IP התוקף. sort + uniq -c = ספור כמה פעמים כל IP. sort -rn = מי ניסה הכי הרבה ראשון. head -5 = 5 התוקפים הכי אגרסיביים. זו אנליזת brute force קלאסית!
// תרגול נוסף

תרגול נוסף — Shell: Pipes, Redirection ו-Injection

שאלות העשרה נוספות לחיזוק החומר של השיעור — באותו פורמט בחירה של הקורס.

✏תרגול נוסף3 שאלות
שאלה 7.1 [קל]
מה עושה cat file | sort | uniq -c | sort -rn | head -5?
✓ תשובה נכונה: א — sort → uniq -c (ספירה) → sort -rn (יורד לפי מספר) → head -5. תוצאה: Top 5 שורות שכיחות. חובה למיין לפני uniq.
שאלה 7.2 [בינוני]
מה ההבדל בין > ל->>?
✓ תשובה נכונה: ד — > = דריסה (מאפס ואז כותב). >> = הוספה לסוף. טעות נפוצה ומסוכנת: > על קובץ קיים מוחק אותו. ב-Logs תמיד >>.
שאלה 7.3 [קשה]
סקריפט מריץ TARGET=$(cat /dev/stdin). מה הבעיה אם הקלט מגיע ממשתמש?
✓ תשובה נכונה: א — קלט לא-מסונן שנכנס להקשר של פקודה = Command Injection. 'site.com; rm -rf ~' → Bash מריץ את שתי הפקודות. פתרון: תמיד לצטט ולוודא קלט.
// אתגר מעשי

אתגר מעשי — לינוקס — grep, awk וצינורות

שיא השיעור: היפוך, ניתוח וזיהוי — כלי ה-RE וה-Low-Level בפעולה. ההגשה נבדקת אוטומטית.

T2 · בסיסי200 נק'~15 דק'algorithmic
grep — עם דגלי -v ו--i
ממש grep(lines, pattern, invert=False, ignore_case=False) המחזיר את השורות המכילות את התבנית (התאמת תת-מחרוזת). invert=True (כמו -v) הופך: מחזיר את שאינן מכילות. ignore_case=True (כמו -i) מתעלם מרישיות.
דוגמאות
grep(['apple','banana','grape'], 'ap') → ['apple', 'grape']
grep(['apple','banana'], 'an', invert=True) → ['apple']
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס grep — עם דגלי -v ו--i ›
def grep(lines, pattern, invert=False, ignore_case=False): out = [] for ln in lines: hit = (pattern.lower() in ln.lower()) if ignore_case else (pattern in ln) if hit != invert: # -v הופך את התנאי out.append(ln) return out
T3 · בינוני350 נק'~20 דק'algorithmic
awk — סכימת עמודה
ממש awk_sum(lines, col, sep=None) שסוכם את השדה ה-col (מ-1) בכל שורה (כמו awk '{s+=$col}'). sep הוא המפריד (ברירת מחדל: רווחים). דלג על שורות עם פחות מ-col שדות או ששדה היעד אינו מספר. החזר את הסכום.
דוגמאות
awk_sum(['a 10','b 20','c 30'], 2) → 60.0
awk_sum(['x,1','y,2'], 2, ',') → 3.0
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס awk — סכימת עמודה ›
def awk_sum(lines, col, sep=None): total = 0 for ln in lines: f = ln.split(sep) if sep else ln.split() if len(f) < col: continue try: total += float(f[col-1]) except ValueError: continue # דלג על שדה לא-מספרי return total
שאלות תרגול ותשובות (19)

שאלה 1.1 · מה עושה השרשרת: ps aux | grep apache | wc -l?

ps aux | grep apache | wc -l
  • א. מוחקת את כל תהליכי apache הרצים במערכת, אף שהשרשרת רק סופרת את השורות ואינה מוחקת דבר כלל כאן
  • ב. מציגה את כל תהליכי apache יחד עם מספר השורות שלהם, אף ש-wc מחזירה רק את מספר השורות ולא אותם כאן
  • ג. מדפיסה את מספר תהליכי apache הרצים כרגע במערכת, על-ידי ספירת שורות הפלט של הפקודה grep כאן
  • ד. מחפשת את המילה apache בתוך קובץ בשם wc, אף ש-wc היא פקודה הסופרת שורות ואינה קובץ שמחפשים בו כאן
תשובה: ג

✓ תשובה: ג) — ps aux = כל תהליכים. | grep apache = סנן רק שורות עם "apache". | wc -l = ספור שורות (= מספר תהליכים). השרשרת = 3 פעולות, תוצאה אחת.

שאלה 1.2 · מה ההבדל בין | לבין >?

# כתוב רשימת קבצים לקובץ
ls /etc > ~/etc_list.txt

# הוסף תאריך לסוף לוג קיים (לא דורס!)
date >> ~/security_log.txt

# חיפוש קבצים — השתק "Permission denied"
find / -name "*password*" 2> /dev/null

# שמור stdout לקובץ, שגיאות לקובץ אחר
./script.sh > output.txt 2> errors.txt

# /dev/null — "החור השחור" של Linux
# כל מה שנכתב אליו נעלם לצמיתות
echo "unwanted" > /dev/null  # נעלם
cat /dev/null                 # מחזיר כלום
  • א. הסימן | מעביר את stdout של פקודה אחת אל stdin של הפקודה הבאה, ואילו > שומר את הפלט לתוך קובץ
  • ב. אין ביניהם כל הבדל, ושני הסימנים מפנים את הפלט אל אותו היעד בדיוק בכל מקרה שהוא במערכת כאן כן
  • ג. הסימן | כותב את הפלט לקובץ ואילו > מעביר אותו אל פקודה אחרת, שהוא בדיוק ההפך מן ההבחנה הנכונה כאן
  • ד. הסימן | משמש עבור פקודות ואילו > משמש עבור תהליכים, אף שאין זו כלל ההבחנה הנכונה בין שני הסימנים כאן
תשובה: א

✓ תשובה: א) — cmd1 | cmd2 = stdout של cmd1 → stdin של cmd2 (תהליך חי). cmd1 > file = stdout של cmd1 → נשמר לקובץ (נכתב לדיסק).

שאלה 2.1 · איזה אופרטור מוסיף פלט לסוף קובץ קיים מבלי לדרוס את התוכן הישן?

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

✓ תשובה: ד) >> — Append: מוסיף לסוף הקובץ. > = Override: מוחק הכל וכותב מחדש. | = Pipe: לא קובץ. < = קריאה מקובץ.

שאלה 2.2 · אתם מריצים סקריפט סריקה שמייצר המון שגיאות. רוצים שהשגיאות יעלמו אבל הפלט התקין ייוצג על המסך. איזו פקודה?

  • א. script.sh > /dev/null: מפנה את הפלט התקין (1) אל האַיִן, ומשאיר דווקא את השגיאות מוצגות על המסך כאן
  • ב. script.sh 1> /dev/null: מפנה במפורש את הפלט התקין (1) אל האַיִן, בדיוק כמו הפקודה הקודמת ולא כרצוי
  • ג. script.sh | /dev/null: מנסה להעביר את הפלט אל dev/null כאל פקודה, אף שהוא קובץ ולא פקודה שניתן לצנרת
  • ד. script.sh 2> /dev/null: מפנה את זרם השגיאות (2) אל האַיִן, ומשאיר את הפלט התקין מוצג על המסך כאן
תשובה: ד

✓ תשובה: ד) 2> /dev/null — ערוץ 2 = stderr = השגיאות. הניתוב שלו ל-/dev/null משמיד רק שגיאות. ערוץ 1 (stdout) ממשיך למסך. א) ו-ב) = ההפך: משתיק stdout.

שאלה 2.3 — Dry Run · מה מכיל הקובץ out.txt לאחר: echo "A" > out.txt; echo "B" >> out.txt; echo "C" > out.txt?

echo "A" > out.txt; echo "B" >> out.txt; echo "C" > out.txt
  • א. C: הסימן > האחרון דורס את כל התוכן הקודם, ולכן נשאר בקובץ רק התו C מן הפקודה האחרונה שרצה כאן
  • ב. ABC: הנחה שגויה ששלוש הפקודות מוסיפות זו אחר זו, אף שהסימן > דורס את התוכן ואינו מוסיף אליו כאן כן
  • ג. AC: הנחה שגויה שהתו A נשמר והתו C מתווסף, אף שהפקודה האחרונה עם > דורסת גם את התו A שהיה קודם כאן
  • ד. BC: הנחה שגויה שהתווים B ו-C נשמרים יחד, אף שהפקודה האחרונה עם > דורסת את כל התוכן הקודם שהיה כאן
תשובה: א

✓ תשובה: א) C בלבד — echo "A" > = כותב A. echo "B" >> = מוסיף B (out.txt = A,B). echo "C" > = דורס הכל, כותב C בלבד. out.txt = "C".

שאלה 3.1 · איזה דגל של grep מחפש ללא תלות באותיות גדולות/קטנות?

  • א. grep -i: מחפש את הדפוס ללא כל תלות באותיות גדולות או קטנות, כך שהטקסט ABC ו-abc נחשבים זהים כאן
  • ב. grep -r: מחפש את הדפוס באופן רקורסיבי בכל הקבצים שבתיקייה, אך אינו מתעלם כלל מגודל האותיות בחיפוש
  • ג. grep -v: מציג דווקא את השורות שאינן מכילות את הדפוס, ואינו קשור כלל לגודל האותיות של הטקסט הנחפש כאן
  • ד. grep -n: מוסיף את מספר השורה לכל התאמה שנמצאה בקובץ, אך אינו מתעלם כלל מגודל האותיות במהלך החיפוש
תשובה: א

✓ תשובה: א) grep -i — -i = case-Insensitive. חיפוש "Password" יתאים גם "password", "PASSWORD", "PaSsWoRd". שימושי ב-CTF כשלא יודעים אם שם הקובץ בגדולות.

שאלה 3.2 · מה עושה: grep -v "nologin" /etc/passwd?

grep -v "nologin" /etc/passwd
  • א. מציג רק את השורות שכן מכילות את המילה nologin, שהוא בדיוק ההפך הגמור מפעולת הדגל v של הפקודה כאן
  • ב. מציג רק את השורות שאינן מכילות את המילה nologin, כלומר את המשתמשים האמיתיים שיש להם מעטפת כאן
  • ג. מוחק מן הקובץ את כל המשתמשים שיש להם nologin, אף ש-grep רק מסנן ומציג שורות ואינו מוחק דבר כלל כאן
  • ד. סופר כמה משתמשים במערכת מוגדרים עם nologin, אף שהדגל v מסנן ומציג שורות ואינו סופר את מספרן כלל כאן
תשובה: ב

✓ תשובה: ב) — -v = Invert: מציג שורות שלא מתאימות לתבנית. nologin = שורות של service accounts. -v מציג רק משתמשים אמיתיים (עם /bin/bash וכדומה).

שאלה 3.3 — CTF · אתם מחפשים flags בכל המערכת. איזו פקודה היעילה ביותר?

# חיפוש לפי שם
find / -name "flag.txt" 2>/dev/null
find /home -name "*.sh" 2>/dev/null
find . -name "*password*"

# חיפוש לפי סוג
find /tmp -type f            # קבצים בלבד
find /etc -type d            # ספריות בלבד

# חיפוש לפי הרשאות — חיוני לPrivEsc!
find / -perm -4000 -type f 2>/dev/null   # SUID binaries
find / -perm -2000 -type f 2>/dev/null   # SGID binaries
find / -writable -type f 2>/dev/null     # קבצים שכולם יכולים לכתוב

# חיפוש לפי גודל
find /home -size +10M          # גדולים מ-10MB
find /tmp -size -1k            # קטנים מ-1KB

# חיפוש לפי זמן
find /etc -mtime -7            # שונו ב-7 ימים האחרונים

# ביצוע פעולה על כל תוצאה
find . -name "*.tmp" -exec rm {} \;
find /home -name "*.log" -exec cat {} \;
  • א. grep -r "flag{" / 2>/dev/null: מחפש את הדפוס בתוך תוכן כל הקבצים במערכת ומתעלם מהודעות השגיאה כאן
  • ב. find / -name flag 2>/dev/null: מחפש קבצים ששמם הוא flag בלבד, ולא את הדפוס בתוך תוכן הקבצים שבמערכת
  • ג. cat / | grep flag: תחביר שגוי, שכן לא ניתן כלל להריץ את הפקודה cat על שורש מערכת הקבצים כולה בבת אחת
  • ד. ls -la / | grep flag: מחפש את המילה flag רק בשמות הקבצים שבשורש בלבד, ולא בתוך תוכן הקבצים עצמם כאן
תשובה: א

✓ תשובה: א) — grep -r "flag{" חיפוש רקורסיבי בתוכן כל הקבצים. 2>/dev/null מסתיר שגיאות Permission Denied. ב) מוצא רק קובץ בשם "flag", לא flag בתוך קובץ.

שאלה 4.1 · אתם רוצים לגלות כמה תהליכי apache רצים. הפקודה הנכונה לסיים את השרשרת ps aux | grep apache | ___?

  • א. wc -w: סופר את מספר המילים שבפלט ולא את מספר השורות, ולכן אינו נותן את מספר התהליכים המבוקש כאן כן
  • ב. count -lines: פקודה שאינה קיימת כלל במערכת, ולכן אינה יכולה לספור את שורות הפלט של הפקודה grep כאן
  • ג. grep -c apache: סופר בעצמו את מספר ההתאמות, אך שילובו כאן יספור שורות בתוך שורות ה-grep הקודם ושגוי
  • ד. wc -l: סופר את מספר השורות שבפלט, וכל שורה מייצגת תהליך apache אחד שרץ במערכת ברגע זה בדיוק כאן
תשובה: ד

✓ תשובה: ד) wc -l — wc -l סופר שורות. כל תהליך = שורה אחת בפלט. wc -w סופר מילים = לא נכון. grep -c גם יעבוד אבל פחות שגרתי בשרשרת.

שאלה 4.2 · ב-CTF רוצים למצוא את כל SUID binaries במערכת. איזו פקודה?

  • א. ls -la / | grep s: מחפש את האות s בשמות הקבצים שבשורש בלבד, ולא את ביט ה-SUID שבתוך הרשאות הקבצים
  • ב. find / -perm -4000 -type f 2>/dev/null: מחפש את הקבצים שביט ה-SUID (הערך 4000) דלוק בהרשאותיהם
  • ג. grep -r "SUID" /etc/ 2>/dev/null: מחפש את המחרוזת SUID בתוך תוכן קבצים, ולא קבצים שביט ה-SUID דלוק בהם
  • ד. find / -name "*.suid" 2>/dev/null: מחפש קבצים בעלי סיומת suid, אף שאין כלל סיומת שכזו לקבצים עם SUID כאן
תשובה: ב

✓ תשובה: ב) — -perm -4000 = קבצים עם bit 4000 מוגדר (SUID). -type f = קבצים בלבד. 2>/dev/null = השתק Permission Denied errors. זה השרשרת הקלאסית ל-PrivEsc ב-CTF.

שאלה 4.3 · מה עושה: find /etc -mtime -7?

find /etc -mtime -7
  • א. קבצים שנוצרו לפני 7 ימים בדיוק, אף שהדגל mtime מציין טווח של שינוי ולא נקודת זמן מדויקת אחת בלבד כאן
  • ב. קבצים שגודלם עולה על 7KB, אף שהדגל mtime קשור כולו לזמן השינוי של הקובץ ולא לגודלו במערכת הקבצים כאן
  • ג. שבעת הקבצים האחרונים שנוצרו בתיקייה, אף שהדגל mtime מסנן לפי זמן ואינו מגביל כלל את כמות הקבצים כאן
  • ד. קבצים שהשתנו במהלך 7 הימים האחרונים, שכן הדגל mtime עם הערך 7- מציין שינוי שהתרחש בטווח הזה כאן
תשובה: ד

✓ תשובה: ד) — -mtime -7 = modified time פחות מ-7 ימים = שונו בשבוע האחרון. שימושי ב-CTF לגלות קבצי config שהותקנו לאחרונה. +7 = יותר מ-7 ימים.

שאלה 5.1 · מצאתם 100 קבצי זבל בשם *.tmp. ניסיתם find . -name "*.tmp" | rm אבל נכשל. תיקון נכון?

  • א. find . -name "*.tmp" > rm: מפנה את הפלט אל קובץ בשם rm ואינו מריץ כלל את פקודת המחיקה על הקבצים כאן
  • ב. find . -name "*.tmp" | xargs rm: הפקודה xargs הופכת את הפלט לרשימת ארגומנטים עבור הפקודה rm כאן
  • ג. rm < find . -name "*.tmp": תחביר שגוי, שכן לא ניתן כלל להזרים כך את פלט הפקודה find אל הפקודה rm כאן
  • ד. find . -name "*.tmp" -delete | rm: אף שהדגל delete- כן מוחק את הקבצים, ה-| rm שאחריו הוא מיותר ושגוי כאן
תשובה: ב

✓ תשובה: ב) — xargs לוקח את שורות הפלט מ-find והופך אותן לארגומנטים לrm: בפועל מריץ rm file1.tmp file2.tmp .... חלופה טובה: find . -name "*.tmp" -delete.

שאלה 5.2 · מה עושה: find . -name "*.py" | xargs grep "password"?

find . -name "*.py" | xargs grep "password"
  • א. מוצא רק את קובצי ה-Python ששמם הוא password, ואינו מחפש כלל את המילה בתוך תוכן הקבצים עצמם כלל כאן
  • ב. מחפש את המילה password בתוך תוכן כל קובצי ה-Python שנמצאים בתיקייה הנוכחית ובתת-התיקיות שבתוכה כאן
  • ג. מוחק את כל קובצי ה-Python שמכילים את המילה password, אף ש-grep רק מחפש ומציג ואינו מוחק דבר כלל כאן
  • ד. נותן שגיאה בטענה שלא ניתן לשלב את find עם xargs, אף ששילוב זה נפוץ ותקין לחלוטין בשימוש יומיומי כאן כן
תשובה: ב

✓ תשובה: ב) — find מוצא כל *.py. xargs מעביר אותם לgrep. grep מחפש "password" בתוכם. מקביל ל-grep -r "password" *.py אבל גמיש יותר.

שאלה 6.1 · מה עושה: cut -d: -f1 /etc/passwd | sort?

cut -d: -f1 /etc/passwd | sort
  • א. מציג את כל קובץ passwd כשהוא ממוין לפי שורות, אף שהפקודה cut חותכת ומציגה רק את השדה הראשון בלבד כאן
  • ב. מדפיס רשימה ממוינת של שמות המשתמשים בלבד, שכן השדה הראשון בקובץ passwd הוא שם המשתמש שנחתך כאן
  • ג. חותך את קובץ passwd לשני חלקים נפרדים, אף שהפקודה cut מחלצת שדה מכל שורה ואינה מפצלת את הקובץ עצמו
  • ד. מציג את שדות ה-UID וה-GID כשהם ממוינים, אף שהדגל f1 מחלץ את שם המשתמש בלבד ולא את המזהים המספריים כאן
תשובה: ב

✓ תשובה: ב) — cut -d: -f1 = חתוך לפי מפריד ":" ולקח שדה 1 = שמות משתמשים. | sort = מיין אלפביתית. תוצאה: רשימת כל המשתמשים ממוינת.

שאלה 6.2 — Dry Run מורכב · מה מציגה הפקודה: sort file.txt | uniq -c | sort -rn | head -3 כאשר file.txt מכיל: alice, bob, alice, carol, bob, alice?

sort file.txt | uniq -c | sort -rn | head -3
  • א. alice bob carol (ממוין): הנחה שגויה, שכן הדגל c ב-uniq מוסיף גם את מספר המופעים לכל שורה שמוצגת כאן
  • ב. 3 alice, 2 bob, 1 carol: הצירוף סופר מופעים, ממיין יורד לפי הספירה, ומציג את שלושת הנפוצים ביותר כאן
  • ג. 3 2 1: הנחה שגויה שמוצגות רק הספירות עצמן, אף שכל שורה כוללת גם את השם שנמצא לצד המספר של המופעים כאן
  • ד. carol bob alice (הפוך): הנחה שגויה שהמיון הוא לפי שם בסדר הפוך, ולא לפי מספר המופעים של כל שם ברשימה כאן
תשובה: ב

✓ תשובה: ב) — sort = ממיין. uniq -c = ספור: alice×3, bob×2, carol×1. sort -rn = מיין מרובה לקטן: 3 alice, 2 bob, 1 carol. head -3 = 3 ראשונים = כולם. זו הפקודה הקלאסית לניתוח תדירות ב-CTF.

שאלה 6.3 — אתגר CTF · מה עושה: grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -5?

grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -5
  • א. מציגה את חמש הפקודות האחרונות שנכשלו במערכת, אף שהשרשרת מנתחת דווקא את ניסיונות ההתחברות הכושלים
  • ב. מחפשת חמישה משתמשים שנכשלו בהתחברות, אף שהשדה 11 מחלץ את כתובת ה-IP של המנסה ולא את שם המשתמש כאן
  • ג. מציגה את חמש כתובות ה-IP שניסו brute force הכי הרבה, ממוינות לפי מספר הניסיונות הכושלים של כל אחת
  • ד. נותנת שגיאה בטענה שהקובץ auth.log אינו קיים, אף שזהו קובץ יומן סטנדרטי הקיים ברוב מערכות הלינוקס כאן
תשובה: ג

✓ תשובה: ג) — grep מוצא שורות "Failed password". awk שדה 11 = כתובת IP התוקף. sort + uniq -c = ספור כמה פעמים כל IP. sort -rn = מי ניסה הכי הרבה ראשון. head -5 = 5 התוקפים הכי אגרסיביים. זו אנליזת brute force קלאסית!

שאלה 7.1 [קל] · מה עושה cat file | sort | uniq -c | sort -rn | head -5?

cat file | sort | uniq -c | sort -rn | head -5
  • א. מוצא את חמש השורות הנפוצות ביותר בקובץ יחד עם ספירת המופעים שלהן — זהו דפוס קלאסי של ניתוח תדירות, שימושי מאוד בקריאת לוגים
  • ב. ממיין את הקובץ לפי אלפבית: הנחה שגויה, אף שהמיון הוא רק שלב ביניים לפני uniq -c, ומטרת השרשרת היא ספירת השורות הנפוצות ביותר
  • ג. מוחק שורות כפולות בלבד: הנחה שגויה, אף ש-unic -c סופר מופעים במקום למחוק בלבד, וה-sort -rn ו-head מדרגים את החמש הנפוצות ביותר כן
  • ד. מציג את חמש השורות הראשונות: הנחה שגויה, אף ש-head -5 פועל אחרי מיון יורד לפי ספירה, ולכן מוחזרות הנפוצות ביותר ולא הראשונות
תשובה: א

✓ תשובה נכונה: א — sort → uniq -c (ספירה) → sort -rn (יורד לפי מספר) → head -5. תוצאה: Top 5 שורות שכיחות. חובה למיין לפני uniq.

שאלה 7.2 [בינוני] · מה ההבדל בין > ל->>?

>
  • א. שניהם מוסיפים לסוף: הנחה שגויה, אף שהסימן הבודד דורס ומאפס את הקובץ בעוד הכפול מוסיף לסופו, ולכן רק אחד מהם באמת מבצע הוספה כאן כן
  • ב. הבודד קורא והכפול כותב: הנחה שגויה, אף ששניהם מפנים פלט לכתיבה, וההבדל הוא בין דריסת הקובץ (בודד) להוספה לסופו (כפול) בלבד כן
  • ג. הכפול מוחק את הקובץ: הנחה שגויה, אף שדווקא הסימן הבודד מאפס את הקובץ, בעוד הכפול משמר את התוכן הקיים ומוסיף אליו בסוף כפי שהוגדר כאן
  • ד. הסימן הבודד מחליף את תוכן הקובץ ומאפס אותו (truncate), ואילו הסימן הכפול מוסיף את הפלט לסוף הקובץ הקיים מבלי למחוק את מה שכבר בו
תשובה: ד

✓ תשובה נכונה: ד — > = דריסה (מאפס ואז כותב). >> = הוספה לסוף. טעות נפוצה ומסוכנת: > על קובץ קיים מוחק אותו. ב-Logs תמיד >>.

שאלה 7.3 [קשה] · סקריפט מריץ TARGET=$(cat /dev/stdin). מה הבעיה אם הקלט מגיע ממשתמש?

TARGET=$(cat /dev/stdin)
  • א. Command Injection — משתמש יכול להזין למשל google.com ואז נקודה-פסיק ו-rm כדי ש-Bash יריץ גם את הפקודה השנייה, ולכן זו חולשה חמורה
  • ב. הסקריפט יאט מאוד: הנחה שגויה, אף שהבעיה אינה בביצועים אלא בכך שקלט לא-מסונן עלול להכיל פקודות זדוניות ש-Bash יריץ בהמשך בפועל בכל מקרה
  • ג. הקלט לא ייקרא כלל: הנחה שגויה, אף ש-cat /dev/stdin דווקא קורא את הקלט, והסכנה היא שקלט זדוני מוזרק ומורץ כפקודה על ידי המעטפת בפועל
  • ד. הקובץ יימחק אוטומטית: הנחה שגויה, אף שאין כאן מחיקת קובץ מובנית, והחשש האמיתי הוא הזרקת פקודות שרירותיות דרך קלט לא-מסונן כאן
תשובה: א

✓ תשובה נכונה: א — קלט לא-מסונן שנכנס להקשר של פקודה = Command Injection. 'site.com; rm -rf ~' → Bash מריץ את שתי הפקודות. פתרון: תמיד לצטט ולוודא קלט.