Vai al contenuto
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

Le basi di Nmap nel tuo laboratorio

Nmap mappa le porte aperte sulla tua macchina. Impara connect scan e SYN scan, rilevamento dei servizi e file di output, poi abbina ogni porta al suo processo.

Base13 min di letturaDi NotHoly

La risposta breve

Nmap è uno scanner di rete. Lo punti su un host e ti dice quali porte rispondono, in che stato è ciascuna e, se glielo chiedi, quale servizio e quale versione ci sono dietro una porta aperta. Sulla tua macchina diventa uno strumento rapido di inventario. Ottieni un elenco di ciò che è in ascolto e puoi confrontarlo con quello che credi di avere in esecuzione.

Considera l'output di Nmap un inventario di partenza, che di per sé non è un finding. Una porta aperta ti dice che c'è un socket in ascolto. Se quel socket sia un problema dipende da quale processo lo possiede, da chi può raggiungerlo e dal fatto che debba esistere o no. Questo articolo si chiude con il passaggio che la maggior parte delle persone salta: abbinare ogni porta aperta al processo che ci sta dietro.

Perché conta

La maggior parte delle sorprese su una macchina viene da qualcosa che nessuno si ricorda di aver avviato. Un server di sviluppo lasciato acceso dalla settimana scorsa. Un container che ha pubblicato una porta su tutte le interfacce. Un servizio in background che si è installato durante un aggiornamento. Non puoi valutare quello che non hai elencato, e un inventario delle porte è il punto di partenza più economico. Lo stesso metodo funziona su un portatile, su una macchina virtuale che hai creato tu o sulla rete di un cliente che hai il permesso di testare.

La regola legale

Leggi questa parte prima di lanciare qualsiasi scansione. Il libro di Nmap ha un capitolo sulle questioni legali, e il suo consiglio principale è semplice: chiedi il permesso prima di scansionare una rete che non controlli. Fa notare che alcuni provider internet vietano la scansione senza permesso nelle loro politiche di utilizzo accettabile e possono disconnettere chi le viola. Per il lavoro professionale, dice che il modo migliore per evitare guai è ottenere un permesso scritto da chi rappresenta la rete bersaglio, e indica lo Statement of Work come il posto giusto per metterla. Nota anche che di rado qualcuno ti disturba per aver scansionato la tua macchina o le reti che amministri.

Per questo articolo, la regola è:

  • Scansiona solo sistemi tuoi, o sistemi per cui hai un permesso scritto che li nomina.
  • Valgono il tuo portatile, una VM che hai creato e un container che hai avviato. Non valgono la macchina di un collega, la rete di una scuola, il Wi-Fi di un hotel o il router di un vicino, anche quando l'indirizzo sembra privato.
  • Un indirizzo IP pubblico non è un bersaglio per fare pratica. Il proprietario e il provider di rete possono prendere una scansione per un attacco.

Ogni comando di questo laboratorio punta a 127.0.0.1, l'indirizzo di loopback. I pacchetti inviati lì non lasciano mai la tua macchina. Per questo puoi esercitarti senza rischi e il perimetro è facile da definire: l'unico host coinvolto è il tuo.

Come una porta ottiene uno stato

Una porta è un numero che il sistema operativo usa per consegnare il traffico in arrivo a un processo. Se un programma ha detto al sistema operativo che accetterà connessioni sulla porta TCP 3000, quel socket è in ascolto. Una scansione chiede, per ogni porta, che cosa succede quando arriva una sonda.

Nmap riporta uno tra diversi stati. I tre che vedrai più spesso sono:

  • open: qualcosa ha accettato la connessione.
  • closed: l'host ha risposto che su quella porta non c'è niente in ascolto.
  • filtered: Nmap non ha ricevuto una risposta utilizzabile, di solito perché un firewall ha scartato la sonda.

Questi stati descrivono la sonda e non il rischio. Una porta chiusa può crearti problemi comunque, se un servizio da cui dipendi è giù. Una porta filtrata può essere un firewall che fa il suo lavoro. Tieni separati lo stato e il suo significato.

Connect scan e SYN scan

Nmap ha diversi tipi di scansione. Per un principiante ne contano due.

TCP connect scan (-sT)

Un connect scan chiede al sistema operativo di aprire una connessione TCP completa verso ogni porta. Il sistema esegue il normale three-way handshake. Se la connessione riesce, la porta è aperta e Nmap la chiude. La guida di Nmap descrive il connect scan come il tipo predefinito quando il SYN scan non è disponibile, perché non richiede privilegi per i pacchetti raw. Nmap usa la chiamata connect del sistema invece di costruire i pacchetti da solo.

Il prezzo è la visibilità. Una connessione completa compare nei log del bersaglio, cosa che nel tuo laboratorio va bene e su una rete non tua va messa in conto.

TCP SYN scan (-sS)

Un SYN scan manda un pacchetto SYN, lo stesso primo passo di una connessione vera, e poi legge la risposta. Un SYN/ACK significa che la porta è in ascolto. Un RST significa che non c'è niente. Nmap non completa l'handshake, ed è per questo che la scansione viene spesso detta half-open. La guida dice che il SYN scan è il tipo predefinito quando Nmap ha i privilegi per inviare pacchetti raw, di solito i diritti di root o di amministratore.

Su Windows, controlla le note di installazione di Nmap sul supporto ai pacchetti raw prima di contare su -sS. Questo laboratorio usa -sT perché funziona senza privilegi elevati e ti dà comunque gli stati delle porte che ti servono.

Per un principiante, la differenza utile è che cosa si lascia dietro ciascuna scansione. Un connect scan completa l'handshake e compare nei log di entrambi i lati. Un SYN scan si ferma prima che l'handshake finisca.

Rilevamento dei servizi con -sV

Lo stato di una porta ti dice che qualcosa ascolta sulla 8000, ma non che cosa sia. L'opzione -sV manda sonde alle porte aperte, confronta le risposte con il database di firme di Nmap e riporta nome del servizio e versione quando li riconosce.

L'intensità va da 0, che manda il minor numero di sonde, a 9, che le prova tutte. I livelli più alti richiedono più tempo e generano più traffico. Per impostazione predefinita, il rilevamento delle versioni salta la porta TCP 9100, una porta da stampante che può reagire male alle sonde. Usa l'intensità più bassa che risponde alla tua domanda e lancia -sV solo su sistemi che controlli.

Le stringhe di versione sono indizi e non prove. Chi gestisce un servizio può cambiarne il banner, quindi un numero di versione è un'affermazione da verificare sul software stesso.

Formati di output

Nmap può scrivere i risultati su file oltre che a schermo. I formati che userai di più sono:

  • -oN file: output normale, leggibile da una persona.
  • -oX file: XML, per gli strumenti che analizzano i risultati.
  • -oG file: output grepable, un host per riga, per filtri rapidi da shell.

Usa -oN per le note che leggerai tu e -oX quando il risultato lo elaborerà un altro strumento. Tieni i file di scansione accanto agli appunti del laboratorio. Una scansione della settimana scorsa registra ciò che era vero la settimana scorsa, e oggi può non esserlo più.

Laboratorio pratico

Ti servono Docker, Python 3, Nmap e una macchina con le porte 3000 e 8000 libere su 127.0.0.1. Se non hai ancora una rete di laboratorio, parti da come creare una rete Docker isolata per i laboratori. Ogni passo qui sotto gira sulla tua macchina. I comandi sono quelli del laboratorio. Dove li ho eseguiti sulla mia macchina Windows 11, mostro l'output che ho visto. Dove non ho potuto eseguirli, lo dico e ti indico che cosa cercare.

Passo 1: avvia Juice Shop su loopback

OWASP Juice Shop è un'app web volutamente vulnerabile, fatta per esercitarsi. Avviala con la porta legata solo al loopback:

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

La parte 127.0.0.1 conta. Senza, Docker pubblica la porta su tutte le interfacce, e qualsiasi dispositivo della tua rete potrebbe raggiungere un'app pensata solo per fare pratica.

Se il nome è già in uso, Docker si ferma con un errore di conflitto. Non cancellare quel container finché non sai chi l'ha creato. Prima ispezionalo:

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

Quello che ho osservato sulla mia macchina:

text
image=bkimminich/juice-shop ports={"3000/tcp":[{"HostIp":"127.0.0.1","HostPort":"3000"}]} status=running

L'ho avviato da zero per questa prova e ho confermato la mappatura con docker port juice-local, che ha stampato 3000/tcp -> 127.0.0.1:3000. Docker aveva l'immagine in cache locale, quindi non è stato scaricato niente. Lascia all'app qualche secondo per partire prima di aprirla in un browser.

Passo 2: avvia un server web Python su loopback

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

Su Windows, python3 può non esistere. Sulla mia macchina non era nel path, quindi ho lanciato Python 3.12 dal suo percorso completo di installazione con gli stessi argomenti. La & esegue il server in background nella shell corrente. Provalo da un altro terminale:

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

Il file che ho richiesto esisteva nella cartella da cui ho avviato il server, e la prova ha restituito 200. Il log del server ha registrato la richiesta:

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

Passo 3: elenca ciò che secondo il sistema operativo è in ascolto

Prima di scansionare, chiedi al sistema operativo. Questo elenco è il tuo riferimento e non dipende da Nmap.

Su Linux:

bash
ss -tlnp

Su Windows, in PowerShell:

powershell
Get-NetTCPConnection -State Listen

Sulla mia macchina ho eseguito una versione che mostra anche il processo proprietario:

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 }

L'output sulla mia macchina, limitato alle porte sotto 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

Conta le righe. Molte di queste porte appartengono a Windows e non a qualcosa che hai avviato tu. È normale, ed è proprio il motivo per cui un inventario deve indicare il proprietario di ogni porta.

Passo 4: lancia il connect scan

bash
nmap -sT -p 1-10000 127.0.0.1

Questo comando non l'ho eseguito. Nmap non è installato sulla macchina che ho usato e non l'ho installato. Che cosa cercare quando lo lanci: una tabella PORT STATE SERVICE. Ogni riga marcata open dovrebbe corrispondere a una riga del passo 3. Per questo laboratorio, 3000/tcp e 8000/tcp dovrebbero comparire entrambe come aperte. Di solito Nmap raggruppa le porte chiuse in una riga di riepilogo, quindi le righe da leggere sono quelle aperte.

Al suo posto ho scritto un breve controllo su loopback con la libreria standard di Python. Apre una connessione TCP verso ogni porta da 1 a 10000 su 127.0.0.1 e riporta quelle che accettano. Fa lo stesso handshake di un connect scan, ma non è 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}")

Output sulla mia macchina:

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

Ogni porta di quell'elenco compare anche nella tabella dei processi in ascolto del passo 3. Le due fonti concordano, ed è la verifica che vuoi fare prima di fidarti di una delle due.

Passo 5: lancia il rilevamento dei servizi e salva l'output

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

Non eseguito qui, per lo stesso motivo del passo 4. Che cosa cercare: una colonna VERSION accanto a 3000 e 8000, e un file chiamato localhost-scan.txt nella cartella corrente. Il testo di versione che Nmap stampa per la porta 3000 è un'affermazione da verificare. Apri l'app in un browser o leggi la documentazione del software prima di annotare la versione da qualche parte.

Passo 6: abbina ogni porta aperta al suo processo

Questo passo trasforma una scansione in un inventario. Per ogni porta aperta ti serve il processo che la possiede. Su Linux, ss -tlnp stampa il nome del processo e il PID nell'ultima colonna. Su Windows, prendi il PID da OwningProcess e cercalo:

powershell
Get-Process -Id 23620 | Select-Object Id, ProcessName

L'ho fatto per le porte dell'elenco. Sulla mia macchina i proprietari sono questi:

Porta In ascolto su PID Proprietario Che cos'è
3000 127.0.0.1 23620 com.docker.backend Il proxy di Docker Desktop per il container juice-local, confermato con docker port juice-local
8000 127.0.0.1 49736 python L'http.server del passo 2
3311 tutte le interfacce (::) 11308 node Un processo Node.js; tasklist /svc non elenca alcun servizio per quel processo, quindi è un programma avviato da qualcuno
515 tutte le interfacce 6084 svchost Il servizio di stampa LPD di Windows; tasklist /svc /fi "PID eq 6084" mostra LPDSVC

Due righe richiedono una decisione, e la scansione da sola non può prenderla. Il processo Node.js sulla 3311 ascolta su tutte le interfacce, quindi se è un server di sviluppo pensato per il lavoro locale, altri dispositivi possono raggiungerlo. Anche il servizio LPD sulla 515 ascolta su tutte le interfacce. Se debbano girare o no lo decidi tu, e la correzione spetta al proprietario del processo, non allo scanner. Non fermare un servizio solo perché compare in un elenco.

La riga di Docker richiede una seconda verifica. Il processo backend inoltra la porta, quindi il PID da solo non dà il nome del container. docker port juice-local ha restituito la mappatura che mi aspettavo:

text
3000/tcp -> 127.0.0.1:3000

I PID cambiano. Il server Python aveva il PID 49668 in un elenco precedente su questa macchina. Dopo che l'ho riavviato per questa prova, la stessa riga di comando possedeva la porta 8000 con il PID 49736. Leggi il PID subito prima di agire e conferma la riga di comando oltre al nome.

Pulizia

bash
docker rm -f juice-local
kill %1

Lancia il primo comando solo su un container che hai creato per questo laboratorio. kill %1 funziona solo nella shell che ha avviato il job; da un'altra shell, trova il PID come al passo 6, controlla la riga di comando e poi fermalo.

Errori comuni

Scansionare un indirizzo che non è tuo. Un intervallo privato come 192.168.x.x può appartenere a un router o a un dispositivo gestito da qualcun altro. Scansiona solo ciò per cui hai un permesso scritto.

Leggere "open" come "vulnerabile". Una porta aperta è un fatto su un processo in ascolto. Diventa un finding solo quando sai che servizio è, perché è raggiungibile e se dovrebbe esserlo.

Dimenticare -p. Senza un intervallo di porte, Nmap scansiona le 1.000 porte più comuni per ogni protocollo. Il laboratorio usa -p 1-10000 di proposito, perché un servizio su una porta insolita è esattamente ciò che un inventario deve intercettare.

Pubblicare senza l'indirizzo. -p 3000:3000 pubblica su tutte le interfacce. Tieni 127.0.0.1: davanti quando l'app serve solo a te.

Fidarsi di una stringa di versione. -sV legge quello che un servizio dice di sé. Controlla la versione sul software prima di farci affidamento.

Fermarsi alla scansione. La scansione ti dà i numeri di porta. Trovare il proprietario di ognuna è la parte che ti resta da fare.

Per andare oltre

Scrivi le porte che ti aspetti prima di scansionare, poi confronta. È il modo più rapido per accorgerti di qualcosa che non sapevi fosse in esecuzione.

Scansiona due volte: una con il server Python acceso e una dopo averlo fermato. Salva i due file con -oN e confrontali. La differenza è ciò che hai cambiato.

Leggi le sezioni della guida di Nmap su -oX e -Pn. Quando conosci i formati di output, puoi dare i risultati in pasto a uno script e seguire i cambiamenti nel tempo, sempre e solo sulle tue macchine.

Il prossimo articolo della serie passa dalle porte al livello web, con le basi di OWASP ZAP contro Juice Shop sullo stesso container.

Fonti

Fonti

  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

Altro su Strumenti di sicurezza

Strumenti di sicurezza

Il toolkit del bug bounty e la NotHoly CLI

Un toolkit di bug bounty per chi inizia, più la NotHoly CLI nel terminale con lo scope registrato così i comandi restano dentro il programma.

Base3 min di lettura

Strumenti di sicurezza

Perché l'estensione VS Code di NotHoly per la review

Review del file o del git diff nel tuo editor, con tutto il contesto. Il modello accetta la domanda di sicurezza e crea da un reperto un test o una regola.

Intermedio3 min di lettura