Fondamenti di Test di Sicurezza Etico con Python: Una Guida Pratica per Principianti
Capitolo 5 di 11 · aggiornato 08 lug 2026
Ricognizione e mappatura di rete: comprensione della superficie di attacco
Ricognizione e Mappatura di Rete: Comprensione della Superficie di Attacco
Lasciatemi raccontarvi come conduco effettivamente questa fase nel Lab Wintermute. Dopo quattro pagine di preparazione e fondamenti, finalmente potete toccare il bersaglio — ma "toccare" è la parola chiave, e il suo peso legale è qualcosa che inculco in ogni studente. La ricognizione (recon per brevità: la fase di raccolta informazioni prima di qualsiasi attacco mirato) si divide in due modalità che si trovano su lati opposti di una netta linea etica. La ricognizione passiva significa osservare informazioni che il bersaglio pubblica già — record DNS, dati WHOIS, offerte di lavoro che menzionano tecnologie, persino foto di rack di server sui social media. Non inviate mai un pacchetto alla loro infrastruttura. La ricognizione attiva significa che i vostri pacchetti raggiungono effettivamente le interfacce del bersaglio: ping, scansioni porte, connessioni dirette. Nel nostro lab, l'accordo di scope autorizza esplicitamente la ricognizione attiva contro 192.0.2.20 e 192.0.2.30. Nel mondo reale, la ricognizione attiva senza autorizzazione scritta è legalmente indistinguibile dalla preparazione di un attacco nella maggior parte delle giurisdizioni. Tengo un documento di scope firmato in ogni cartella del lab; dovreste farlo anche voi.
⚠️ Solo uso autorizzato e difensivo. Ogni tecnica descritta di seguito è contestualizzata per valutazione di sicurezza autorizzata. Non indirizzate mai queste tecniche contro sistemi che non possedete o per i quali non avete esplicita autorizzazione scritta di testare.
Il Three-Way Handshake TCP: Perché gli Scanner Funzionano
Prima di scrivere Python che sonda le porte, dovete vedere cosa attraversa effettivamente il cavo. Il TCP, definito nell'RFC 793 di settembre 1981, è stato costruito per comunicazione affidabile processo-a-processo attraverso reti interconnesse. Il meccanismo che rende possibile questa affidabilità è anche ciò che rende possibile la scansione porte: il three-way handshake.
Ecco la sequenza. La vostra macchina invia un pacchetto SYN (synchronize, con un numero di sequenza iniziale casuale). Se la porta bersaglio è aperta e in ascolto, risponde SYN-ACK (synchronize-acknowledge, con il proprio numero di sequenza più un acknowledgment del vostro). La vostra macchina invia quindi ACK, e la connessione è stabilita. Se la porta è chiusa, l'RFC 793 stabilisce che il bersaglio deve rispondere con RST (reset). Se un firewall scarta il pacchetto, ottenete silenzio — nessun RST, nessun SYN-ACK, solo timeout.
In termini semplici: il handshake è come bussare a una porta. Porta aperta? Qualcuno risponde. Porta chiusa a chiave? Qualcuno urla "vattene." Porta nascosta dietro un muro insonorizzato? Nessuno risponde, e rimanete lì a sembrare sciocchi finché non vi arrendete.
Questo comportamento è il motivo per cui funziona il nostro semplice scanner TCP connect. Il socket.socket(socket.AF_INET, socket.SOCK_STREAM) di Python crea un socket TCP, e sock.connect((target_ip, target_port)) innesca implicitamente l'intero three-way handshake. Non costruiamo qui pacchetti SYN raw — quella è una tecnica più avanzata non trattata nelle nostre fonti — ma sfruttiamo ciò che lo stack TCP del sistema operativo fa automaticamente.
Perché questo è importante: Una scansione SYN "stealth" (invio solo di SYN, senza completare mai l'handshake) richiede privilegi di raw socket e specifici flag di Nmap. Il nostro scanner Python utilizza la scansione full connect, che è più lenta e più rumorosa ma non richiede permessi speciali e insegna la meccanica sottostante in modo trasparente. Nel Lab Wintermute, accettiamo il rumore perché stiamo imparando, non evadendo il rilevamento.
Costruzione dello Scanner: Python Contro 192.0.2.20
Dalla Pagina 2, avete già Python installato e comprendete variabili, cicli e operazioni socket di base. Ora assembliamo i pezzi nel nostro primo strumento di ricognizione attiva. Scansioniamo Metasploitable2 su 192.0.2.20, porte 1-1024 — l'intervallo delle "well-known ports" dove i servizi standard tradizionalmente sono in ascolto. (Le specifiche mappature porta-servizio non sono nelle nostre fonti; apprenderete assegnazioni comuni come 22/SSH, 80/HTTP, 445/SMB attraverso la pratica e riferimenti supplementari.)
La logica dello scanner: iterare le porte, tentare la connessione, registrare il risultato, chiudere il socket. Il timeout è critico — senza di esso, una porta filtrata blocca il vostro script. Notate che il comportamento di settimeout() varia tra implementazioni Python; le nostre fonti notano che in alcuni contesti embedded come CircuitPython 8.2.2, il timeout di connessione TCP può essere fisso indipendentemente dalla vostra impostazione. Il CPython standard su Kali Linux si comporta come previsto, ma testate sempre.
#!/usr/bin/env python3
# tcp_connect_scanner.py — Lab Wintermute authorized scan only
import socket TARGET = "192.0.2.20"
START_PORT = 1
END_PORT = 1024
TIMEOUT_SECONDS = 1 # aggressive for lab; adjust for reliability def scan_port(target_ip, port): """Attempt TCP connection, return state string.""" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(TIMEOUT_SECONDS) try: sock.connect((target_ip, port)) # If we reach here, three-way handshake succeeded return "open" except socket.timeout: return "filtered" # no response, likely firewall drop except ConnectionRefusedError: return "closed" # target sent RST per RFC 793 finally: sock.close() def main(): print(f"[*] Starting TCP connect scan: {TARGET} ports {START_PORT}-{END_PORT}") results = {"open": [], "closed": [], "filtered": []} for port in range(START_PORT, END_PORT + 1): state = scan_port(TARGET, port) results[state].append(port) if state == "open": print(f"[+] Port {port}/tcp open") print(f"\n[*] Scan complete") print(f" Open: {len(results['open'])} | Closed: {len(results['closed'])} | Filtered: {len(results['filtered'])}") if __name__ == "__main__": main()
Eseguitelo dalla vostra workstation Kali (192.0.2.10). Aspettate minuti, non secondi — le scansioni full connect sono lente. L'output mostrerà le porte aperte; i conteggi delle porte chiuse e filtrate si aggregano alla fine.
Perché questo è importante: Una porta marcata come filtered non è un risultato pulito — è una domanda senza risposta. Nelle valutazioni in produzione, le porte filtrate richiedono approfondimento: diversi tipi di scansione, manipolazione della porta sorgente, o semplicemente documentare l'incertezza. Non riportate mai "filtered" come "sicuro"; riportatelo come "irrisolto."
Banner di Servizio e Rilevamento Versione
Una porta aperta vi dice dove parlare; il banner spesso vi dice a cosa state parlando. Molti servizi — demoni SSH, web server, server FTP — inviano un saluto testuale al momento della connessione. Questo è il primo passo del rilevamento versione, ed è critico per il lavoro difensivo: sapere quale software gira dove vi permette di mappare contro vulnerabilità note.
Il banner grabbing in Python estende il nostro scanner:
def grab_banner(sock, port): """Attempt to read service banner after successful connect.""" try: # Some services send banner immediately; others require protocol-specific probe banner = sock.recv(1024).decode('utf-8', errors='replace').strip() return banner except socket.timeout: return "[no banner received]"
In pratica, il banner grabbing è delicato. I protocolli differiscono: SSH invia una stringa di versione senza sollecito; HTTP richiede che inviate prima una richiesta; altri sono binari. Per il Lab Wintermute, l'ispezione manuale con nc (netcat) spesso insegna più dell'automazione:
# Connect to SSH banner — banner typically sent immediately
nc -v 192.0.2.20 22 # HTTP requires speaking the protocol
echo -e "HEAD / HTTP/1.0\r\n\r\n" | nc 192.0.2.20 80
Il banner alimenta la ricerca sulle vulnerabilità: nome prodotto e versione portano a ricerche CVE, bollettini del vendor e verifica dello stato delle patch. Questo è oro difensivo — state costruendo un inventario accurato degli asset, non solo una mappa di attacco.
Integrazione Nmap: Richiamare lo Standard da Python
Il nostro scanner Python insegna la meccanica, ma Nmap è lo standard industriale per buone ragioni. Il suo motore di rilevamento versione, la libreria di script e i formati di output sono battagliati. La licenza di Nmap è una licenza personalizzata basata su (ma non compatibile con) GPLv2; per i nostri scopi, usiamo la distribuzione binaria su Kali Linux.
Nmap supporta l'output XML tramite -oX, che possiamo analizzare programmaticamente. Il comando nmap -oX - target invia XML a stdout (il trattino come nome file), perfetto per il piping in Python. La DTD che definisce la struttura XML risiede su https://svn.nmap.org/nmap/docs/nmap.dtd.
# Representative scan: OS detection, version detection, scripts, traceroute
# -A enables aggressive detection; -T4 sets timing template (faster than default)
nmap -A -T4 -oX wintermute_192.0.2.20.xml 192.0.2.20 # For stdout XML piping to Python
nmap -oX - 192.0.2.20
L'analisi in Python usa la libreria standard — nessuna dipendenza esterna necessaria:
#!/usr/bin/env python3
# parse_nmap_xml.py
import xml.etree.ElementTree as ET
import sys def parse_nmap_xml(xml_source): """Extract host, port, state, service info from Nmap XML.""" tree = ET.parse(xml_source) root = tree.getroot() for host in root.findall('host'): address = host.find('address').get('addr') ports = host.find('ports') if ports is None: continue for port in ports.findall('port'): portid = port.get('portid') state = port.find('state').get('state') service = port.find('service') svc_name = service.get('name', 'unknown') if service is not None else 'unknown' product = service.get('product', '') if service is not None else '' version = service.get('version', '') if service is not None else '' print(f"{address}:{portid} {state} {svc_name} {product} {version}".strip()) if __name__ == "__main__": parse_nmap_xml(sys.argv[1])
Perché questo è importante: L'output strutturato trasforma la ricognizione da artigianato in processo ripetibile. Il vostro report del Lab Wintermute includerà dati Nmap analizzati; il vostro futuro datore di lavoro se lo aspetterà.
L'XML di Nmap include attributi product, version ed extrainfo dal rilevamento versione, con livelli di confidenza: livello 3 per ipotesi da lookup tabellare (associazioni porte comuni), livello 10 per rilevamento versione confermato. Trattate i risultati a minore confidenza come indizi, non verdetti.
Prospettiva Difensiva: Vedere la Scansione dall'Altro Lato
Ogni tecnica offensiva si mappa a un controllo difensivo. Ecco come il lato bersaglio sperimenta la nostra attività, e come i difensori rispondono.
| Azione Offensiva | Osservabile dal Lato Bersaglio | Controllo Difensivo |
|---|---|---|
| TCP connect scan (porte 1-1024) | Rapidi tentativi di connessione sequenziali da singola sorgente | Network IDS/IPS: Snort (open-source network intrusion detection system) identifica scansioni porte covert per pattern — soglia di SYN senza completare handshake, o full connect a molte porte. Snort esamina ogni pacchetto per anomalie sospette. |
| Banner grabbing | Connessioni applicative valide, possibilmente loggate | Service hardening: Disabilitare i banner o restituire stringhe generiche; configurare il logging applicativo di tutte le connessioni |
| Version detection (Nmap -sV) | Probe a porte aperte con pattern insoliti | Honeypots: Sistemi esca che emulano servizi, loggano interazioni, fanno perdere tempo all'attaccante; non nelle nostre fonti ma ampiamente deployati |
| Scan da singolo IP | Ovvia attribuzione della sorgente | Network segmentation: Isolare asset critici; la scansione da una subnet non dovrebbe raggiungerne un'altra senza passare per chokepoint controllati |
| Ricognizione ripetuta | Pattern persistente nel tempo | Correlation: Regole SIEM (Security Information and Event Management, piattaforma di aggregazione e analisi log) segnalano multipli indicatori di ricognizione dalla stessa sorgente |
Note specifiche sul logging: le full connect del nostro scanner Python appaiono come connessioni TCP standard nei log di sistema — /var/log/auth.log per SSH, log di accesso del web server per HTTP. I probe di servizio di Nmap possono innescare il logging a livello applicativo di richieste malformate o inaspettate. Su Metasploitable2, esaminate /var/log/syslog dopo la vostra scansione; vedrete il rumore che avete generato.
Il port knocking — apertura dinamica delle porte firewall basata su una sequenza segreta di tentativi di connessione — non è menzionato nelle nostre fonti ma rappresenta un ulteriore strato: le porte appaiono chiuse finché non arriva la sequenza di "bussata" corretta, rendendo le scansioni semplici fuorvianti.
Checklist Lab Wintermute: Fase di Ricognizione
Prima di procedere alla mappatura applicazione web della Pagina 6, verificate:
- [ ] Scanner Python eseguito contro 192.0.2.20 con gestione timeout
- [ ] Output XML Nmap generato e analizzato con successo
- [ ] Banner di servizio verificati manualmente per almeno 3 porte aperte
- [ ] Log Metasploitable2 rivisti per identificare artefatti della scansione
- [ ] Documentato: porte aperte, servizi, versioni e livelli di confidenza
- [ ] Controlli difensivi identificati per ogni esposizione osservata
Create snapshot delle vostre VM prima di continuare. La ricognizione è la fondazione; tutto ciò che segue nelle Pagine 6-10 si basa su questa mappa. Una scansione approssimativa significa tentativi di exploit alla cieca — inefficienti, rumorosi, e cattiva tradecraft anche in lab autorizzati.