Motore di Scripting Nmap: Automazione Personalizzata e Sviluppo NSE
Architettura ed Execution Model di NSE
Il Nmap Scripting Engine (NSE) incorpora un runtime Lua 5.3 che esegue script in parallelo con il motore di pacchetto nativo di Nmap. Non è un'aggiunta successiva applicata allo scanner: gli script vengono eseguiti durante la fase di scansione stessa, non in un passaggio di post-elaborazione. Il motore si lega a Nsock per I/O di rete asincrono, permettendo a centinaia di script di eseguire simultaneamente senza bloccare il thread principale della scansione.
Gli script rientrano in categorie (vuln, exploit, auth, brute, discovery, safe, intrusive, malware, version, default) e si attivano tramite quattro tipi di regola:
| Tipo di regola | Quando si attiva | Utilizzo tipico |
|---|---|---|
prerule |
Prima del discovery dell'host | Configurazione a livello di script, lettura di file |
hostrule |
Dopo il discovery dell'host, per ogni target attivo | Controlli a livello di host (es. analisi traceroute) |
portrule |
Dopo la scansione delle porte, corrispondenza con porte/servizi specifici | Enumerazione dei servizi, controlli di vulnerabilità |
postrule |
Dopo il completamento di tutte le scansioni | Report aggregati, correlazione cross-host |
Le regole restituiscono booleani Lua; il motore di Nmap decide se mettere in coda la funzione action dello script. Una portrule che corrisponde a shortport.http si attiverà contro qualsiasi porta identificata come HTTP da Nmap—sia la 80, la 8080, o una porta non standard con un banner riconoscibile.
Libreria di Script Built-in e Selezione
NSE include centinaia di script. Considera il set predefinito (-sC, equivalente a --script=default) come una linea di base sicura; esegue solo script nelle categorie default, safe, o version che si completano rapidamente e comportano un rischio minimo di crash.
Pattern di esecuzione selettiva:
# Script predefiniti sicuri contro un singolo host
nmap -sC 192.0.2.10
# Categoria specifica — controlli vuln contro un web server
nmap --script vuln -p 80,443 198.51.100.5
# Categorie multiple, separate da virgola
nmap --script "discovery,auth" 192.168.50.0/24
# Escludi script distruttivi anche con globbing
nmap --script "not intrusive" 10.0.3.0/24
Cosa fa:
--script vulncarica tutti gli script nella categoriavuln, verificando CVE noti, debolezze di configurazione e divulgazioni di informazioni. Quando usarlo: Durante le fasi autorizzate di valutazione delle vulnerabilità dopo il discovery iniziale degli host. Rischi: Alcuni scriptvulnsonointrusive—possono attivare allarmi IDS o, in casi rari, causare crash di servizi fragili. Output atteso: Risultati strutturati di vulnerabilità con riferimenti CVE e indicatori di gravità.
Distinzione Lab vs. Produzione:
| Ambiente | Approccio | Motivazione |
|---|---|---|
| Lab | nmap --script "vuln,exploit" --script-args=unsafe=1 |
Copertura completa, accettare crash in reti isolate |
| Produzione | nmap --script "safe,vuln" --max-parallelism 10 --max-retries 2 |
Escludere exploit, limitare il parallelismo, ridurre tempeste di retry |
La categoria exploit merita particolare cautela. Questi script tentano attivamente l'esecuzione di codice o il bypass dell'autenticazione. Sono preziosi per validare lo stato delle patch in un lab, ma un'esecuzione exploit in produzione contro un server shadow IT mancato è un report di incidente in attesa di accadere.
Argomenti degli Script e Interazione Dinamica
Gli script espongono parametri configurabili tramite --script-args e --script-args-file. Questo trasforma gli script statici in strumenti flessibili.
# Passa un User-Agent personalizzato a http-title
nmap --script http-title --script-args http.useragent='Mozilla/5.0 (Windows NT 10.0; Win64; x64)' -p 80,443 192.0.2.15
# Argomenti multipli, delimitati da punto e virgola
nmap --script ssh-brute --script-args "userdb=./users.txt,passdb=./passwords.txt,ssh-brute.timeout=8s" -p 22 198.51.100.20
# Argomenti da file per ripetibilità
nmap --script smb-enum-shares --script-args-file ./smb-args.txt 10.0.4.50
Cosa fa:
http.useragentsovrascrive la stringa User-Agent predefinita di NSE, riducendo il rilevamento basato su firme e corrispondendo alle aspettative di logging del target. Quando usarlo: Quando si testano regole WAF, si riproduce un ambiente client specifico, o si evitano stringhe "Nmap Scripting Engine" nei log. Rischi: Gli User-Agent personalizzati sono banali da impostare; non costituiscono un'evasione significativa contro un monitoraggio maturo. Output atteso: Estrazione http-title identica, ma i log del server riflettono la stringa fornita.
Scopri gli argomenti disponibili per qualsiasi script:
nmap --script-help http-title
nmap --script-help ssh-brute
L'output di --script-help elenca argomenti obbligatori vs. opzionali, valori predefiniti e appartenenza alle categorie. Leggilo prima di eseguire script non familiari—gli script brute in particolare possono bloccare account se non si impostano ritardi adeguati.
Scrivere Script NSE Personalizzati
Gli script personalizzati colmano il divario dove nessuno script esistente corrisponde al tuo protocollo, alla tua logica di rilevamento o al tuo formato di report. Lo script minimamente funzionante richiede quattro campi: description, categories, rule, e action.
Esempio minimale completo — uno script hostrule che verifica se il record PTR di un target risolve a un pattern sospetto:
description = [[
Checks if a reverse-DNS PTR record contains indicators of
dynamic/residential IP space, useful for flagging VPN exit nodes
or residential proxies during incident response.
]]
categories = {"discovery", "safe"}
author = "Analyst Name"
license = "Same as Nmap"
-- Pull in the NSE DNS library
local dns = require "dns"
local stdnse = require "stdnse"
-- Hostrule: run once per host after host discovery
hostrule = function(host)
-- Only run if we have an IP; IPv6 PTR logic differs
return host.ip ~= nil
end
-- Main action
action = function(host)
local status, name = dns.query(host.ip, {dtype="PTR"})
if not status then
return "No PTR record found"
end
local suspicious = {
"dhcp", "dynamic", "pool", "res", "ppp", "dsl", "cable"
}
local lower_name = string.lower(name)
for _, pattern in ipairs(suspicious) do
if string.find(lower_name, pattern, 1, true) then
return string.format("SUSPICIOUS PTR: %s (matched '%s')", name, pattern)
end
end
return string.format("PTR: %s", name)
end
Salva come ptr-suspicious.nse nella directory degli script di Nmap (<nmapdatadir>/scripts/ su Linux, o usa --datadir per puntare altrove). Esegui con:
nmap --script ptr-suspicious 192.0.2.100
Cosa fa: La
hostrulesi attiva dopo il discovery dell'host;actionesegue una lookup DNS inverso e pattern-matching contro parole chiave note di IP dinamici. Quando usarlo: Durante il threat-hunting per segnalare proxy residenziali o fonti di scansione erratamente attribuite. Rischi: I record PTR sono controllabili dall'attaccante; non considerare mai un risultato "pulito" come prova di infrastruttura legittima. Output atteso: Una stringa di pattern corrispondente, un record PTR semplice, o "No PTR record found."
Librerie NSE chiave per lo sviluppo:
| Libreria | Scopo | Funzione di esempio |
|---|---|---|
nmap |
API core: info host/port, creazione socket | nmap.new_socket() |
stdnse |
Utility: formattazione, debug, timing | stdnse.debug(1, "message") |
shortport |
Predicati comuni per portrule | shortport.http |
table |
Helper per manipolazione tabelle | table.contains(t, val) |
string |
Pattern matching, parsing | string.match(response, "Server: (.+)\r\n") |
nsock |
I/O asincrono (tramite metodi socket di nmap) |
socket:connect(host, port) |
Gli script vengono eseguiti in un ambiente Lua sandboxato. Non è possibile importare librerie C arbitrarie o eseguire comandi shell direttamente—questo è voluto. Per logica complessa che richiede dati esterni, usa stdnse.get_script_args() per leggere percorsi di file passati tramite --script-args, poi analizza quei file in puro Lua.
Debug degli Script e Profiling delle Prestazioni
Gli script NSE falliscono silenziosamente per impostazione predefinita—un timeout, una porta chiusa, o una mancata corrispondenza di protocollo non producono output. Forza la visibilità:
# Livello di debug 2: flusso di esecuzione dello script
nmap --script http-title -d2 --script-trace 192.0.2.10
# Traccia completa a livello di pacchetto dell'attività di rete dello script
nmap --script http-title -d3 --packet-trace 192.0.2.10
Cosa fa:
-d2abilita l'output di debug a livello di script;--script-tracestampa ogni lettura/scrittura Nsock. Quando usarlo: Quando uno script non restituisce nulla e si sospetta un edge case di protocollo. Rischi: Le tracce di pacchetto sono voluminose; reindirizza su file. Output atteso: Stack trace Lua, transizioni di stato del socket, e coppie raw di richiesta/risposta HTTP.
Per il profiling sistematico, usa --script-timeout e --host-timeout per impedire che script bloccati rallentino intere fasi di scansione. La funzione stdnse.debug() accetta livelli 1-9; usa il livello 1 per diagnostica in produzione e il livello 3+ solo durante lo sviluppo attivo.
Mantenere Repository di Script Privati
Le organizzazioni con logica di rilevamento personalizzata o firme sensibili non dovrebbero affidarsi alla directory globale degli script di Nmap. Stabilisci una struttura di repository privata:
/opt/nse-private/
├── scripts/ # file *.nse
├── lib/ # Librerie Lua private
├── data/ # File di fingerprint, wordlist
└── update.sh # Deployment version-controlled
Invoca con datadir esplicito:
nmap --datadir /opt/nse-private --script my-custom-script 192.0.2.0/24
O crea symlink di singoli script nella directory di sistema ed esegui --script-updatedb per ricostruire il database degli script. Il file script.db nel datadir è una tabella Lua che Nmap analizza all'avvio; corruzioni qui causano criptici errori "Script not found".
Meccanismi di aggiornamento: il comando built-in nmap --script-update-db reindicizza solo i file locali. Per una vera consegna di aggiornamenti, versiona il tuo repository e fai deploy tramite configuration management (Ansible, Puppet, ecc.). Non tentare di sovrapporre script privati sulla directory upstream di Nmap—gli aggiornamenti dei pacchetti upstream entreranno in conflitto e sovrascriveranno.
NSE vs. Strumenti Esterni: Quando Restare, Quando Uscire
NSE eccelle nell'integrazione stretta con i risultati della scansione: consapevolezza dello stato delle porte, dati del rilevamento versione, e timing delle hostrule sono gratuiti. Vacilla quando hai bisogno di sessioni persistenti, macchine a stati di protocollo complesse, o post-elaborazione pesante.
| Scenario | NSE appropriato? | Alternativa migliore |
|---|---|---|
| Acquisizione header HTTP durante la scansione host | Sì | — |
| Crawl completo di web application e test di form | No | Burp Suite, OWASP ZAP |
| Fingerprinting chiavi SSH | Sì | — |
| Brute-force con logica personalizzata di retry/backoff | Marginale | Hydra, Medusa |
| Exploit con consegna payload multi-stadio | No | Metasploit framework |
| Controllo vulnerabilità con 100+ varianti di richiesta | No | Scanner standalone (OpenVAS, Nessus) |
I moduli Metasploit e gli script NSE si sovrappongono concettualmente ma divergono architetturalmente. NSE viene eseguito stateless per host/porta con secondi di tempo di esecuzione; Metasploit mantiene sessioni, effettua pivoting ed esegue Ruby arbitrario. Uno script come msrpc-enum elencherà interfacce; un modulo Metasploit si legherà a una ed estrarrà hash SAM. Usa NSE per la vastità della ricognizione, Metasploit per la profondità mirata.
Sicurezza degli Script e Denial of Service
La categorizzazione safe vs. intrusive è un segnale, non una garanzia. Gli script safe non causano crash di servizi nei test di Nmap, ma il tuo antico HMI ICS che parla un sottoinsieme HTTP rotto non era in quella matrice di test. Gli script intrusive possono inviare payload che esauriscono tabelle di connessione, riempiono log su disco, o attivano regole fail2ban.
Errori comuni:
| Errore | Perché ti colpisce |
|---|---|
Eseguire script brute senza --script-args brute.delay |
Blocco account, allarmi SIEM, telefonate arrabbiate |
Usare la categoria exploit in produzione senza scoping |
Crash effettivi di servizi su sistemi non patchati |
Globbing --script "*" su grandi reti |
Esaurimento risorse da centinaia di script × migliaia di host |
Ignorare http.max-cache-size e limiti simili |
Bloated di memoria, OOM kills su nodi di scansione a bassa risorsa |
Assumere che safe significhi "impatto di rete zero" |
Qualsiasi sonda aumenta il carico; l'effetto cumulativo conta a scala |
⚠️ Solo uso autorizzato e difensivo. Gli script exploit e intrusive sono progettati per validazione in lab e valutazioni di hardening autorizzate. Non indirizzarli mai a sistemi senza autorizzazione esplicita, documentata, che copra sia lo scope tecnico che l'impatto aziendale di una potenziale interruzione di servizio.
Prima del deployment in produzione, replicare le versioni dei servizi del target in un lab ed eseguire lo script previsto con -d3 --packet-trace. Osservare limiti di rateo di connessione, risposte di protocollo non standard, e crescita di memoria. Uno script che si completa in 0.3 secondi contro nginx può bloccarsi indefinitamente contro un server web embedded personalizzato che non chiude mai il socket.