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.
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.
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.
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.
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 è:
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.
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:
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.
Nmap ha diversi tipi di scansione. Per un principiante ne contano due.
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.
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.
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.
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ù.
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.
OWASP Juice Shop è un'app web volutamente vulnerabile, fatta per esercitarsi. Avviala con la porta legata solo al loopback:
docker run -d --name juice-local -p 127.0.0.1:3000:3000 bkimminich/juice-shopLa 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:
docker inspect juice-local --format 'image={{.Config.Image}} ports={{json .NetworkSettings.Ports}} status={{.State.Status}}'Quello che ho osservato sulla mia macchina:
image=bkimminich/juice-shop ports={"3000/tcp":[{"HostIp":"127.0.0.1","HostPort":"3000"}]} status=runningL'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.
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:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/index.txtIl 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:
127.0.0.1 - - [08/Nov/2026 06:20:25] "GET /index.txt HTTP/1.1" 200 -Prima di scansionare, chiedi al sistema operativo. Questo elenco è il tuo riferimento e non dipende da Nmap.
Su Linux:
ss -tlnpSu Windows, in PowerShell:
Get-NetTCPConnection -State ListenSulla mia macchina ho eseguito una versione che mostra anche il processo proprietario:
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:
:: 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.backendConta 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.
nmap -sT -p 1-10000 127.0.0.1Questo 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:
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:
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.
nmap -sV -p 3000,8000 127.0.0.1 -oN localhost-scan.txtNon 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.
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:
Get-Process -Id 23620 | Select-Object Id, ProcessNameL'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:
3000/tcp -> 127.0.0.1:3000I 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.
docker rm -f juice-local
kill %1Lancia 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.
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.
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.
Strumenti di sicurezza
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.
Strumenti di sicurezza
L'agente gira sulla tua macchina con la tua approvazione, il modello accetta il lavoro di sicurezza, e un engagement controlla ogni comando.
Strumenti di sicurezza
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.