2016-04-23 31 views
0

我正在嘗試在nodejs中編寫一個簡單的portscan腳本。您可以針對scanme.nmap.org運行此腳本。通過運行nmap本身我知道,這臺主機有四個開放的端口:22,80,9929,31337.如果端口範圍太寬,Portscan in Node無法工作

我的腳本是:

var net = require('net'); 
var host = 'scanme.nmap.org'; 
var max = 35000; 

function scanPort(port) { 
    try { 
     var c = new net.Socket(); 
     c.setTimeout(5000); 
     c.connect({ 
      port: port, 
      host: host 
     }) 

     c.on('connect', function() { 
      console.log(port); 
     }) 

     c.on('error', function (err) { 
      c.destroy(); 
     }) 

     c.on('timeout', function() { 
      c.destroy(); 
     }) 
    } catch (err) { 
     console.error(err); 
    } 
} 

for (i = 1; i<=max; i++) { 
    scanPort(i); 
} 

如果我開始從i = 1循環,腳本會檢測端口22和80之後,它將以退出碼0退出。它不會檢測到其他兩個端口。如果我玩變量i,即跳過第一個端口並設置i = 9500,它將正確檢測端口9929。如果我設置i = 31000,檢測到端口31337,則會發生同樣的情況。

我真的不明白爲什麼它不按預期工作。我懷疑某些系統限制會導致一些錯誤,但我試圖將掃描功能封裝在try塊中,但未設法檢測到任何錯誤。

+0

在錯誤和超時回調中添加一個console.log。嘗試趕上dos無助於異步代碼。 –

+0

您可能應該增加打開文件描述符的最大數量。這取決於操作系統。 – lipp

回答

4

您可能試圖一次性打開太多的連接,並且資源耗盡或在接收服務器上被阻塞,導致其氾濫。

因爲所有的套接字都是異步的,您的for循環立即嘗試打開35,000個套接字。雖然服務器可以配置爲這樣做,但它需要一個非常特殊的配置,並且使用每個套接字(這裏您沒有)需要較少的內存方案。

因此,一個簡單的解決方案是限制一次打開多少個套接字到一些合理的數量。

下面是一些代碼,最初打開一個固定數量的套接字,然後當每個套接字完成時,它會打開另一個,保持固定數量的打開和活動套接字。它目前設置爲一次打開100插座。您可以在特定的環境和操作系統實驗,看看你有多高這個號碼,而不會產生問題:

var net = require('net'); 
var host = 'scanme.nmap.org'; 
var low = 1; 
var high = 35000; 

var maxInFlight = 100; 


function scanPort(port) { 
    return new Promise(function(resolve, reject) { 
     var c = new net.Socket(); 
     c.setTimeout(5000); 
     c.connect({ 
      port: port, 
      host: host 
     }) 

     c.on('connect', function() { 
      console.log(port); 
      c.destroy(); 
      resolve(port); 
     }) 

     c.on('error', function (err) { 
      c.destroy(); 
      reject(err); 
     }) 

     c.on('timeout', function() { 
      c.destroy(); 
      reject({code: "Timeout", port: port}); 
     }) 
    }); 
} 

var cntr = low; 
var inFlightCnt = 0; 

function run() { 
    while (inFlightCnt < maxInFlight && cntr <= high) { 
     ++inFlightCnt; 
     scanPort(cntr++).then(function(port) { 
      --inFlightCnt; 
      run(); 
     }, function(err) { 
      --inFlightCnt; 
      run(); 
     }); 
    } 
} 

run(); 

注:當設置爲100的時間,這需要一段時間,所有端口向上運行到35,000。它確實找到你提到的四個開放端口。


而且,這裏的另一個版本,收集關於每個端口的信息,以及它如何失敗/成功,所以你在最後得到的轉儲。它也顯示在控制檯的進步,所以你可以看到,如果它仍在運行與否,以及如何關閉它就是正在做:

var net = require('net'); 
var host = 'scanme.nmap.org'; 

var low = 1; 
var high = 35000; 

var maxInFlight = 200; 


function scanPort(port) { 
    return new Promise(function(resolve, reject) { 
     var c = new net.Socket(); 
     c.setTimeout(15000); 
     c.connect({ 
      port: port, 
      host: host 
     }) 

     c.on('connect', function() { 
      c.destroy(); 
      resolve(port); 
     }) 

     c.on('error', function (err) { 
      c.destroy(); 
      reject(err); 
     }) 

     c.on('timeout', function() { 
      c.destroy(); 
      reject({code: "timeout", port: port}); 
     }) 
    }); 
} 

var cntr = low; 
var inFlightCnt = 0; 

var openPorts = []; 
var timeouts = []; 
var refused = []; 
var otherErrors = []; 

function run() { 
    while (inFlightCnt < maxInFlight && cntr <= high) { 
     ++inFlightCnt; 
     scanPort(cntr++).then(function(port) { 
      --inFlightCnt; 
      openPorts.push(port); 
      console.log(openPorts); 
      run(); 
     }, function(err) { 
      if (err.code === "timeout" || err.code === "ETIMEDOUT") { 
       timeouts.push(err.port); 
      } else if (err.code === "ECONNREFUSED") { 
       refused.push(err.port); 
      } else { 
       otherErrors.push(err.port); 
      } 
      console.log(err.code + ": " + err.port); 
      --inFlightCnt; 
      run(); 
     }); 
    } 
    // if we are all done here, log the open ports 
    if (inFlightCnt === 0 && cntr >= high) { 
     console.log("open: " + JSON.stringify(openPorts)); 
     console.log("timeouts: " + JSON.stringify(timeouts)); 
     console.log("otherErrors: " + JSON.stringify(otherErrors)); 
    } 
} 

run(); 

下面是它的輸出,當我與節點V4.0.0在Windows 10運行:

open: [22,80,9929,31337] 
timeouts: [25,135,136,137,138,139,445,974,984,972,965,963,964,978,985,980,975,981,987,971,960,977,1000,992,990,986,991,997,1391,1384,7455,7459,7450,7506,7512,23033,23736,33635,33640,33638,33641,33634,33636,33633] 
otherErrors: [] 

我不知道爲什麼有些端口超時。大多數得到ECONNREFUSED這是你所期望的不開放的端口,幾個從net庫得到ETIMEDOUT和從你的代碼超時(我增加到15秒)的幾個超時。

另外,請注意,我在連接後添加了一個銷燬。當只有一對連接時,你正在離開那些可以正常工作的插座,但是如果連接很多端口,可能會出現問題。


注意事項:在測試這個節目,我跑了很多很多次,關於第20次我跑了後,我的互聯網連接走下了一小會兒,它把我的電纜重新啓動調制解調器讓事情重新開始。我懷疑有線調制解調器內部的某些東西在測試過程中無法一次又一次地處理這種快速的請求。但是,由於不尋常的活動(大量的端口請求),Comcast也可能會關閉我的連接。

當然,這可能都是巧合,我的小故障可能與我正在做的事情沒有關係,但時機似乎太相關了,我認爲這只是一個巧合。

這個程序可以通過計算出每秒鐘不超過N個端口探頭進一步修改以「減慢速度」。

+0

增加了一個新版本的代碼,收集每個套接字上的數據,最後可以看到一個總結。 – jfriend00