דילוג לתוכן
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

יסודות Nmap במעבדה שלך

Nmap ממפה את הפורטים הפתוחים במחשב שלך. סריקות connect ו-SYN, זיהוי שירותים וקובצי פלט, ואז התאמה של כל פורט לתהליך שמאחוריו.

מתחילים10 דקות קריאהמאת NotHoly

התשובה הקצרה

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

את הפלט של Nmap צריך לקרוא כאינוונטר ראשוני. הוא עדיין לא ממצא. פורט פתוח מספר ש-socket מאזין. האם ה-socket הזה הוא בעיה, זה תלוי בתהליך שמחזיק בו, במי שיכול להגיע אליו ובשאלה אם הוא בכלל אמור להתקיים. המאמר מסתיים בשלב שרוב האנשים מדלגים עליו: התאמה של כל פורט פתוח לתהליך שמאחוריו.

למה זה משנה

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

הכלל המשפטי

צריך לקרוא את זה לפני שמריצים סריקה כלשהי. בספר של Nmap יש פרק על סוגיות משפטיות, והעצה המרכזית בו פשוטה: לקבל רשות לפני שסורקים רשת שאינה בשליטתך. הפרק מציין שספקי אינטרנט מסוימים אוסרים סריקה בלי הרשאה במדיניות השימוש המקובל שלהם ויכולים לנתק משתמשים שמפרים אותה. בעבודה מקצועית, לפי הספר, הדרך הטובה ביותר להימנע מצרות היא לקבל הרשאה בכתב מהאנשים שמייצגים את רשת היעד, ומקומה הוא ב-Statement of Work. עוד הוא מציין שכמעט אף אחד לא יטריד אותך על סריקה של המחשב שלך או של רשתות שבניהולך.

הכלל במאמר הזה:

  • לסרוק רק מערכות בבעלותך, או מערכות שיש לך עליהן הרשאה בכתב שנוקבת בשמן.
  • המחשב הנייד שלך, VM שבנית וקונטיינר שהפעלת נחשבים. מחשב של עמית, רשת של בית ספר, Wi-Fi של מלון או נתב של שכן לא נחשבים, גם כשהכתובת נראית פרטית.
  • כתובת IP ציבורית אינה יעד לתרגול. הבעלים וספק הרשת עשויים לפרש סריקה כמתקפה.

כל פקודה במעבדה הזו מכוונת אל 127.0.0.1, כתובת ה-loopback. חבילות שנשלחות אליה אף פעם לא יוצאות מהמחשב שלך. לכן בטוח לתרגל עליה, ולכן קל להגדיר את הסקופ: ה-host היחיד המעורב הוא שלך.

איך פורט מקבל מצב

פורט הוא מספר שמערכת ההפעלה משתמשת בו כדי למסור תעבורה נכנסת לתהליך. אם תוכנה הודיעה למערכת ההפעלה שהיא תקבל חיבורים על פורט TCP 3000, ה-socket הזה מאזין. סריקה שואלת, עבור כל פורט, מה קורה כשמגיעה בדיקה.

Nmap מדווח על אחד מכמה מצבים. שלושת הנפוצים ביותר:

  • open: משהו קיבל את החיבור.
  • closed: ה-host ענה שאף אחד לא מאזין על הפורט הזה.
  • filtered: Nmap לא קיבל תשובה שאפשר להשתמש בה, בדרך כלל כי firewall זרק את הבדיקה.

המצבים האלה מתארים את הבדיקה ולא את הסיכון. גם פורט סגור יכול לפגוע בך אם שירות שהעבודה שלך תלויה בו נפל. פורט filtered יכול להיות firewall שעושה את עבודתו. צריך להפריד בין המצב למשמעות שלו.

סריקת connect וסריקת SYN

ל-Nmap יש כמה סוגי סריקה. למתחילים שניים מהם רלוונטיים.

סריקת TCP connect (-sT)

סריקת connect מבקשת ממערכת ההפעלה לפתוח חיבור TCP מלא לכל פורט. מערכת ההפעלה מבצעת את ה-three-way handshake הרגיל. אם החיבור מצליח, הפורט פתוח ו-Nmap סוגר אותו. המדריך של Nmap מתאר את סריקת connect כברירת המחדל כשסריקת SYN לא זמינה, כי היא לא דורשת הרשאות לחבילות גולמיות. Nmap משתמש בקריאת ה-connect של המערכת במקום לבנות חבילות בעצמו.

המחיר הוא נראות. חיבור מלא מופיע בלוגים של היעד, וזה בסדר במעבדה שלך ומצריך מחשבה בכל רשת שאינה שלך.

סריקת TCP SYN (-sS)

סריקת SYN שולחת חבילת SYN, אותו צעד ראשון שחיבור אמיתי עושה, וקוראת את התשובה. SYN/ACK אומר שהפורט מאזין. RST אומר שלא. Nmap לא משלים את ה-handshake, ולכן הסריקה הזו נקראת לעיתים קרובות half-open. לפי המדריך, סריקת SYN היא ברירת המחדל כשיש ל-Nmap הרשאות לשלוח חבילות גולמיות, ובדרך כלל זה אומר root או הרשאות אדמין.

ב-Windows צריך לבדוק בהערות ההתקנה של Nmap את התמיכה בחבילות גולמיות לפני שסומכים על -sS. המעבדה משתמשת בדגל -sT כי הוא עובד בלי הרשאות מוגבהות ועדיין נותן את מצבי הפורטים הדרושים.

למתחילים, ההבדל השימושי הוא מה כל סריקה משאירה אחריה. סריקת connect משלימה את ה-handshake ומופיעה בלוגים בשני הצדדים. סריקת SYN עוצרת לפני שה-handshake מסתיים.

זיהוי שירותים עם -sV

מצב פורט אומר שמשהו מאזין על 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 שלי, מוצג הפלט שראיתי. במקומות שלא יכולתי להריץ אותן, אציין זאת ואכתוב מה לחפש.

שלב 1: להפעיל את Juice Shop על loopback

OWASP Juice Shop היא אפליקציית ווב פגיעה בכוונה שנבנתה לתרגול. מפעילים אותה כשהפורט שלה קשור ל-loopback בלבד:

bash
docker run -d --name juice-local -p 127.0.0.1:3000:3000 bkimminich/juice-shop

החלק 127.0.0.1 חשוב. בלעדיו Docker מפרסם את הפורט על כל הממשקים, וכל מכשיר ברשת שלך יוכל להגיע לאפליקציה שנועדה לתרגול בלבד.

אם השם כבר תפוס, Docker עוצר עם שגיאת קונפליקט. אין למחוק את הקונטיינר הזה לפני שברור מי יצר אותו. קודם בודקים אותו:

bash
docker inspect juice-local --format 'image={{.Config.Image}} ports={{json .NetworkSettings.Ports}} status={{.State.Status}}'

מה שראיתי על המחשב שלי:

text
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 בקאש מקומי, ולכן שום דבר לא ירד. כדאי לתת לאפליקציה כמה שניות לעלות לפני שפותחים אותה בדפדפן.

שלב 2: להפעיל שרת ווב של Python על loopback

bash
python3 -m http.server 8000 --bind 127.0.0.1 &

ב-Windows ייתכן שהפקודה python3 לא קיימת. אצלי היא לא הייתה ב-path, אז הרצתי את Python 3.12 לפי נתיב ההתקנה המלא שלו עם אותם ארגומנטים. התו & מריץ את השרת ברקע של ה-shell הנוכחי. בודקים אותו מטרמינל אחר:

bash
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/index.txt

הקובץ שביקשתי היה קיים בתיקייה שממנה הפעלתי את השרת, והבדיקה החזירה 200. הלוג של השרת רשם את הבקשה:

text
127.0.0.1 - - [08/Nov/2026 06:20:25] "GET /index.txt HTTP/1.1" 200 -

שלב 3: לראות מה לפי מערכת ההפעלה מאזין

לפני הסריקה שואלים את מערכת ההפעלה. הרשימה הזו היא נקודת הייחוס שלך, והיא לא תלויה ב-Nmap.

ב-Linux:

bash
ss -tlnp

ב-Windows, ב-PowerShell:

powershell
Get-NetTCPConnection -State Listen

על המחשב שלי הרצתי גרסה שמציגה גם את התהליך שמחזיק בפורט:

powershell
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:

text
::                 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 עצמו ולא למשהו שהפעלת. זה נורמלי, ובדיוק בגלל זה אינוונטר צריך לנקוב בבעלים של כל פורט.

שלב 4: להריץ את סריקת ה-connect

bash
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:

python
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}")

הפלט על המחשב שלי:

text
open on 127.0.0.1 in 1-10000: [135, 445, 515, 1026, 3000, 3311, 5000, 5040, 7680, 8000, 8001, 8026]

כל פורט ברשימה מופיע גם בטבלת המאזינים משלב 3. שני המקורות מסכימים, וזו הבדיקה שרוצים לעשות לפני שסומכים על אחד מהם.

שלב 5: להריץ זיהוי שירותים ולשמור את הפלט

bash
nmap -sV -p 3000,8000 127.0.0.1 -oN localhost-scan.txt

לא הורץ כאן, מאותה סיבה כמו בשלב 4. מה לחפש: עמודת VERSION ליד 3000 ו-8000, וקובץ בשם localhost-scan.txt בתיקייה הנוכחית. טקסט הגרסה ש-Nmap מדפיס לפורט 3000 הוא טענה שצריך לבדוק. כדאי לפתוח את האפליקציה בדפדפן או לקרוא את התיעוד של התוכנה לפני שרושמים את הגרסה בכל מקום שהוא.

שלב 6: להתאים כל פורט פתוח לתהליך שלו

השלב הזה הופך סריקה לאינוונטר. לכל פורט פתוח צריך את התהליך שמחזיק בו. ב-Linux, הפקודה ss -tlnp מדפיסה בעמודה האחרונה את שם התהליך ואת ה-PID. ב-Windows לוקחים את ה-PID מהשדה OwningProcess ומחפשים אותו:

powershell
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 נתנה את המיפוי שציפיתי לו:

text
3000/tcp -> 127.0.0.1:3000

PIDs משתנים. שרת ה-Python החזיק ב-PID 49668 ברשימה קודמת על המחשב הזה. אחרי שהפעלתי אותו מחדש לריצה הזו, אותה שורת פקודה החזיקה בפורט 8000 תחת PID 49736. צריך לקרוא את ה-PID ממש לפני שפועלים לפיו, ולאמת גם את שורת הפקודה ולא רק את השם.

ניקוי

bash
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 שרץ מול אותו קונטיינר.

מקורות

מקורות

  1. Nmap Reference Guide (Chapter 15)
  2. Nmap Network Scanning: Legal Issues
  3. Nmap Network Scanning: Version Detection
  4. Nmap Network Scanning: Port Scanning Techniques
  5. Nmap Network Scanning: Port Specification and Scan Order
  6. Nmap Network Scanning: Output

עוד בנושא כלי אבטחה

כלי אבטחה

ה-toolkit ל-bug bounty ו-NotHoly CLI

toolkit קטן וישר ל-bug bounty למתחילים, בתוספת NotHoly CLI בטרמינל עם scope רשום כך שהפקודות נשארות בתוך התוכנית.

מתחילים3 דקות קריאה

כלי אבטחה

למה ה-CLI של NotHoly ולא עוזר טרמינל כללי

הסוכן רץ על המכונה שלכם באישורכם, המודל מקבל את עבודת האבטחה, ו-engagement בודק כל פקודה מול ה-scope שלכם לפני שהיא רצה.

ביניים2 דקות קריאה

כלי אבטחה

למה תוסף ה-VS Code של NotHoly לסקירת קוד

סקרו את הקובץ או את ה-git diff בעורך שלכם, עם ההקשר שהקוד נותן. המודל מקבל את שאלת האבטחה והופך ממצא לבדיקה או לחוקה.

ביניים2 דקות קריאה