All Projects
CompletedSecurityNetworking2024-06-01

Network Security Scanner

A Python tool to scan local subnets, discover active hosts, identify open TCP services, and check basic service configurations. Tested in a local lab environment.

PythonBashNmapTCP/IPSocket Programming

Overview

I built a Python command-line tool to scan local networks and detect open services without depending on heavy third-party scanning frameworks. The project helped me understand how TCP handshakes operate at the socket layer and how network latency affects scan accuracy.

Goal

Build a lightweight reconnaissance and verification script that can:

  • Discover live hosts on a /24 subnet using ARP requests and ICMP ping probes.
  • Scan specific TCP ports or common port lists across detected hosts.
  • Perform banner grabbing to identify running service versions (such as SSH and HTTP).
  • Save clean JSON and plaintext summary reports for documentation.

Lab Environment

  • Host workstation: Ubuntu Linux 22.04 LTS.
  • Test subnet: 192.168.10.0/24 (isolated VirtualBox host-only network).
  • Target virtual machines:
    • Debian 12 running OpenSSH 9.2, Nginx 1.22, and an unauthenticated Redis instance on port 6379.
    • Windows 10 test VM with Windows Defender Firewall enabled.
    • Raspberry Pi 4 running lighttpd and SSH.

Architecture & Scan Flow

[ Scanner CLI ]
       |
       +---> [ Phase 1: Host Discovery ]
       |        |-- ICMP Echo Request / ARP Ping
       |        `-- Filter active responders
       |
       +---> [ Phase 2: TCP Port Scanner ]
       |        |-- Standard TCP Connect probe (socket.connect_ex)
       |        `-- Configurable socket timeout (0.5s default)
       |
       +---> [ Phase 3: Service Banner Grabbing ]
       |        |-- Send probe bytes (\r\n or HTTP HEAD)
       |        `-- Capture first 1024 bytes of response
       |
       `---> [ Phase 4: Report Generation ]
                `-- Structured output to stdout / results.json

Implementation Details

The scanner is organized into modular Python components:

  1. Host Discovery (discovery.py): Uses raw sockets for ICMP echo requests where permissions allow, or falls back to system ping -c 1 -W 1 to locate alive IPs.
  2. Port Scanner (scanner.py): Uses Python's native socket library. It attempts connections using socket.connect_ex((ip, port)). If the return code is 0, the port is recorded as open; 111 (ECONNREFUSED) records it as closed; timeout records it as filtered.
  3. Banner Grabber (banner.py): For open ports, opens a short-lived stream, sends a minimal probe, and extracts server identity headers.
python — sample scan output
$ python3 scanner.py --target 192.168.10.50 --ports 21,22,80,443,6379 --timeout 0.5
$ [*] Starting scan on target: 192.168.10.50
$ [+] Host is up (ICMP reply received)
$ [+] Port 22/tcp OPEN - Banner: SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2
$ [+] Port 80/tcp OPEN - Banner: nginx/1.22.1
$ [+] Port 6379/tcp OPEN - Banner: Redis server v=7.0.15 (unprotected mode)
$ [-] Port 21/tcp CLOSED
$ [-] Port 443/tcp CLOSED
$ [*] Scan completed in 1.12s. 3 open ports found.

Problems Encountered & Fixes

1. Socket Hanging on Filtered Ports

  • Problem: In the first prototype, the scanner used blocking sockets with the default OS timeout (often 30–60 seconds per port). When scanning hosts with firewalls that drop packets silently (like the Windows test VM), the script took over 15 minutes to finish scanning just 20 ports.
  • Fix: Implemented strict per-socket timeouts using sock.settimeout(0.5). For local subnets, 500ms proved optimal to detect drops without false negatives.

2. Service Banner Deadlocks

  • Problem: Certain services (such as HTTP servers) wait for the client to speak first before sending any data, while others (like SSH or FTP) output a welcome banner immediately. A simple sock.recv(1024) caused the script to freeze indefinitely on HTTP ports.
  • Fix: Added service-specific probe triggers: sending a generic HEAD / HTTP/1.0\r\n\r\n when connecting to common web ports (80, 8080, 443) before calling recv().

Validation Against Nmap

I tested the tool against Nmap on the same target to evaluate accuracy:

  • Nmap command: nmap -sT -p 21,22,80,443,6379 192.168.10.50
  • Results matched completely on open and closed state classification.
  • Nmap was faster across wide port ranges due to asynchronous epoll/select loops, whereas my initial version ran sequential sockets. This highlighted why multi-threading or async I/O is standard in production tools.

Limitations

  • Local Lab Only: Tested strictly in private lab networks; not designed or tested for wide-area Internet routing.
  • No Raw Packet Crafting: Uses high-level TCP sockets (connect()), meaning it completes the full three-way handshake and cannot perform stealth SYN scans (-sS) without root raw sockets.
  • Single-Threaded Sequential Core: Scans large subnets slowly compared to tools built in C or Go.

What I Learned

  • How the operating system handles socket state transitions (SYN_SENT to ESTABLISHED or CLOSED).
  • The difference between connection refusal (RST packet returned) and firewall packet drop (timeout).
  • Why timing templates and timeout thresholds are critical in network scanning tools.