Project 5 - Port Scanner

Project Objectives

In this course project, you will develop a Python script that performs TCP and UDP port scanning.

Description

A port scanner program identifies the status of transport layer ports. A port can be open, closed, filtered, etc. Port scanning logic is discussed in the class. In this project, you will implement such a tool with the following features.

  • The tool must be implemented in python3 and utilize scapy for custom packet generation. Aside from the socket and argparse libraries, no additional libraries are allowed to be used.
  • Input Arguments: The tool should accept the following arguments using Pyton's argparse functionality:
    • The --tcp or --udp arguments allow the user to select the desired transport layer protocol for scanning. These two options are mutually exclusive. If unspecified, the default should be TCP.
    • The --target X argument allows the user to specify either the IP address or hostname of the target machine to be scanned. If unspecified, localhost (127.0.0.1) should be scanned.
    • The --port argument allows the user to specify a port (--port X) or range of ports (--port X-Y) to be scanned. Any other format for this argument must be rejected. If unspecified, the system port range (0-1023) should be scanned. Only valid port numbers in the range 0-65535 should be scannable.
    • The --verbose argument specifies that all scanned ports (open or closed/filtered) are displayed. Otherwise, only open ports are printed.
  • Do not probe the target initially to determine if it is online. This is similar to running nmap with the -Pn option.
  • For the TCP port scan, your program must do stealth scanning. You send a SYN, the target may respond with SYN-ACK if the port is open, and then you send a RST to stop the connection from proceeding. Note that Linux (not your Python script) will send the RST, because from the perspective of Linux, the operating system didn't try to open this connection, and thus the OS will terminate it.
    • For TCP scans, your results should be similar in style to a nmap scan run with options nmap -Pn -sS -p <port(s)> <Host/IP> --reason. In other words, a TCP stealth scan on a port or range of ports of a given target host, along with the reason for reporting the status of a port in a certain way.
  • For the UDP port scan, your technique will differ somewhat from nmap. In nmap UDP port scanning, valid application layer messages are used for well-known UDP ports. For example, a UDP scan of port 53 would utilize a dummy DNS request, in case a DNS server was listening on that well-known port. In this manner, nmap tries to encourage the target to send back a response for the valid query on the well-known open port. In your program, however, you only have to do this for the DNS port (UDP 53). When probing that port, send a legitimate DNS query for a domain name of your choosing. For probes to any other UDP port, you do not have to do this. For those ports, add a dummy application layer message as a payload to all of your UDP probes. This means that most UDP ports, even if there is an application listening there, will probably be silent to the received message. Your program will miss some open UDP ports and instead identify them as “Filtered|Open” because no response was received.
    • For UDP scans, your results should be similar in style to a nmap scan run with options nmap -Pn -sU -p <port(s)> <Host/IP> --reason, except for open ports. Note that you should also report the reason for the status of each port.
  • Similar to the default behavior of nmap, scan the requested port(s) in a random order rather than a sequential order. Print the output of the scan in sorted order.
  • At the top of the script file, briefly describe how your tool works.

Tip: Be sure to use argparse to handle the command-line arguments. It's much more robust than rolling your own parsing code.

Resources

Deliverables

Submit a single Python script that implements port scanning to the Canvas CMS Project 5 assignment.

If using PyCharm, do not submit your venv environment. Before submitting, test to ensure you can run your program outside of PyCharm on the command line.

Sample Output

Running the tool may generate an output similar to the following in a terminal in Ubuntu Linux.

Help Mode:

$ ./portscanner.py -h
usage: portscanner.py [-h] [-v] [--target TARGET] [--port PORT] [--tcp | --udp] [--verbose]

Port Scanner

optional arguments:
  -h, --help       show this help message and exit
  -v, --version    show program's version number and exit
  --target TARGET  Hostname or IP to scan
  --port PORT      Port [X] or Port Range [X-Y] to scan
  --tcp            TCP port scan (mutually exclusive with --udp)
  --udp            UDP port scan (mutually exclusive with --tcp)
  --verbose        Verbose output (Print all ports, not just open ports)

Version Mode:

shafer@ubuntu:~/comp177/project-5-port-scanner$ ./portscanner.py -v
portscanner.py 1.0

Default Scan, No Options Set:

$ sudo ./portscanner.py
Scan type: tcp
Target: localhost (127.0.0.1)
Port(s): 0-1023
TCP Scanning....

TCP Scan, Non-Verbose Mode, Default Ports:

$ sudo ./portscanner.py --tcp --target cyberlab.pacific.edu
Scan type: tcp
Target: ec2-54-148-163-48.us-west-2.compute.amazonaws.com (54.148.163.48)
Port(s): 0-1023
TCP Scanning....
Port: 22        Status: Open    Reason: Received TCP SYN-ACK
Port: 80        Status: Open    Reason: Received TCP SYN-ACK
Port: 443       Status: Open    Reason: Received TCP SYN-ACK

TCP Scan, Non-Verbose Mode, Ports 0-30:

$ sudo ./portscanner.py --tcp --target cyberlab.pacific.edu  --port 0-30
Scan type: tcp
Target: ec2-54-148-163-48.us-west-2.compute.amazonaws.com (54.148.163.48)
Port(s): 0-30
TCP Scanning....
Port: 22        Status: Open    Reason: Received TCP SYN-ACK

TCP Scan, Verbose Mode, Default Ports:

$ sudo ./portscanner.py --tcp --target cyberlab.pacific.edu --verbose
Scan type: tcp
Target: ec2-54-148-163-48.us-west-2.compute.amazonaws.com (54.148.163.48)
Port(s): 0-1023
TCP Scanning....
Port: 0     Status: Filtered    Reason: No response
Port: 1     Status: Filtered    Reason: No response
Port: 2     Status: Filtered    Reason: No response
Port: 3     Status: Filtered    Reason: No response
Port: 4     Status: Filtered    Reason: No response
Port: 5     Status: Filtered    Reason: No response
Port: 6     Status: Filtered    Reason: No response
Port: 7     Status: Filtered    Reason: No response
Port: 8     Status: Filtered    Reason: No response
Port: 9     Status: Filtered    Reason: No response
Port: 10    Status: Filtered    Reason: No response
Port: 11    Status: Filtered    Reason: No response
Port: 12    Status: Filtered    Reason: No response
Port: 13    Status: Filtered    Reason: No response
Port: 14    Status: Filtered    Reason: No response
Port: 15    Status: Filtered    Reason: No response
Port: 16    Status: Filtered    Reason: No response
Port: 17    Status: Filtered    Reason: No response
Port: 18    Status: Filtered    Reason: No response
Port: 19    Status: Filtered    Reason: No response
Port: 20    Status: Filtered    Reason: No response
Port: 21    Status: Filtered    Reason: No response
Port: 22    Status: Open    Reason: Received TCP SYN-ACK
Port: 23    Status: Filtered    Reason: No response
Port: 24    Status: Filtered    Reason: No response
Port: 25    Status: Filtered    Reason: No response
...... output continues through port 1023.

UDP Scan, Non-Verbose Mode, Default Ports:

$ sudo ./portscanner.py --udp --target 8.8.8.8
Scan type: udp
Target: dns.google (8.8.8.8)
Port(s): 0-1023
UDP Scanning....
Port: 53        Status: Open    Reason: Received DNS Response

nmap Comparison Scans

TCP Scan:

$ sudo nmap -Pn -sS -p 0-1023 cyberlab.pacific.edu --reason
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-18 11:38 PDT
Nmap scan report for cyberlab.pacific.edu (54.148.163.48)
Host is up, received user-set (0.20s latency).
Other addresses for cyberlab.pacific.edu (not scanned): 2600:1f14:536:b01:9cda:64e:15a9:da0
rDNS record for 54.148.163.48: ec2-54-148-163-48.us-west-2.compute.amazonaws.com
Not shown: 1021 filtered ports
Reason: 1021 no-responses
PORT    STATE SERVICE REASON
22/tcp  open  ssh     syn-ack ttl 128
80/tcp  open  http    syn-ack ttl 128
443/tcp open  https   syn-ack ttl 128

Nmap done: 1 IP address (1 host up) scanned in 10.61 seconds

UDP Scan:

$ sudo nmap -Pn -sU -p 0-1023 dns.google --reason
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-18 15:03 PDT
Nmap scan report for dns.google (8.8.4.4)
Host is up, received user-set (0.036s latency).
Other addresses for dns.google (not scanned): 8.8.8.8 2001:4860:4860::8888 2001:4860:4860::8844
Not shown: 1022 open|filtered ports
Reason: 1022 no-responses
PORT    STATE SERVICE REASON
53/udp  open  domain  udp-response ttl 128
443/udp open  https   udp-response ttl 128

Nmap done: 1 IP address (1 host up) scanned in 103.91 seconds