Making a Port Scanner Using Python

Q: What is a port scanner?

A port scanner is a penetration testing tool used for information gathering. It allows us to look at all the open ports of a computer. This is either to ensure our servers are secure or to exploit those of someone else. An unnecessarily opened port can create a vulnerability which threat actors can exploit. It is common for people to scan the ports of their own network to find security gaps.

Important!!!

Before we begin, you need to know that port scanning someone else’s network without their permission is a crime. Only scan your own network or one that you are permitted to. This is a purely educational guide and i do not take responsibility for the misuse of this information.

In this guide, I will show you how to create your own port scanner using the powerful programming language, python. This guide assumes that you have basic knowledge of the python language(loops, if/else, functions, libraries, etc..). We will be using three different libraries for this program, socket, threading, and queue. I will discuss these in more detail later. But essentially, the socket allows us to establish the connections with the ports, threading enables us to have multiple port scans running simultaneously, and the queue will allow us to manage the various threads running the port scans.


Preparing the scanner

We start by first importing the libraries needed:

import socket
import threading
from queue import Queue

Like I mentioned earlier,

  • Socket will be used to connect to a specific host and port
  • Threading enables us to run multiple scan functions simultaneously
  • Queue is a data structure that will help us manage the multiple threads that are running simultaneously, which in our case will be the port scans. Its primary function is to ensure that threads don’t scan a port number more than once.

Next, we need to assign the global variables we will use throughout the program:

target = '192.168.1.254'
queue = Queue()
openPorts = []
  • target assigns the IP of the host you wish to scan
  • queue is currently empty but will be filled later with the ports that need to be scanned
  • openPorts is a list that will contain all the ports that were found open

Now we are going to implement the portScan function to check whether a port is open or not:

def portScan(port):
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((target, port))
        return True
    except:
        return False

We try to connect to our target on a specific port in this function. If the connection works, we return True, which means the scanned port is open. Otherwise, we return False, which means there was an error or the port is closed.

Next, we will create another function that defines the ports we want to scan. The function is called getPorts:

def getPorts(mode):
    if mode == 1:
        for port in range(1, 1024):
            queue.put(port)
    elif mode == 2:
        for port in range(1, 49152):
            queue.port(port)
    elif mode == 3:
        ports = [20, 21, 22, 23, 25, 53, 80, 110, 443]
        for port in ports:
            queue.put(port)
    elif mode == 4:
        ports = input("Enter your ports separated by blanks:")
        ports = ports.split()
        ports = list(map(int, ports))
        for port in ports:
            queue.put(port)

This function defines the four possible modes to scan a target’s ports. The first mode scans the 1023 standardized ports. With the second mode, we add the 48,128 reserved ports. We focus on some of the most important ports using the third mode. Furthermore, the fourth mode allows us to choose our ports manually. In the end, we add all the ports to the queue.


Multi-threading

The following function will be responsible for getting the port numbers from the queue and scanning them. It then finally prints the results:

def queueWorker():
    while not queue.empty():
        port = queue.get()
        if portScan(port):
            print('Port {} is open!'.format(port))
            openPorts.append(port)

Here we can see that we get the next element and scan it as long as the queue is not empty. If the port is open, we add it to our open_ports list and print it out.

Now we are going to write our primary function, which creates, starts, and manages our threads:

def runScanner(threads, mode):
    getPorts(mode)
    threadList = []

    for t in range(threads):
        thread = threading.Thread(target=queueWorker)
        threadList.append(thread)

    for thread in threadList:
        thread.start()

    for thread in threadList:
        thread.join()
    print(f'Open ports are: {openPorts}')

With this function, we have two parameters. The first is for the number of threads we want to start, and the second is for our mode. We load our ports and create an empty list for our threads depending on the mode. We then create the threads and assign them to our queue function to be added to the list. After this, we start the threads and let them scan the different ports. Finally, we wait for all the threads to finish and print all the ports again in a list.


Interface

The final part of this program is the interface for the user to choose what ports they want to scan:

mode = int(input(f'Enter the corresponding number for mode you wish to use\n'
                 f'(1)Scan ports 1-1024\n'
                 f'(2)Scan ports 1-49152\n'
                 f'(3)Scan ports 20, 21, 22, 23, 25, 53, 80, 110, and 443\n'
                 f'(4)Choose your own ports'
                 f'\nEnter Here:'))
runScanner(200,mode)

Here the user is given the interface to choose what mode they wish to use. Once they choose the mode, we call the runScanner function with the number of threads and the mode variable.

This is an example of how the console interface looks:

I hope this guide was helpful, if you have any question feel free to comment on this post.

Link to source code