
Быстрый модуль обнаружения сети на основе браузера
Быстрый модуль обнаружения сети на основе браузера
Этот проект больше не поддерживается.
netmap.js предоставляет возможности обнаружения хостов и сканирования портов на основе браузера, позволяя вам картировать сети посетителей вашего сайта.
Он довольно быстр, используя es6-promise-pool для эффективного выполнения максимального количества одновременных соединений, которое позволяет браузер.
Мне понадобился сканер портов на основе браузера для идеи, над которой я работал. Я думал, что это будет просто импортировать существующий модуль или скопировать-вставить из другого проекта, например BeEF.
Оказалось, что нет подходящего готового модуля npm, а модуль port_scanner в BeEF (на момент написания) неточен, медленен и не работает на Chromium.
netmap.js — это несколько оптимизированный «пинг»-сканер и TCP-сканер, который работает во всех современных браузерах.
npm install --save netmap.js
Давайте определим IP-адрес шлюза посетителя сайта, начиная со списка вероятных кандидатов в домашней среде:
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": {}
}
Хост 192.168.1.1 похоже, жив.
Давайте попробуем найти несколько открытых TCP-портов на нескольких хостах:
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": {}
}
На первый взгляд результаты могут показаться противоречивыми.
192.168.1.1 — это встроенная Linux-машина (роутер) в локальном сегменте сети, и единственный открытый порт — 80. Мы видим, что браузеру потребовалось примерно в 5 раз больше времени, чтобы завершиться ошибкой на порту 80, по сравнению с другими, закрытыми, портами.
192.168.99.100 — это виртуальная машина с host-only сетью, у которой открыт порт 8080, а google.co.uk — внешний хост с открытыми портами 443 и 80. В этих случаях браузер относительно быстро выдавал ошибку на открытых портах, в то время как закрытые порты просто таймаутились. Раздел Теория ниже объясняет, когда это происходит.
Чтобы определить, следует ли помечать порты как открытые или закрытые, netmap.js сканирует «контрольный» порт (по умолчанию 45000), который считается закрытым. Затем время control используется для определения статуса других портов. Если отношение delta/control больше заданного значения (по умолчанию 0.8), порт считается закрытым (короче говоря: разница более 20% от контрольного времени означает, что порт открыт).
Браузеры поддерживают чёрные списки портов, к которым они отказываются подключаться (например, FTP, SSH или SMTP). Если вы попытаетесь отсканировать эти порты с помощью netmap.js с использованием протокола по умолчанию (http), вы получите очень короткий таймаут. Короткий таймаут обычно является признаком того, что порт закрыт, но в случае заблокированных портов это ничего не значит.
Вы можете проверить чёрные списки из этих источников:
До Firefox 61 (и, возможно, других браузеров) можно обойти это ограничение, используя протокол ftp вместо http для установки соединений. Вы можете указать protocol в объекте опций при создании экземпляра NetMap. При использовании ftp следует ожидать, что открытые порты будут таймаутиться, а закрытые — относительно быстро выдавать ошибку. Сканирование через ftp также подвержено ограничениям, связанным с пакетами TCP RST, которые обсуждаются в этом документе.
Запросы подресурсов из «устаревших» протоколов, таких как ftp, были заблокированы некоторое время назад в Chromium.
Функционал «пинг»-сканирования, предоставляемый netmap.js, довольно хорошо справляется с быстрым поиском живых хостов на основе *nix в локальном сегменте сети (другие компьютеры, телефоны, роутеры, принтеры и т.д.).
Однако из-за реализации это не будет работать, когда пакеты TCP RST не возвращаются. Обычно:
Причина этого объясняется в разделе Теория ниже.
Это ограничение не влияет на возможности TCP-сканирования, и по-прежнему можно определить, живы ли вышеуказанные хосты, попытавшись найти на них открытый порт.
В целом, я обнаружил, что этот модуль более точен и быстрее, чем другие фрагменты кода, которые я нашёл в интернете. Тем не менее, сама идея картирования сетей из браузера по своей природе будет капризной. Ваш опыт может отличаться.
NetMapКонструктор NetMap принимает объект опций, который позволяет настроить:
protocol, используемый для сканирования (по умолчанию http; см. Чёрные списки портов для информации, почему его можно установить в ftp)timeout (по умолчанию 1000 миллисекунд)import NetMap from 'netmap.js'
const netmap = new NetMap({
protocol: 'http',
timeout: 3000
})
pingSweep()Метод pingSweep() определяет, жив ли заданный массив хостов. Это делается путём проверки, истекает ли время подключения к порту; в этом случае хост считается офлайн (см. «Пинг»-сканирование для ограничений и Стандартный случай для теории).
Метод принимает следующие параметры:
hosts — массив хостов для сканирования (IP-адреса или имена хостов)options — объект с:
maxConnections — максимальное количество одновременных соединений (по умолчанию 10 в Chrome и 17 в других браузерах — максимальное количество одновременных соединений, поддерживаемое браузерами)port — порт для сканирования (по умолчанию 45000)Возвращает promise.
netmap.pingSweep(['192.168.1.1'], {
maxConnections: 5,
port: 80
}).then(results => {
console.log(results)
})
tcpScan()Метод tcpScan() выполняет сканирование портов по диапазону целей. Прочитайте Стандартный случай, чтобы понять, как это работает.
Метод принимает следующие параметры:
hosts — массив хостов для сканирования (IP-адреса или имена хостов)ports — список портов для сканирования (целые числа от 1 до 65535, избегайте портов из чёрных списков)options — объект с:
maxConnections — максимальное количество одновременных соединений (по умолчанию 6 — максимальное количество соединений на домен, которое разрешают браузеры)portCallback — callback, выполняемый после завершения сканирования отдельной комбинации host:portcontrolPort — порт для сканирования, чтобы определить базовую дельту закрытого порта (по умолчанию 45000)controlRatio — сходство в процентах от контрольной дельты, чтобы порт считался закрытым (по умолчанию 0.8; см. пример)Возвращает 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)
})
Проверьте пример, чтобы интерпретировать вывод.
В этом разделе кратко описывается теория, лежащая в основе методов обнаружения модуля.
Этот модуль использует объекты Image для попытки запроса кросс-доменных ресурсов (серии URL-адресов http://{host}:{port}, которые тестируются). Время, за которое браузер выдаёт ошибку (delta), или отсутствие ошибки после определённого значения таймаута, даёт представление о состоянии хоста и порта.
Живой хост обычно относительно быстро отвечает пакетом TCP RST при попытке подключения к закрытому порту.
Если порт открыт, и даже если на нём не запущен HTTP-сервер, браузеру потребуется немного больше времени, чтобы выдать ошибку из-за накладных расходов на установку полного TCP-соединения и последующего осознания, что изображение по указанному URL получить невозможно.
Офлайн-хост, естественно, не ответит ни RST, ни позволит установить полное TCP-соединение. Браузеры всё равно будут пытаться установить соединение некоторое время, прежде чем произойдёт таймаут (~90 секунд). netmap.js по умолчанию таймаутится через 1000 миллисекунд.
Резюмируя:
deltadeltaСтандартный случай иллюстрируется хостом 192.168.1.1 в примере TCP Port Scan.
RSTНекоторые хосты (например, google.co.uk или Windows-хосты) и некоторые сетевые конфигурации (например, host-only сети VirtualBox) не возвращают пакеты TCP RST при обращении к закрытому порту.
В этих случаях закрытые порты обычно таймаутятся, в то время как открытые порты быстро выдают ошибку.
Реализация метода pingSweep() поэтому ненадёжна, когда пакеты RST не возвращаются.
Резюмируя, когда пакеты TCP RST по какой-либо причине не возвращаются:
deltapingSweep() не может отличить таймаут закрытого порта от таймаута «мёртвого» хостаОсобый случай иллюстрируется хостами 192.168.99.100 и google.co.uk в примере TCP Port Scan.
Хорошо задокументировано, что вы также должны иметь возможность картировать сети с помощью WebSockets и AJAX.
Я попробовал это (а также настроил BeEF на использование только модуля port_scanner с WebSockets и AJAX); я обнаружил, что оба метода дают совершенно ненадёжные результаты.
Пожалуйста, дайте мне знать, если я что-то упускаю в этом отношении.