Skip to content Skip to sidebar Skip to footer

Portscan In Node Doesn't Work If Port Range Is Too Wide

I'm trying to write a simple portscan script in nodejs. You can run this script against scanme.nmap.org. By running nmap itself I know that this host has four open ports: 22, 80, 9

Solution 1:

You are probably trying to open too many connections at once and running out of resources or being blocked at the receiving server for flooding it.

Because all your socket stuff is async, your for loop is immediately attempting to open 35,000 sockets. While servers can be configured to do that, it takes a very special configuration and it takes a low memory scheme for using each socket (which you don't have here).

So, a straightforward solution is to limit how many sockets are open at once to some reasonable number.

Here's some code that initially opens a fixed number of sockets and then as each one completes, it then opens another, maintaining a fix number of open and active sockets. It is currently set to have 100 sockets open at once. You can experiment in your particular environment and operating system to see how high you can make that number without incurring problems:

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

var maxInFlight = 100;


functionscanPort(port) {
    returnnewPromise(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;

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

run();

Note: When set for 100 at a time, this takes awhile to run through all the ports up to 35,000. It does find the four open ports you mention.


And, here's another version that collects info about each port and how it failed/succeeded so you get a dump at the end. It also shows progress in the console so you can see if it's still running or not and how close it is to being done:

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

var low = 1;
var high = 35000;

var maxInFlight = 200;


functionscanPort(port) {
    returnnewPromise(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 = [];

functionrun() {
    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);
            } elseif (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 portsif (inFlightCnt === 0 && cntr >= high) {
        console.log("open: " + JSON.stringify(openPorts));
        console.log("timeouts: " +  JSON.stringify(timeouts));
        console.log("otherErrors: " +  JSON.stringify(otherErrors));
    }
}

run();

Here's the output it generates when I run it on Windows 10 with node v4.0.0:

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: []

I don't know why some ports time out. Most get ECONNREFUSED which is kind of what you would expect for a port that isn't open, a few get ETIMEDOUT from the net library and a few timeout from the timeout in your code (which I increased to 15 seconds).

Also, notice that I added a destroy after they connect. You were leaving those sockets open which works fine here when only a couple connect, but could be a problem if lots of ports connect.


Note of Caution: While testing this program I ran it many, many times and after about the 20th time I ran it my internet connection went down for a little while and it took a reboot of my cable modem to get things working again. I suspect something inside the cable modem could not handle this rapid fire flood of requests over and over again while testing. But, it also could have been Comcast shutting down my connection due to the unusual activity (a flood of port requests).

Of course, this could have all been a coincidence and my little outage could have had no connection to what I was doing, but the timing seems too connected for me to think it's just a coincidence.

This program could be modified further to "slow it down" by metering out no more than N port probes per second.

Post a Comment for "Portscan In Node Doesn't Work If Port Range Is Too Wide"