
Veloce modulo di scoperta della rete basato su browser
Modulo di scoperta di rete veloce basato su browser
Questo progetto non è più mantenuto.
netmap.js fornisce capacità di scoperta di host e scansione delle porte basate su browser per permetterti di mappare le reti dei visitatori del sito web.
È abbastanza veloce, utilizzando es6-promise-pool per eseguire in modo efficiente il numero massimo di connessioni simultanee consentite dai browser.
Avevo bisogno di uno scanner di porte basato su browser per un'idea su cui stavo lavorando. Pensavo fosse una semplice questione di importare un modulo esistente o copiare/incollare da un altro progetto come BeEF.
Si è scoperto che non esisteva un modulo npm decente pronto all'uso e il modulo port_scanner in BeEF è (al momento della scrittura) impreciso, lento e non funziona su Chromium.
netmap.js è quindi uno "ping" sweeper e scanner TCP in qualche modo ottimizzato che funziona su tutti i browser moderni.
npm install --save netmap.js
Scopriamo l'indirizzo IP del gateway di un visitatore del sito web, partendo da una lista di candidati probabili in un ambiente domestico:
import NetMap from 'netmap.js'
const netmap = new NetMap()
const hosts = ['192.168.0.1', '192.168.0.254', '192.168.1.1', '192.168.1.254']
netmap.pingSweep(hosts).then(results => {
console.log(results)
})
{
"hosts": [
{ "host": "192.168.0.1", "delta": 1003, "live": false },
{ "host": "192.168.0.254", "delta": 1001, "live": false },
{ "host": "192.168.1.1", "delta": 18, "live": true },
{ "host": "192.168.1.254", "delta": 1002, "live": false }
],
"meta": {}
}
Sembra che l'host 192.168.1.1 sia attivo.
Proviamo a trovare alcune porte TCP aperte su alcuni host:
import NetMap from 'netmap.js'
const netmap = new NetMap()
const hosts = ['192.168.1.1', '192.168.99.100', 'google.co.uk']
const ports = [80, 443, 8000, 8080, 27017]
netmap.tcpScan(hosts, ports).then(results => {
console.log(results)
})
{
"hosts": [
{
"host": "192.168.1.1",
"control": "22",
"ports": [
{ "port": 443, "delta": 15, "open": false },
{ "port": 8000, "delta": 19, "open": false },
{ "port": 8080, "delta": 21, "open": false },
{ "port": 27017, "delta": 26, "open": false },
{ "port": 80, "delta": 95, "open": true }
]
},
{
"host": "192.168.99.100",
"control": "1001",
"ports": [
{ "port": 8080, "delta": 40, "open": true },
{ "port": 80, "delta": 1001, "open": false },
{ "port": 443, "delta": 1000, "open": false },
{ "port": 8000, "delta": 1004, "open": false },
{ "port": 27017, "delta": 1000, "open": false }
]
},
{
"host": "google.co.uk",
"control": "1001",
"ports": [
{ "port": 443, "delta": 67, "open": true },
{ "port": 80, "delta": 159, "open": true },
{ "port": 8000, "delta": 1001, "open": false },
{ "port": 8080, "delta": 1002, "open": false },
{ "port": 27017, "delta": 1000, "open": false }
]
}
],
"meta": {}
}
All'inizio i risultati possono sembrare contraddittori.
192.168.1.1 è un dispositivo Linux embedded (un router) sul segmento di rete locale, e l'unica porta aperta è la 80. Possiamo notare che il browser ha impiegato circa 5 volte di più per dare errore sulla 80 rispetto alle altre porte chiuse.
192.168.99.100 è una VM con solo host e porta 8080 aperta, mentre google.co.uk è un host esterno con entrambe le porte 443 e 80 aperte. In questi casi il browser ha generato un errore relativamente rapido sulle porte aperte, mentre le porte chiuse sono semplicemente scadute. La sezione Teoria più avanti spiega quando ciò accade.
Per determinare se le porte devono essere contrassegnate come aperte o chiuse, netmap.js scansiona una porta di "controllo" (per impostazione predefinita 45000) che si presume sia chiusa. Il tempo di control viene quindi utilizzato per determinare lo stato delle altre porte. Se il rapporto delta/control è maggiore di un valore impostato (predefinito 0.8), la porta viene considerata chiusa (in breve: una differenza superiore al 20% rispetto al tempo di controllo significa che la porta è aperta).
I browser mantengono una blacklist di porte a cui rifiutano di connettersi (come FTP, SSH o SMTP). Se provi a scansionare queste porte con netmap.js utilizzando il protocollo predefinito (http), otterrai un timeout molto breve. Un timeout breve è solitamente un segno che la porta è chiusa, ma nel caso di porte in blacklist non significa nulla.
Puoi consultare le blacklist da queste fonti:
Prima di Firefox 61 (e forse altri browser), è possibile aggirare questa limitazione utilizzando il protocollo ftp invece di http per stabilire le connessioni. Puoi specificare il protocol nell'oggetto options quando istanzi NetMap. Quando utilizzi ftp, dovresti aspettarti che le porte aperte vadano in timeout e che le porte chiuse diano errore relativamente rapidamente. La scansione con ftp è anche soggetta alle limitazioni relative ai pacchetti TCP RST discusse in questo documento.
Le richieste di sotto-risorse da protocolli "legacy" come ftp sono state bloccate per un po' in Chromium.
La funzionalità di "ping" sweep fornita da netmap.js fa un buon lavoro nel trovare rapidamente host *nix attivi su un segmento di rete locale (altri computer, telefoni, router, stampanti, ecc.).
Tuttavia, a causa dell'implementazione, ciò non funziona quando i pacchetti TCP RST non vengono restituiti. Tipicamente:
Il motivo è spiegato nella sezione Teoria di seguito.
Questa limitazione non influisce sulle capacità di scansione TCP ed è comunque possibile determinare se gli host di cui sopra sono attivi provando a trovare una porta aperta su di essi.
In generale, ho trovato questo modulo più accurato e veloce rispetto ad altri frammenti di codice trovati in giro per il web. Detto questo, l'intera idea di mappare le reti da un browser sarà per natura imprecisa. I risultati possono variare.
NetMapIl costruttore NetMap accetta un oggetto options che ti permette di configurare:
protocol utilizzato per la scansione (predefinito http, vedi Blacklist delle porte per capire perché potresti volerlo impostare su ftp)timeout di connessione alla porta (predefinito 1000 millisecondi)import NetMap from 'netmap.js'
const netmap = new NetMap({
protocol: 'http',
timeout: 3000
})
pingSweep()Il metodo pingSweep() determina se un dato array di host è attivo. Lo fa verificando se la connessione a una porta va in timeout, nel qual caso un host viene considerato offline (vedi "Ping" Sweep per le limitazioni e Caso standard per la teoria).
Il metodo accetta i seguenti parametri:
hosts array di host da scansionare (indirizzi IP o nomi host)options oggetto con:
maxConnections - il numero massimo di connessioni simultanee (per impostazione predefinita 10 su Chrome e 17 su altri browser - il massimo di connessioni simultanee supportate dai browser)port da scansionare (predefinito 45000)Restituisce una promise.
netmap.pingSweep(['192.168.1.1'], {
maxConnections: 5,
port: 80
}).then(results => {
console.log(results)
})
tcpScan()Il metodo tcpScan() esegue una scansione delle porte su un intervallo di target. Leggi il Caso standard per capire come funziona.
Il metodo accetta i seguenti parametri:
hosts array di host da scansionare (indirizzi IP o nomi host)ports elenco di porte da scansionare (interi tra 1-65535, evita le porte nelle blacklist)options oggetto con:
maxConnections - il numero massimo di connessioni simultanee (per impostazione predefinita 6 - il massimo di connessioni per dominio consentite dai browser)portCallback - una callback da eseguire quando una combinazione host:port individuale ha terminato la scansionecontrolPort - la porta da scansionare per determinare un delta di base per una porta chiusa (predefinito 45000)controlRatio - la somiglianza, in percentuale, dal delta di controllo per cui una porta è considerata chiusa (predefinito 0.8, vedi esempio)Restituisce una promise.
netmap.tcpScan(['192.168.1.1'], [80, 27017], {
maxConnections: 5,
portCallback: result => {
console.log(result)
},
controlPort: 45000,
controlRatio: 0.8
}).then(results => {
console.log(results)
})
Consulta l'esempio per interpretare l'output.
Questa sezione copre brevemente la teoria alla base delle tecniche di scoperta del modulo.
Questo modulo utilizza oggetti Image per tentare di richiedere risorse cross-origin (le serie di URL http://{host}:{port} sotto test). Il tempo che il browser impiega per sollevare un errore (il delta), o l'assenza di errore dopo un certo timeout, fornisce informazioni sullo stato dell'host e della porta in esame.
Un host attivo risponderà di solito relativamente rapidamente con un pacchetto TCP RST quando si tenta di connettersi a una porta chiusa.
Se la porta è aperta, anche se non sta eseguendo un server HTTP, il browser impiegherà un po' più di tempo per sollevare un errore a causa dell'overhead di stabilire una connessione TCP completa e poi rendersi conto che non può ottenere un'immagine dall'URL fornito.
Un host offline naturalmente non risponderà né con un RST né permetterà di stabilire una connessione TCP completa. I browser proveranno comunque a stabilire la connessione per un po' prima del timeout (~90 secondi). netmap.js andrà in timeout dopo aver atteso 1000 millisecondi per impostazione predefinita.
In sintesi:
delta molto brevedelta leggermente più lungoIl caso standard è illustrato dall'host 192.168.1.1 nell'esempio Scansione delle porte TCP.
RSTAlcuni host (come google.co.uk o host Windows) e alcune configurazioni di rete (come le reti solo host di VirtualBox) non restituiranno pacchetti TCP RST quando si colpisce una porta chiusa.
In questi casi, le porte chiuse di solito andranno in timeout, mentre le porte aperte solleveranno rapidamente un errore.
L'implementazione del metodo pingSweep() è quindi inaffidabile quando i pacchetti RST non vengono restituiti.
In sintesi, quando i pacchetti TCP RST non vengono restituiti per qualsiasi motivo:
delta brevepingSweep() non può distinguere tra un timeout di porta chiusa e un timeout di host "morto"Il caso speciale è illustrato dagli host 192.168.99.100 e google.co.uk nell'esempio Scansione delle porte TCP.
È ben documentato che dovresti anche essere in grado di mappare le reti con WebSocket e AJAX.
Ci ho provato (e ho anche modificato BeEF per provare il suo modulo port_scanner solo con WebSocket e AJAX); ho trovato entrambi i metodi completamente inaffidabili.
Fammi sapere se mi sfugge qualcosa a questo proposito.