No history yet

Socket-Level Security Tools

Sockets The Building Blocks

At the lowest level of network programming in Python is the socket module. It provides a direct interface to the operating system's networking capabilities. Think of a socket as a digital endpoint for sending or receiving data. Just like you plug a cable into a physical socket in a wall, your program creates a software socket to connect to another program on a network.

Sockets come in two main flavors, corresponding to the two most common transport layer protocols: TCP and UDP. Choosing between them depends entirely on what you need to accomplish.

ProtocolTypeKey Feature
TCPConnection-OrientedReliable, ordered data delivery. A handshake establishes the connection before data is sent.
UDPConnectionlessFast, low-overhead data broadcast. No guarantee of delivery or order.

For tasks like port scanning, where reliability is key, we almost always use TCP sockets. Creating one is straightforward.

import socket

# Create a socket object
# AF_INET specifies we're using IPv4
# SOCK_STREAM specifies it's a TCP socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Always a good practice to close the socket when done
s.close()

With AF_INET, we're telling the socket to use the standard IPv4 address family. For a UDP socket, you would simply use socket.SOCK_DGRAM instead of SOCK_STREAM.

Building a Port Scanner

One of the first steps in network reconnaissance is discovering which services are running on a target machine. We do this by checking which ports are open. A port scanner is a tool that automates this process. While powerful tools like Nmap exist, building your own helps you understand the underlying mechanics and gives you a custom tool when off-the-shelf options are unavailable or too noisy.

The core of our scanner is the socket's connect_ex() method. Unlike the standard connect(), which raises an exception on failure, connect_ex() returns an error code. A return value of 0 indicates the connection was successful, meaning the port is open. Anything else means it's closed or unreachable.

We also need to set a timeout. Without one, our script could hang for a long time trying to connect to a port that isn't responding. socket.setdefaulttimeout() applies a global timeout to all new sockets.

import socket

target = '127.0.0.1' # Scan localhost
socket.setdefaulttimeout(1) # 1 second timeout

for port in range(1, 1025):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    result = s.connect_ex((target, port))
    if result == 0:
        print(f'Port {port} is open')
    s.close()

Speeding It Up With Threads

The simple scanner works, but it's slow. It checks each port one by one, waiting for the timeout or a connection on each before moving to the next. Scanning all 65,535 ports would take ages. To fix this, we can use multi-threading.

Python's threading module lets us run multiple functions concurrently. We can create a worker function that scans a single port and then spawn hundreds of threads, each running that function for a different port. This allows us to check many ports in parallel, drastically reducing the total scan time.

import socket
import threading
from queue import Queue

target = '127.0.0.1'
queue = Queue()
open_ports = []

def port_scan(port):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(1)
        s.connect((target, port))
        return True
    except:
        return False

def worker():
    while not queue.empty():
        port = queue.get()
        if port_scan(port):
            print(f'Port {port} is open')
            open_ports.append(port)

for port in range(1, 1025):
    queue.put(port)

threads = []
for _ in range(100): # Create 100 threads
    thread = threading.Thread(target=worker)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join() # Wait for all threads to finish

print('Open ports are:', open_ports)

Identifying Services with Banners

Knowing a port is open is useful, but knowing what service is running on it is even better. Many services announce themselves by sending a "banner" when a client connects. This banner often contains the software name and version, which is invaluable for a security assessment. This technique is called s.

We can grab this banner by using the recv() method on our socket right after a successful connection. This method receives a specified number of bytes from the socket. We'll add this to our simple, single-threaded scanner for clarity.

import socket

target = '127.0.0.1'
socket.setdefaulttimeout(2)

for port in [21, 22, 25, 80]: # Common ports
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((target, port))
        
        # Try to receive 1024 bytes of data
        banner = s.recv(1024)
        
        print(f'Port {port} is open')
        print(f'  Banner: {banner.decode().strip()}')
        s.close()
        
    except Exception as e:
        # Port is likely closed or banner not sent
        print(f'Port {port} is closed or no banner. Error: {e}')

By combining socket programming, threading, and banner grabbing, you can build powerful and custom reconnaissance tools. These low-level skills are the foundation for understanding how more advanced network security tools operate under the hood.

Quiz Questions 1/5

What is the primary role of Python's socket module?

Quiz Questions 2/5

When building a port scanner, why is the connect_ex() method generally preferred over the connect() method?

With these fundamentals, you're now equipped to interact with networks at a much deeper level.