כלי אבטחה
ה-toolkit ל-bug bounty ו-NotHoly CLI
toolkit קטן וישר ל-bug bounty למתחילים, בתוספת NotHoly CLI בטרמינל עם scope רשום כך שהפקודות נשארות בתוך התוכנית.
Nmap ממפה את הפורטים הפתוחים במחשב שלך. סריקות connect ו-SYN, זיהוי שירותים וקובצי פלט, ואז התאמה של כל פורט לתהליך שמאחוריו.
Nmap הוא סורק רשת. מכוונים אותו אל host והוא מדווח אילו פורטים עונים, באיזה מצב כל פורט, ולפי בקשה גם איזה שירות ואיזו גרסה יושבים מאחורי פורט פתוח. על המחשב שלך זה כלי מהיר לאינוונטר: מקבלים רשימה של מה שמאזין, ואפשר להשוות אותה למה שנדמה לך שרץ.
את הפלט של Nmap צריך לקרוא כאינוונטר ראשוני. הוא עדיין לא ממצא. פורט פתוח מספר ש-socket מאזין. האם ה-socket הזה הוא בעיה, זה תלוי בתהליך שמחזיק בו, במי שיכול להגיע אליו ובשאלה אם הוא בכלל אמור להתקיים. המאמר מסתיים בשלב שרוב האנשים מדלגים עליו: התאמה של כל פורט פתוח לתהליך שמאחוריו.
רוב ההפתעות במחשב באות ממשהו שאף אחד לא זוכר שהפעיל. שרת פיתוח שנשאר רץ מהשבוע שעבר. קונטיינר שפרסם פורט על כל הממשקים. שירות רקע שהתקין את עצמו במהלך עדכון. אי אפשר להעריך את מה שלא נרשם, ורשימת פורטים היא נקודת ההתחלה הזולה ביותר. אותה שיטה עובדת על מחשב נייד, על מכונה וירטואלית שבנית או על רשת של לקוח שיש לך הרשאה לבדוק.
צריך לקרוא את זה לפני שמריצים סריקה כלשהי. בספר של Nmap יש פרק על סוגיות משפטיות, והעצה המרכזית בו פשוטה: לקבל רשות לפני שסורקים רשת שאינה בשליטתך. הפרק מציין שספקי אינטרנט מסוימים אוסרים סריקה בלי הרשאה במדיניות השימוש המקובל שלהם ויכולים לנתק משתמשים שמפרים אותה. בעבודה מקצועית, לפי הספר, הדרך הטובה ביותר להימנע מצרות היא לקבל הרשאה בכתב מהאנשים שמייצגים את רשת היעד, ומקומה הוא ב-Statement of Work. עוד הוא מציין שכמעט אף אחד לא יטריד אותך על סריקה של המחשב שלך או של רשתות שבניהולך.
הכלל במאמר הזה:
כל פקודה במעבדה הזו מכוונת אל 127.0.0.1, כתובת ה-loopback. חבילות שנשלחות אליה אף פעם לא יוצאות מהמחשב שלך. לכן בטוח לתרגל עליה, ולכן קל להגדיר את הסקופ: ה-host היחיד המעורב הוא שלך.
פורט הוא מספר שמערכת ההפעלה משתמשת בו כדי למסור תעבורה נכנסת לתהליך. אם תוכנה הודיעה למערכת ההפעלה שהיא תקבל חיבורים על פורט TCP 3000, ה-socket הזה מאזין. סריקה שואלת, עבור כל פורט, מה קורה כשמגיעה בדיקה.
Nmap מדווח על אחד מכמה מצבים. שלושת הנפוצים ביותר:
המצבים האלה מתארים את הבדיקה ולא את הסיכון. גם פורט סגור יכול לפגוע בך אם שירות שהעבודה שלך תלויה בו נפל. פורט filtered יכול להיות firewall שעושה את עבודתו. צריך להפריד בין המצב למשמעות שלו.
ל-Nmap יש כמה סוגי סריקה. למתחילים שניים מהם רלוונטיים.
סריקת connect מבקשת ממערכת ההפעלה לפתוח חיבור TCP מלא לכל פורט. מערכת ההפעלה מבצעת את ה-three-way handshake הרגיל. אם החיבור מצליח, הפורט פתוח ו-Nmap סוגר אותו. המדריך של Nmap מתאר את סריקת connect כברירת המחדל כשסריקת SYN לא זמינה, כי היא לא דורשת הרשאות לחבילות גולמיות. Nmap משתמש בקריאת ה-connect של המערכת במקום לבנות חבילות בעצמו.
המחיר הוא נראות. חיבור מלא מופיע בלוגים של היעד, וזה בסדר במעבדה שלך ומצריך מחשבה בכל רשת שאינה שלך.
סריקת SYN שולחת חבילת SYN, אותו צעד ראשון שחיבור אמיתי עושה, וקוראת את התשובה. SYN/ACK אומר שהפורט מאזין. RST אומר שלא. Nmap לא משלים את ה-handshake, ולכן הסריקה הזו נקראת לעיתים קרובות half-open. לפי המדריך, סריקת SYN היא ברירת המחדל כשיש ל-Nmap הרשאות לשלוח חבילות גולמיות, ובדרך כלל זה אומר root או הרשאות אדמין.
ב-Windows צריך לבדוק בהערות ההתקנה של Nmap את התמיכה בחבילות גולמיות לפני שסומכים על -sS. המעבדה משתמשת בדגל -sT כי הוא עובד בלי הרשאות מוגבהות ועדיין נותן את מצבי הפורטים הדרושים.
למתחילים, ההבדל השימושי הוא מה כל סריקה משאירה אחריה. סריקת connect משלימה את ה-handshake ומופיעה בלוגים בשני הצדדים. סריקת SYN עוצרת לפני שה-handshake מסתיים.
מצב פורט אומר שמשהו מאזין על 8000. הוא לא אומר מה זה. האפשרות -sV שולחת בדיקות לפורטים הפתוחים, משווה את התשובות למסד החתימות של Nmap ומדווחת על שם שירות וגרסה כשהיא מזהה אותם.
העוצמה נעה מ-0, ששולח הכי מעט בדיקות, עד 9, שמנסה את כולן. רמות גבוהות יותר לוקחות יותר זמן ושולחות יותר תעבורה. כברירת מחדל, זיהוי הגרסה מדלג על פורט TCP 9100, פורט מדפסות שעלול להגיב רע לבדיקות. כדאי להשתמש בעוצמה הנמוכה ביותר שעונה על השאלה, ולהריץ את -sV רק מול מערכות בשליטתך.
מחרוזות גרסה הן ראיה ולא הוכחה. מי שמפעיל שירות יכול לשנות את ה-banner שלו, ולכן מספר גרסה הוא טענה שצריך לבדוק מול התוכנה עצמה.
Nmap יודע לכתוב תוצאות לקובץ וגם למסך. הפורמטים הנפוצים:
-oN file: פלט רגיל, קריא לאדם.-oX file: XML, לכלים שמנתחים תוצאות.-oG file: פלט שנוח ל-grep, host אחד בשורה, לסינון מהיר ב-shell.הדגל -oN מתאים להערות לקריאה אישית, והדגל -oX מתאים כשכלי אחר יעבד את התוצאה. קובצי סריקה כדאי לשמור ליד הערות המעבדה. סריקה מהשבוע שעבר מתעדת את מה שהיה נכון בשבוע שעבר, לא היום.
צריך Docker, Python 3, Nmap ומחשב שבו הפורטים 3000 ו-8000 פנויים על הכתובת 127.0.0.1. אם עדיין אין לך רשת מעבדה, כדאי להתחיל ביצירת רשת Docker מבודדת למעבדות. כל השלבים רצים על המחשב שלך. הפקודות הן פקודות המעבדה. במקומות שבהם הרצתי אותן על מחשב Windows 11 שלי, מוצג הפלט שראיתי. במקומות שלא יכולתי להריץ אותן, אציין זאת ואכתוב מה לחפש.
OWASP Juice Shop היא אפליקציית ווב פגיעה בכוונה שנבנתה לתרגול. מפעילים אותה כשהפורט שלה קשור ל-loopback בלבד:
docker run -d --name juice-local -p 127.0.0.1:3000:3000 bkimminich/juice-shopהחלק 127.0.0.1 חשוב. בלעדיו Docker מפרסם את הפורט על כל הממשקים, וכל מכשיר ברשת שלך יוכל להגיע לאפליקציה שנועדה לתרגול בלבד.
אם השם כבר תפוס, Docker עוצר עם שגיאת קונפליקט. אין למחוק את הקונטיינר הזה לפני שברור מי יצר אותו. קודם בודקים אותו:
docker inspect juice-local --format 'image={{.Config.Image}} ports={{json .NetworkSettings.Ports}} status={{.State.Status}}'מה שראיתי על המחשב שלי:
image=bkimminich/juice-shop ports={"3000/tcp":[{"HostIp":"127.0.0.1","HostPort":"3000"}]} status=runningהפעלתי אותו מאפס לריצה הזו ואימתתי את המיפוי עם docker port juice-local, שהדפיס 3000/tcp -> 127.0.0.1:3000. ל-Docker היה ה-image בקאש מקומי, ולכן שום דבר לא ירד. כדאי לתת לאפליקציה כמה שניות לעלות לפני שפותחים אותה בדפדפן.
python3 -m http.server 8000 --bind 127.0.0.1 &ב-Windows ייתכן שהפקודה python3 לא קיימת. אצלי היא לא הייתה ב-path, אז הרצתי את Python 3.12 לפי נתיב ההתקנה המלא שלו עם אותם ארגומנטים. התו & מריץ את השרת ברקע של ה-shell הנוכחי. בודקים אותו מטרמינל אחר:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/index.txtהקובץ שביקשתי היה קיים בתיקייה שממנה הפעלתי את השרת, והבדיקה החזירה 200. הלוג של השרת רשם את הבקשה:
127.0.0.1 - - [08/Nov/2026 06:20:25] "GET /index.txt HTTP/1.1" 200 -לפני הסריקה שואלים את מערכת ההפעלה. הרשימה הזו היא נקודת הייחוס שלך, והיא לא תלויה ב-Nmap.
ב-Linux:
ss -tlnpב-Windows, ב-PowerShell:
Get-NetTCPConnection -State Listenעל המחשב שלי הרצתי גרסה שמציגה גם את התהליך שמחזיק בפורט:
Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -lt 10000 } | Sort-Object LocalPort | ForEach-Object { $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue; '{0,-15} {1,6} {2,8} {3}' -f $_.LocalAddress, $_.LocalPort, $_.OwningProcess, $p.ProcessName }הפלט על המחשב שלי, מוגבל לפורטים מתחת ל-10000:
:: 135 2204 svchost
0.0.0.0 135 2204 svchost
192.168.0.100 139 4 System
172.23.112.1 139 4 System
:: 445 4 System
0.0.0.0 515 6084 svchost
:: 515 6084 svchost
127.0.0.1 1026 23620 com.docker.backend
127.0.0.1 3000 23620 com.docker.backend
:: 3311 11308 node
127.0.0.1 5000 43252 python
0.0.0.0 5040 10556 svchost
:: 7680 4604 svchost
127.0.0.1 8000 49736 python
127.0.0.1 8001 7976 python
127.0.0.1 8026 23620 com.docker.backendכדאי לספור את השורות. הרבה מהפורטים האלה שייכים ל-Windows עצמו ולא למשהו שהפעלת. זה נורמלי, ובדיוק בגלל זה אינוונטר צריך לנקוב בבעלים של כל פורט.
nmap -sT -p 1-10000 127.0.0.1את הפקודה הזו לא הרצתי. Nmap לא מותקן על המחשב שהשתמשתי בו, ולא התקנתי אותו. מה לחפש כשמריצים אותה: טבלת PORT STATE SERVICE. כל שורה שמסומנת open צריכה להתאים לשורה משלב 3. במעבדה הזו 3000/tcp וגם 8000/tcp אמורים להופיע כפתוחים. Nmap בדרך כלל מקפל את הפורטים הסגורים לשורת סיכום, ולכן קוראים את השורות של הפתוחים.
כתחליף כתבתי בדיקת loopback קצרה עם הספרייה הסטנדרטית של Python. היא פותחת חיבור TCP לכל פורט מ-1 עד 10000 על 127.0.0.1 ומדווחת על אלה שמקבלים אותו. היא עושה את אותו handshake שסריקת connect עושה, אבל היא לא Nmap:
import socket
from concurrent.futures import ThreadPoolExecutor
HOST = "127.0.0.1"
def is_open(port: int) -> bool:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.3)
return s.connect_ex((HOST, port)) == 0
if __name__ == "__main__":
with ThreadPoolExecutor(max_workers=200) as ex:
results = list(ex.map(is_open, range(1, 10001)))
open_ports = [p for p, ok in zip(range(1, 10001), results) if ok]
print(f"open on {HOST} in 1-10000: {open_ports}")הפלט על המחשב שלי:
open on 127.0.0.1 in 1-10000: [135, 445, 515, 1026, 3000, 3311, 5000, 5040, 7680, 8000, 8001, 8026]כל פורט ברשימה מופיע גם בטבלת המאזינים משלב 3. שני המקורות מסכימים, וזו הבדיקה שרוצים לעשות לפני שסומכים על אחד מהם.
nmap -sV -p 3000,8000 127.0.0.1 -oN localhost-scan.txtלא הורץ כאן, מאותה סיבה כמו בשלב 4. מה לחפש: עמודת VERSION ליד 3000 ו-8000, וקובץ בשם localhost-scan.txt בתיקייה הנוכחית. טקסט הגרסה ש-Nmap מדפיס לפורט 3000 הוא טענה שצריך לבדוק. כדאי לפתוח את האפליקציה בדפדפן או לקרוא את התיעוד של התוכנה לפני שרושמים את הגרסה בכל מקום שהוא.
השלב הזה הופך סריקה לאינוונטר. לכל פורט פתוח צריך את התהליך שמחזיק בו. ב-Linux, הפקודה ss -tlnp מדפיסה בעמודה האחרונה את שם התהליך ואת ה-PID. ב-Windows לוקחים את ה-PID מהשדה OwningProcess ומחפשים אותו:
Get-Process -Id 23620 | Select-Object Id, ProcessNameעשיתי את זה לפורטים שברשימה. אלה הבעלים שהתגלו על המחשב שלי:
| פורט | מאזין על | PID | בעלים | מה זה |
|---|---|---|---|---|
| 3000 | 127.0.0.1 | 23620 | com.docker.backend | ה-proxy של Docker Desktop עבור הקונטיינר juice-local, אומת עם docker port juice-local |
| 8000 | 127.0.0.1 | 49736 | python | השרת http.server משלב 2 |
| 3311 | כל הממשקים (::) |
11308 | node | תהליך Node.js. הפקודה tasklist /svc לא מציגה עבורו שירות, אז זו תוכנה שמישהו הפעיל |
| 515 | כל הממשקים | 6084 | svchost | שירות ההדפסה LPD של Windows. הפקודה tasklist /svc /fi "PID eq 6084" מציגה LPDSVC |
שתי שורות דורשות החלטה, והסריקה לבדה לא יכולה לקבל אותה. תהליך ה-Node.js על 3311 מאזין על כל הממשקים, כך שאם זה שרת פיתוח שנועד לעבודה מקומית, מכשירים אחרים יכולים להגיע אליו. גם שירות ה-LPD על 515 מאזין על כל הממשקים. אם אחד מהם צריך לרוץ, זו החלטה שלך, והתיקון שייך לבעלים של התהליך, לא לסורק. אין לעצור שירות רק כי הוא מופיע ברשימה.
שורת ה-Docker דורשת בדיקה נוספת. תהליך ה-backend מעביר את הפורט, ולכן ה-PID לבדו לא נוקב בשם הקונטיינר. הפקודה docker port juice-local נתנה את המיפוי שציפיתי לו:
3000/tcp -> 127.0.0.1:3000PIDs משתנים. שרת ה-Python החזיק ב-PID 49668 ברשימה קודמת על המחשב הזה. אחרי שהפעלתי אותו מחדש לריצה הזו, אותה שורת פקודה החזיקה בפורט 8000 תחת PID 49736. צריך לקרוא את ה-PID ממש לפני שפועלים לפיו, ולאמת גם את שורת הפקודה ולא רק את השם.
docker rm -f juice-local
kill %1את הפקודה הראשונה מריצים רק על קונטיינר שיצרת למעבדה הזו. הפקודה kill %1 עובדת רק ב-shell שהפעיל את ה-job. מ-shell אחר צריך למצוא את ה-PID כמו בשלב 6, לבדוק את שורת הפקודה שלו, ורק אז לעצור אותו.
לסרוק כתובת שאינה שלך. טווח פרטי כמו 192.168.x.x יכול להיות של נתב או של מכשיר שמישהו אחר מפעיל. סורקים רק את מה שיש עליו הרשאה בכתב.
לקרוא "open" כאילו כתוב "vulnerable". פורט פתוח הוא עובדה על מאזין. הוא הופך לממצא רק כשיודעים מה השירות, למה אפשר להגיע אליו והאם זה אמור להיות כך.
לשכוח את -p. בלי טווח פורטים, Nmap סורק את 1,000 הפורטים הנפוצים ביותר בכל פרוטוקול. המעבדה משתמשת בדגל -p 1-10000 בכוונה, כי שירות על פורט לא שגרתי הוא בדיוק מה שאינוונטר צריך לתפוס.
קישור בלי הכתובת. -p 3000:3000 מפרסם על כל הממשקים. כשהאפליקציה מיועדת לך בלבד, צריך להשאיר 127.0.0.1: בהתחלה.
לסמוך על מחרוזת גרסה. -sV קורא את מה ששירות אומר על עצמו. צריך לבדוק את הגרסה מול התוכנה לפני שסומכים עליה.
לעצור בסריקה. הסריקה נותנת מספרי פורטים. מציאת הבעלים של כל פורט היא החלק שעדיין נשאר לעשות.
לרשום את הפורטים הצפויים לפני הסריקה, ואז להשוות. זו הדרך המהירה ביותר לגלות שרץ משהו שלא ידעת עליו.
לסרוק פעמיים: פעם אחת כששרת ה-Python רץ ופעם אחרי שעוצרים אותו. לשמור את שני הקבצים עם -oN ולהשוות ביניהם. ההבדל הוא מה ששינית.
לקרוא במדריך של Nmap את הסעיפים על -oX ועל -Pn. כשמכירים את פורמטי הפלט, אפשר להזין תוצאות סריקה לסקריפט ולעקוב אחרי שינויים לאורך זמן, ועדיין רק מול המחשבים שלך.
המאמר הבא בסדרה עובר מפורטים לשכבת הווב, עם יסודות OWASP ZAP מול Juice Shop שרץ מול אותו קונטיינר.
כלי אבטחה
toolkit קטן וישר ל-bug bounty למתחילים, בתוספת NotHoly CLI בטרמינל עם scope רשום כך שהפקודות נשארות בתוך התוכנית.
כלי אבטחה
הסוכן רץ על המכונה שלכם באישורכם, המודל מקבל את עבודת האבטחה, ו-engagement בודק כל פקודה מול ה-scope שלכם לפני שהיא רצה.
כלי אבטחה
סקרו את הקובץ או את ה-git diff בעורך שלכם, עם ההקשר שהקוד נותן. המודל מקבל את שאלת האבטחה והופך ממצא לבדיקה או לחוקה.