Table of Contents
Introduction
In the world of ethical hacking, a port scanner is a crucial tool for discovering open ports on a target system. Python, with its robust networking capabilities and vast libraries, provides an excellent platform to build a port scanner from scratch. In this tutorial, you will learn how to utilize Python to create a simple yet effective port scanner. By the end of this tutorial, you will be able to write Python code to scan for open ports on a target system.
Prerequisites
To follow along with this tutorial, you should have a basic understanding of Python programming concepts, including variables, loops, and functions. Additionally, a basic knowledge of networking concepts such as TCP/IP and ports would be beneficial.
Setup
Before we begin building the port scanner, we need to ensure that Python is installed on our system. You can download the latest version of Python from the official website (python.org) and follow the installation instructions for your operating system.
Once Python is installed, you can verify its installation by opening a command prompt or terminal and running the following command:
python
python --version
If Python is correctly installed, you will see the version number printed on the screen.
Building the Port Scanner
Scanning a Single Port
Let’s start by building a basic port scanner that scans a single port on a target system. We will use the socket
module in Python, which provides low-level networking functionalities.
First, import the socket
module:
python
import socket
Next, define a function to perform the port scan:
```python
def scan_port(target_host, target_port):
try:
# Create a socket object
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Set a timeout value (in seconds)
client_socket.settimeout(1)
# Try to connect to the target host and port
result = client_socket.connect_ex((target_host, target_port))
# Check if the port is open
if result == 0:
print(f"Port {target_port} is open")
else:
print(f"Port {target_port} is closed")
# Close the socket
client_socket.close()
except socket.error:
print("An error occurred while connecting to the target")
``` In the `scan_port` function, we create a socket object using `socket.socket()`. We then set a timeout value of 1 second using `settimeout()` to prevent the program from waiting indefinitely if the connection attempt takes too long. Next, we use `connect_ex()` to attempt a connection to the target host and port. If the result is 0, it means the port is open. Otherwise, the port is closed.
To test the port scanner, call the scan_port
function with the target host and port number:
python
scan_port("127.0.0.1", 80)
Replace "127.0.0.1"
with the IP address of the target system and 80
with the desired port number.
Scanning Multiple Ports
Now, let’s enhance our port scanner to scan multiple ports. Instead of scanning a single port, we will provide a list of ports to scan.
Modify the scan_port
function as follows:
```python
def scan_ports(target_host, port_list):
for port in port_list:
try:
# Create a socket object
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Set a timeout value (in seconds)
client_socket.settimeout(1)
# Try to connect to the target host and port
result = client_socket.connect_ex((target_host, port))
# Check if the port is open
if result == 0:
print(f"Port {port} is open")
else:
print(f"Port {port} is closed")
# Close the socket
client_socket.close()
except socket.error:
print("An error occurred while connecting to the target")
``` In the `scan_ports` function, we iterate over the `port_list` and call the `scan_port` function for each port.
To test the new functionality, provide a list of ports to scan:
python
target_ports = [80, 443, 22, 3389]
scan_ports("127.0.0.1", target_ports)
Replace "127.0.0.1"
with the IP address of the target system and [80, 443, 22, 3389]
with the desired list of port numbers.
Handling Exceptions
When scanning multiple ports, it’s important to handle exceptions gracefully and continue scanning even if an error occurs for a particular port. Let’s modify the code to handle exceptions and display a meaningful error message. ```python def scan_ports(target_host, port_list): for port in port_list: try: # Create a socket object client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Set a timeout value (in seconds)
client_socket.settimeout(1)
# Try to connect to the target host and port
result = client_socket.connect_ex((target_host, port))
# Check if the port is open
if result == 0:
print(f"Port {port} is open")
else:
print(f"Port {port} is closed")
except socket.gaierror:
print("Invalid target hostname or IP address")
except socket.timeout:
print(f"Timeout occurred while connecting to port {port}")
except ConnectionRefusedError:
print(f"Connection refused while connecting to port {port}")
except Exception as e:
print(f"An error occurred while connecting to port {port}: {str(e)}")
finally:
# Close the socket
client_socket.close()
``` In the modified code, we added specific exception handlers for common error scenarios such as an invalid target hostname/IP address, timeout, and connection refused. Additionally, we added a generic exception handler to catch any other exceptional scenarios. Finally, we moved the socket closing logic to the `finally` block to ensure the socket is closed regardless of any exception that occurs.
Scanning a Range of Ports
To further enhance our port scanner, let’s add the capability to scan a range of ports. Instead of providing a list of individual ports, we will specify a range of ports to scan.
Modify the scan_ports
function again:
```python
def scan_ports(target_host, start_port, end_port):
for port in range(start_port, end_port + 1):
try:
# Create a socket object
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Set a timeout value (in seconds)
client_socket.settimeout(1)
# Try to connect to the target host and port
result = client_socket.connect_ex((target_host, port))
# Check if the port is open
if result == 0:
print(f"Port {port} is open")
else:
print(f"Port {port} is closed")
except socket.gaierror:
print("Invalid target hostname or IP address")
except socket.timeout:
print(f"Timeout occurred while connecting to port {port}")
except ConnectionRefusedError:
print(f"Connection refused while connecting to port {port}")
except Exception as e:
print(f"An error occurred while connecting to port {port}: {str(e)}")
finally:
# Close the socket
client_socket.close()
``` In the updated code, we use the `range()` function to generate a range of ports from `start_port` to `end_port`. The `end_port + 1` is used to include the `end_port` in the range.
To scan a range of ports, simply call the scan_ports
function with the target host and the desired range:
python
scan_ports("127.0.0.1", 1, 1024)
Replace "127.0.0.1"
with the IP address of the target system and 1
and 1024
with the desired start and end ports.
Conclusion
In this tutorial, you learned how to build a simple port scanner using Python. We started by scanning a single port and gradually enhanced the scanner to support scanning multiple ports and ranges of ports. We also explored exception handling to handle various error scenarios that may arise during the scanning process. By following this tutorial, you now have the necessary knowledge to start building more advanced and sophisticated network scanning tools with Python.
Remember, always use your knowledge and skills responsibly and ethically. Happy hacking!
Note: This tutorial is for educational purposes only. Ethical hacking should only be performed with proper authorization and legal consent.