Skip to main content

Command Palette

Search for a command to run...

Build network port scanning command-line tool using Node.js

Published
4 min read
M

I'm a Student, Developer, Writer and a Tech Geek

Network reconnaissance is extremely crucial in cybersecurity. There have been various technologies created for network scanning.I decided to give it a shot and create a basic command line tool that can scan any network and find vulnerabilities if they exist. In this article, I will show you how to create a simple command-line tool for network scanning. Let's get started.

Initial Setup:

Before diving into the implementation details, ensure you have Node.js and npm (Node Package Manager) installed on your system. These tools will facilitate the development and management of dependencies for this project.

Dependencies:

This project relies on two key dependencies: inquirer for building the command-line interface and axios for making HTTP requests to the National Vulnerability Database (NVD) API. Begin by installing these dependencies via npm:

npm install inquirer axios

Implementation:

Our tool scans a range of ports on a target host to identify open ports and enumerates services running on those ports. We utilize the net module in Node.js for port scanning and service enumeration. Each detected service is categorized based on well-known port assignments. We leverage inquirer to prompt users for input and display results in a user-friendly manner.

For vulnerability assessment, we need NVD API for querying known vulnerabilities associated with the services identified during service enumeration. We utilize the axios module to make HTTP requests to the NVD API and retrieve vulnerability data.

Code:

const inquirer = require("inquirer");
const net = require("net");
const axios = require("axios");

// Function to scan for open ports
async function portScan(host, startPort, endPort) {
  console.log(`Scanning ports on ${host}...`);
  const openPorts = [];
  for (let port = startPort; port <= endPort; port++) {
    await new Promise((resolve) => {
      const socket = new net.Socket();
      socket.setTimeout(100);
      socket.on("connect", () => {
        openPorts.push(port);
        socket.destroy();
        resolve();
      });
      socket.on("timeout", () => {
        socket.destroy();
        resolve();
      });
      socket.on("error", () => {
        resolve();
      });
      socket.connect(port, host);
    });
  }
  return openPorts;
}

/// Function to enumerate services on open ports
async function enumerateServices(host, ports) {
  console.log(`Enumerating services on ${host}...`);
  const services = [];
  for (const port of ports) {
    await new Promise((resolve) => {
      const socket = new net.Socket();
      socket.setTimeout(100);
      socket.on("connect", () => {
        const service = detectService(port);
        services.push({ port, status: "open", service });
        socket.destroy();
        resolve();
      });
      socket.on("timeout", () => {
        const service = detectService(port);
        services.push({ port, status: "filtered", service });
        socket.destroy();
        resolve();
      });
      socket.on("error", () => {
        resolve();
      });
      socket.connect(port, host);
    });
  }
  return services;
}

// Function to detect service based on port number
function detectService(port) {
  switch (port) {
    case 21:
      return "FTP";
    case 22:
      return "SSH";
    case 25:
      return "SMTP";
    case 53:
      return "DNS";
    case 80:
      return "HTTP";
    case 110:
      return "POP3";
    case 123:
      return "NTP";
    case 143:
      return "IMAP";
    case 443:
      return "HTTPS";
    case 587:
      return "SMTP (Submission)";
    case 993:
      return "IMAPS";
    case 995:
      return "POP3S";
    case 1723:
      return "PPTP";
    case 3306:
      return "MySQL";
    case 3389:
      return "RDP";
    case 5432:
      return "PostgreSQL";
    case 5900:
      return "VNC";
    case 6667:
      return "IRC";
    case 8080:
      return "HTTP (Alt)";
    case 8443:
      return "HTTPS (Alt)";
    default:
      return "Unknown";
  }
}

// Function to perform vulnerability assessment
async function assessVulnerabilities(host, services) {
  console.log(`Assessing vulnerabilities on ${host}...`);
  const vulnerabilities = [];
  // Implement logic for assessing vulnerabilities using NVD API
  for (const service of services) {
    try {
      const response = await axios.get(
        `https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=${service.service}`
        );

      if (
        response.data &&
        response.data.result &&
        response.data.result.totalResults > 0
      ) {
        vulnerabilities.push({
          service: service.service,
          vulnerabilities: response.data.result.CVE_Items,
        });
      } else {
        console.log(`No vulnerabilities found for service ${service.service}`);
      }
    } catch (error) {
      console.error(
        `Error assessing vulnerabilities for service ${service.service}:`,
        error.message
      );
    }
  }

  return vulnerabilities;
}

// Function to display results
function displayResults(openPorts, services, vulnerabilities) {
  console.log("--- Open Ports ---");
  console.log(openPorts.join(", "));
  console.log("------------------");

  console.log("--- Services ---");
  console.table(services);  // Displays it in a small table
  console.log("----------------");

  console.log("--- Vulnerabilities ---");
  console.table(vulnerabilities); // Appears if found any vulns
  console.log("-----------------------");
}

// Main function to execute network reconnaissance
// Prompting happens here
async function main() {
  const questions = [
    {
      type: "input",
      name: "host",
      message: "Enter the target host:", // Enter IP address
      validate: (input) => input.trim() !== "",
    },
    {
      type: "number",
      name: "startPort",
      message: "Enter the start port:", // Specify the starting port (from)
      default: 1,
    },
    {
      type: "number",
      name: "endPort",
      message: "Enter the end port:", // Specify the ending port (to)
      default: 1024,
    },
  ];

  try {
    const { host, startPort, endPort } = await inquirer.prompt(questions);

    const openPorts = await portScan(host, startPort, endPort);
    const services = await enumerateServices(host, openPorts);
    const vulnerabilities = await assessVulnerabilities(host, services);

    displayResults(openPorts, services, vulnerabilities);
  } catch (error) {
    console.error("An error occurred:", error);
  }
}

main(); // Execute the application

Conclusion

That's it. You now have a fully functional network scanner tool. You can make it even more interesting by adding additional features. If any questions or any doubts comment. If this article looks interesting and want to read more like this, click on that follow button. Thank you for reading!