Project 1: Build Your Own Network Reconnaissance Toolkit
Project 1: Build Your Own Network Reconnaissance Toolkit
Project Overview
| Attribute | Value |
|---|---|
| Difficulty | Beginner-Intermediate |
| Time Estimate | 1-2 weeks |
| Programming Language | Python |
| Primary Tool | Scapy / Raw Sockets |
| Main Book | โBlack Hat Pythonโ by Justin Seitz |
| Knowledge Area | Networking / Security |
Learning Objectives
By completing this project, you will:
- Understand TCP/IP at the packet level - Not just conceptually, but what actual bytes travel over the wire
- Implement port scanning from scratch - Learn why Nmap works the way it does by building your own
- Master DNS enumeration techniques - Discover subdomains, mail servers, and zone transfer vulnerabilities
- Develop service fingerprinting skills - Identify whatโs running on open ports by analyzing banners
- Build production-quality security tools - Handle threading, timeouts, and error conditions like professional tools
The Core Question
โHow do attackers discover whatโs running on a network before they even attempt exploitation?โ
Reconnaissance is the foundation of every penetration test. Before you can hack anything, you need to know:
- What hosts are alive on the network?
- What ports are open on each host?
- What services are running behind those ports?
- What versions of software are exposed?
By building these tools yourself, youโll understand the mechanics of network discovery at a fundamental levelโknowledge that makes you effective with tools like Nmap and helps you understand what defenders see.
Deep Theoretical Foundation
The TCP/IP Stack: Where Scanning Lives
Before writing a single line of code, you must understand how data travels across networks. The TCP/IP model has four layers, and your reconnaissance tools will operate primarily at Layer 3 (Network) and Layer 4 (Transport):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ APPLICATION LAYER โ
โ HTTP, HTTPS, SSH, FTP, DNS, SMTP, MySQL โ
โ "What humans interact with" โ
โ โ
โ Example: GET /index.html HTTP/1.1 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TRANSPORT LAYER โ
โ TCP (connection-oriented) / UDP (connectionless) โ
โ "How data is segmented and guaranteed delivery" โ
โ โ
โ TCP Header Structure: โ
โ โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโ โ
โ โ Source Port โ Dest Port โ (16 bits each) โ
โ โโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโค โ
โ โ Sequence Number โ (32 bits) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Acknowledgment Number โ (32 bits) โ
โ โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโค โ
โ โ Data Offset, โ Flags (URG,ACK, โ โ
โ โ Reserved โ PSH,RST,SYN,FIN)โ โโโ Port scanning uses these!โ
โ โโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโค โ
โ โ Window Size โ (16 bits) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Checksum โ Urgent Pointer โ โ
โ โโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ NETWORK LAYER โ
โ IP (IPv4/IPv6), ICMP, Routing โ
โ "How packets find their way across networks" โ
โ โ
โ IPv4 Header: โ
โ โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโ โ
โ โ Version (4) โ IHL โ (4 bits each) โ
โ โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโค โ
โ โ DSCP โ ECN โ โ
โ โโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโค โ
โ โ Total Length โ (16 bits) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Identification โ (16 bits) โ
โ โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโค โ
โ โ Flags โ Fragment Offset โ โ
โ โโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโค โ
โ โ TTL โ Protocol โ โโโ 6=TCP, 17=UDP, 1=ICMP โ
โ โโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโค โ
โ โ Header Checksum โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Source IP Address โ (32 bits) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Destination IP Address โ (32 bits) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ LINK LAYER โ
โ Ethernet, WiFi, ARP โ
โ "Physical transmission on local network" โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ

The TCP Three-Way Handshake: Why Port Scanning Works
TCP is a connection-oriented protocol. Before any data transfer, client and server must establish a connection using a โthree-way handshakeโ:
Normal TCP Connection Establishment
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Client Server
โ โ
โ SYN (Synchronize) โ
โ seq=100, ack=0, flags=SYN โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบโ
โ "I want to connect. My sequence starts at 100" โ
โ โ
โ SYN-ACK โ
โ seq=300, ack=101, flags=SYN+ACK โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ "OK. My sequence starts at 300. โ
โ I expect your next byte to be 101" โ
โ โ
โ ACK (Acknowledge) โ
โ seq=101, ack=301, flags=ACK โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบโ
โ "Got it. Connection established." โ
โ โ
โ โโโโโโโ CONNECTION ESTABLISHED โโโโโโโ โ
โ โ
Why this matters for scanning: By sending specific combinations of TCP flags, we can probe a portโs state without completing a full connection:
Port States and What They Mean
OPEN PORT (Service Listening)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Scanner Target
โ โ
โ SYN โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบโ
โ โ
โ SYN-ACK โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ "Yes, I'm listening on this port!" โ
โ โ
โ RST (or complete handshake) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบโ
โ โ
Result: PORT IS OPEN
โโโโโโโโโโโโโโโโโโโโโ
CLOSED PORT (Nothing Listening)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Scanner Target
โ โ
โ SYN โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบโ
โ โ
โ RST โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ "Nothing running here. Go away!" โ
โ โ
Result: PORT IS CLOSED
โโโโโโโโโโโโโโโโโโโโโโ
FILTERED PORT (Firewall Blocking)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Scanner Target
โ โ
โ SYN โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบโ
โ [Firewall]
โ ... silence ... X
โ (timeout after 1-2 seconds) โ
โ โ
Result: PORT IS FILTERED (probably firewalled)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ALTERNATIVE: ICMP Unreachable
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Scanner Target
โ โ
โ SYN โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบโ
โ [Firewall]
โ ICMP Type 3 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ "Destination port unreachable" โ
โ โ
Result: PORT IS FILTERED (administratively blocked)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ

Types of Port Scans
Your toolkit will implement multiple scan types, each with different tradeoffs:
| Scan Type | How It Works | Advantages | Disadvantages |
|---|---|---|---|
| TCP Connect | Complete 3-way handshake | No root required, reliable | Logged by target, slow |
| SYN Scan | Send SYN, analyze response, send RST | Faster, stealthier (no logging) | Requires root/raw sockets |
| UDP Scan | Send UDP packets, wait for response | Finds UDP services (DNS, SNMP) | Very slow, unreliable |
| ACK Scan | Send ACK, analyze RST response | Detects firewall rules | Canโt determine if port is open |
DNS: The Reconnaissance Goldmine
DNS (Domain Name System) is often overlooked as an attack surface, but it contains a wealth of information:
DNS RECORD TYPES FOR RECONNAISSANCE
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
A Record: Maps domain to IPv4 address
example.com โ 93.184.216.34
Use: Discover IP addresses of hosts
AAAA Record: Maps domain to IPv6 address
example.com โ 2606:2800:220:1:248:1893:25c8:1946
Use: Often overlooked, may have different security
MX Record: Mail server for domain
example.com โ mail.example.com (priority 10)
Use: Identify mail servers (common phishing targets)
NS Record: Authoritative nameservers
example.com โ ns1.example.com, ns2.example.com
Use: Identify DNS infrastructure
TXT Record: Arbitrary text (SPF, DKIM, verification)
example.com โ "v=spf1 include:_spf.google.com ~all"
Use: Reveals email infrastructure, third-party services
CNAME Record: Alias pointing to another domain
www.example.com โ cdn.cloudflare.net
Use: Identifies CDNs, cloud providers
PTR Record: Reverse DNS (IP to hostname)
93.184.216.34 โ example.com
Use: Discover internal naming conventions
Zone Transfers: When DNS Gets Really Chatty
A zone transfer (AXFR) is meant for DNS server replication, but misconfigured servers allow anyone to request the entire zone:
ZONE TRANSFER ATTACK
โโโโโโโโโโโโโโโโโโโโ
Normal Query (one record at a time):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Attacker: "What's the IP for www.target.com?" โ
โ DNS: "93.184.216.34" โ
โ โ
โ Attacker: "What's the IP for mail.target.com?" โ
โ DNS: "93.184.216.35" โ
โ โ
โ (Must guess each subdomain individually) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Zone Transfer (get everything at once):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Attacker: "Give me all records for target.com" โ
โ DNS: "Here's 500 records: โ
โ - www.target.com โ 93.184.216.34 โ
โ - mail.target.com โ 93.184.216.35 โ
โ - admin.target.com โ 93.184.216.36 โ
โ - dev-internal.target.com โ 10.0.0.50 โ โ Internal!
โ - jenkins.target.com โ 10.0.0.51 โ โ CI/CD server!
โ - vpn.target.com โ 203.0.113.10 โ
โ - ..." โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Why this is devastating:
- Reveals ALL subdomains (including internal systems)
- Exposes infrastructure layout
- Identifies high-value targets (admin panels, CI/CD)
- No rate limiting or detection
Service Fingerprinting: Whatโs Actually Running?
Knowing a port is open isnโt enoughโyou need to know what service is running and what version:
BANNER GRABBING
โโโโโโโโโโโโโโโ
Connect to port 22:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Server Response: โ
โ SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5 โ
โ โ
โ Information Revealed: โ
โ - Protocol: SSH version 2 โ
โ - Software: OpenSSH 8.2p1 โ
โ - OS: Ubuntu (specific patch level) โ
โ โ
โ Now you can search: "OpenSSH 8.2p1 vulnerabilities"โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Connect to port 80:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Send: "GET / HTTP/1.0\r\n\r\n" โ
โ โ
โ Response Headers: โ
โ HTTP/1.1 200 OK โ
โ Server: Apache/2.4.41 (Ubuntu) โ
โ X-Powered-By: PHP/7.4.3 โ
โ โ
โ Information Revealed: โ
โ - Web Server: Apache 2.4.41 โ
โ - Language: PHP 7.4.3 โ
โ - OS: Ubuntu โ
โ โ
โ Attack vector: Look for Apache 2.4.41 CVEs โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Project Specification
What Youโre Building
A command-line toolkit with three main components:
network-recon-toolkit/
โโโ scanner.py # Port scanner (TCP connect + SYN scan)
โโโ dns_enum.py # DNS enumeration and zone transfer
โโโ fingerprint.py # Service fingerprinting and banner grabbing
โโโ output/ # Scan results (JSON, CSV, HTML)
โโโ wordlists/ # Subdomain wordlists
โ โโโ subdomains.txt
โโโ requirements.txt # Dependencies
โโโ README.md # Usage documentation
Functional Requirements
1. Port Scanner (scanner.py)
Must implement:
- TCP Connect scan (no root required)
- Scan single port, port range, or common ports list
- Configurable timeout per connection
- Multi-threaded scanning (100+ connections concurrent)
- Output: JSON with host, port, state, response time
Should implement:
- SYN scan (requires root/raw sockets)
- UDP scan for common ports (DNS, SNMP, NTP)
- Service version detection via banner grabbing
- Rate limiting to avoid detection
Example usage:
# Scan single host, common ports
python scanner.py 192.168.1.1
# Scan port range with increased threads
python scanner.py 192.168.1.1 -p 1-1000 --threads 200
# Scan network range
python scanner.py 192.168.1.0/24 -p 22,80,443
# SYN scan (requires sudo)
sudo python scanner.py 192.168.1.1 --syn
2. DNS Enumerator (dns_enum.py)
Must implement:
- Query A, AAAA, MX, NS, TXT, CNAME records
- Subdomain enumeration via wordlist
- Attempt zone transfer (AXFR)
- Reverse DNS lookups
Should implement:
- Multi-threaded subdomain bruteforcing
- Wildcard detection (*.domain.com)
- Integration with Certificate Transparency logs
- Output to structured format
Example usage:
# Basic enumeration
python dns_enum.py example.com
# Subdomain bruteforce
python dns_enum.py example.com --wordlist wordlists/subdomains.txt
# Attempt zone transfer
python dns_enum.py example.com --zone-transfer
3. Service Fingerprinter (fingerprint.py)
Must implement:
- HTTP/HTTPS banner grabbing
- SSH version detection
- FTP banner grabbing
- Generic TCP banner grabbing
- TLS certificate extraction
Should implement:
- Service-specific probes (MySQL, PostgreSQL, Redis)
- Custom fingerprint database
- Version-to-CVE mapping suggestions
Example usage:
# Fingerprint all services on host
python fingerprint.py 192.168.1.1
# Fingerprint specific ports
python fingerprint.py 192.168.1.1 -p 22,80,443
# Deep fingerprinting (all probes)
python fingerprint.py 192.168.1.1 --deep
Non-Functional Requirements
- Performance: Scan 1000 ports in under 30 seconds
- Reliability: Handle network errors gracefully, never crash
- Accuracy: Match Nmap results for same targets
- Documentation: Clear help messages, README with examples
- Ethics: Include legal disclaimer, respect robots.txt
Solution Architecture
Component Design
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RECONNAISSANCE TOOLKIT โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ Port Scanner โ โ DNS Enumer. โ โ Fingerprinter โ
โโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโค
โ - TCP Connect โ โ - Record โ โ - Banner Grab โ
โ - SYN Scan โ โ Queries โ โ - TLS Extract โ
โ - UDP Scan โ โ - Subdomain โ โ - Service โ
โ - Threading โ โ Bruteforce โ โ Probes โ
โโโโโโโโโฌโโโโโโโโ โ - Zone AXFR โ โโโโโโโโโฌโโโโโโโโ
โ โโโโโโโโโฌโโโโโโโโ โ
โ โ โ
โโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโ
โ Output Engine โ
โโโโโโโโโโโโโโโโโค
โ - JSON Export โ
โ - CSV Export โ
โ - HTML Report โ
โ - Console โ
โโโโโโโโโโโโโโโโโ
Key Data Structures
# Port scan result
@dataclass
class PortResult:
ip: str
port: int
state: Literal["open", "closed", "filtered"]
service: Optional[str] = None
banner: Optional[str] = None
response_time_ms: Optional[float] = None
# DNS enumeration result
@dataclass
class DNSResult:
domain: str
record_type: str # A, AAAA, MX, NS, TXT, CNAME
value: str
ttl: int
# Service fingerprint
@dataclass
class ServiceInfo:
ip: str
port: int
protocol: str # tcp, udp
service_name: str # ssh, http, mysql
version: Optional[str] = None
os_guess: Optional[str] = None
cves: List[str] = field(default_factory=list)
Threading Model for Port Scanning
PRODUCER-CONSUMER PATTERN
โโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโ
โ Target Queue โ
โ (ports to โ
โ scan) โ
โโโโโโโโฌโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ Worker 1 โ โ Worker 2 โ โ Worker N โ
โ โ โ โ โ โ
โ - Get port โ โ - Get port โ โ - Get port โ
โ - Attempt โ โ - Attempt โ โ - Attempt โ
โ connect โ โ connect โ โ connect โ
โ - Report โ โ - Report โ โ - Report โ
โ result โ โ result โ โ result โ
โโโโโโโโโฌโโโโโโโโ โโโโโโโโโฌโโโโโโโโ โโโโโโโโโฌโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโ
โ Result Queue โ
โ (completed โ
โ scans) โ
โโโโโโโโโโโโโโโโ
Phased Implementation Guide
Phase 1: Basic TCP Connect Scanner (Days 1-2)
Goal: Scan a single port on a single host
Implementation steps:
- Create a function that attempts to connect to a TCP port:
def scan_port(ip: str, port: int, timeout: float = 1.0) -> PortResult: """ Attempt TCP connection to ip:port Returns: PortResult with state='open' if connection succeeds PortResult with state='closed' if connection refused PortResult with state='filtered' if timeout """ # Use socket.socket() with SO_REUSEADDR # Set timeout with socket.settimeout() # Try connect_ex() for non-blocking connect # Map return codes to states: # 0 = open # 111 (ECONNREFUSED) = closed # 110 (ETIMEDOUT) = filtered - Add CLI argument parsing:
- Target IP/hostname
- Port number or range
- Timeout value
- Test against your local machine:
- Start a local HTTP server:
python -m http.server 8080 - Scan port 8080 (should be open)
- Scan port 8081 (should be closed)
- Start a local HTTP server:
Verification: Can you correctly identify an open port on localhost?
Phase 2: Multi-Threaded Scanning (Days 2-3)
Goal: Scan 1000 ports in under 30 seconds
Implementation steps:
- Use
concurrent.futures.ThreadPoolExecutor: ```python from concurrent.futures import ThreadPoolExecutor, as_completed
def scan_ports(ip: str, ports: List[int], threads: int = 100) -> List[PortResult]: results = [] with ThreadPoolExecutor(max_workers=threads) as executor: futures = { executor.submit(scan_port, ip, port): port for port in ports } for future in as_completed(futures): results.append(future.result()) return results
2. Add progress indicator (tqdm or simple counter)
3. Implement rate limiting to avoid overwhelming target
**Verification**: Scan ports 1-1000 on a target in under 30 seconds
### Phase 3: DNS Enumeration (Days 3-4)
**Goal**: Enumerate all DNS record types and attempt zone transfer
**Implementation steps**:
1. Use the `dnspython` library for queries:
```python
import dns.resolver
import dns.zone
import dns.query
def query_records(domain: str, record_type: str) -> List[DNSResult]:
"""Query specific DNS record type"""
resolver = dns.resolver.Resolver()
try:
answers = resolver.resolve(domain, record_type)
return [DNSResult(domain, record_type, str(rdata), answers.ttl)
for rdata in answers]
except dns.resolver.NXDOMAIN:
return [] # Domain doesn't exist
except dns.resolver.NoAnswer:
return [] # No records of this type
- Implement subdomain enumeration:
- Read subdomain wordlist
- Query A record for each:
subdomain.domain.com - Track which ones resolve
- Implement zone transfer attempt:
def attempt_zone_transfer(domain: str) -> Optional[List[DNSResult]]: """Attempt AXFR zone transfer""" # Get NS records for domain # For each NS, attempt: dns.query.xfr(ns, domain) # If successful, extract all records
Verification: Enumerate google.com and see A, MX, NS, TXT records
Phase 4: Service Fingerprinting (Days 4-5)
Goal: Identify services running on open ports
Implementation steps:
- Implement banner grabbing:
def grab_banner(ip: str, port: int, timeout: float = 2.0) -> Optional[str]: """Connect and read initial response""" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) try: sock.connect((ip, port)) # Some services send banner immediately (SSH, FTP) # Others need us to send something first (HTTP) banner = sock.recv(1024) return banner.decode('utf-8', errors='ignore') except: return None finally: sock.close() - Add service-specific probes:
- HTTP: Send
GET / HTTP/1.0\r\n\r\n - MySQL: Parse greeting packet
- TLS: Extract certificate info
- HTTP: Send
- Build a simple service detection database:
SERVICE_SIGNATURES = { "ssh": re.compile(r"SSH-[\d.]+-"), "http": re.compile(r"HTTP/[\d.]+"), "ftp": re.compile(r"220.*FTP"), "smtp": re.compile(r"220.*SMTP"), }
Verification: Correctly identify SSH, HTTP, and MySQL on test servers
Phase 5: SYN Scanning with Scapy (Days 5-6)
Goal: Implement stealthy SYN scanning (requires root)
Implementation steps:
-
Install Scapy:
pip install scapy -
Implement SYN scan: ```python from scapy.all import IP, TCP, sr1, conf
def syn_scan(ip: str, port: int) -> str: โโโ SYN scan using raw packets Requires root privileges โโโ conf.verb = 0 # Disable Scapy output
# Craft SYN packet
syn = IP(dst=ip)/TCP(dport=port, flags='S')
# Send and wait for response
response = sr1(syn, timeout=1)
if response is None:
return "filtered"
elif response.haslayer(TCP):
if response[TCP].flags == 0x12: # SYN-ACK
# Send RST to close (stealth)
rst = IP(dst=ip)/TCP(dport=port, flags='R')
send(rst, verbose=0)
return "open"
elif response[TCP].flags == 0x14: # RST
return "closed"
return "filtered" ```
- Add sudo detection and privilege check
Verification: Compare SYN scan results to TCP connect results
Phase 6: Output and Reporting (Days 6-7)
Goal: Generate professional reports
Implementation steps:
- JSON output:
def export_json(results: List[PortResult], filepath: str): data = [asdict(r) for r in results] with open(filepath, 'w') as f: json.dump(data, f, indent=2) -
CSV output for spreadsheet analysis
- HTML report with styling: ```html
Network Reconnaissance Report
Target: {target}
Scan Time: {timestamp}
Open Ports
| Port | Service | Banner |
|---|
4. Compare output to Nmap format
**Verification**: Generate all three output formats for a scan
---
## Testing Strategy
### Unit Tests
```python
# test_scanner.py
import pytest
from scanner import scan_port, parse_port_range
def test_parse_port_range():
assert parse_port_range("80") == [80]
assert parse_port_range("1-5") == [1, 2, 3, 4, 5]
assert parse_port_range("22,80,443") == [22, 80, 443]
def test_scan_localhost_open_port():
# Start a server on port 9999 before test
result = scan_port("127.0.0.1", 9999)
assert result.state == "open"
def test_scan_localhost_closed_port():
result = scan_port("127.0.0.1", 9998) # Nothing running
assert result.state == "closed"
Integration Tests
- Against known targets:
- Scan
scanme.nmap.org(Nmap provides this for testing) - Compare results to Nmap output
- Verify same open ports detected
- Scan
- DNS tests:
- Enumerate
google.com(should find A, MX, NS records) - Test zone transfer against intentionally vulnerable server
- Enumerate
- Fingerprinting tests:
- Correctly identify Apache vs Nginx
- Correctly identify OpenSSH version
Performance Tests
import time
def test_scan_performance():
start = time.time()
results = scan_ports("192.168.1.1", range(1, 1001), threads=100)
elapsed = time.time() - start
assert elapsed < 30, f"Scan took {elapsed}s, should be under 30s"
Common Pitfalls and Debugging
1. โMy scanner is too slowโ
Problem: Scanning takes minutes instead of seconds
Debug steps:
- Check thread count (increase to 100-200)
- Check timeout (decrease to 0.5-1s)
- Look for blocking operations in main thread
- Use
cProfileto find bottleneck
Solution: Use ThreadPoolExecutor properly, donโt wait sequentially
2. โI get โPermission deniedโ for SYN scanโ
Problem: Raw socket access requires root
Debug steps:
- Run with
sudo - Check if Scapy is installed correctly
- Verify raw socket capability
Solution: Either use sudo or fall back to TCP connect scan
3. โDNS zone transfer always failsโ
Problem: Most servers have zone transfers disabled
This is expected! Zone transfers are a security misconfiguration. For testing:
- Use intentionally vulnerable DNS servers (set up your own)
- Zonetransfer.me is a test server that allows AXFR
4. โBanner grabbing returns emptyโ
Problem: Some services need a prompt before responding
Debug steps:
- Check if connection succeeds
- Try sending a probe (like HTTP GET)
- Increase timeout
- Handle binary protocols (MySQL handshake)
Solution: Implement service-specific probes
5. โResults donโt match Nmapโ
Problem: Different scan techniques yield different results
Debug steps:
- Compare exact scan types (Nmap -sT for TCP connect)
- Check timing/timeout differences
- Verify target hasnโt changed between scans
- Consider rate limiting differences
Extensions and Challenges
Beginner Extensions
- Add color output: Green for open, red for closed
- Progress bar: Show scan progress with tqdm
- Save/resume: Allow resuming interrupted scans
Intermediate Extensions
- OS Detection: Analyze TCP/IP stack quirks to guess OS
- Service probes: Add MySQL, PostgreSQL, Redis detection
- Rate limiting: Avoid triggering IDS/IPS
Advanced Extensions
- Evasion techniques: Fragmented packets, timing variations
- IPv6 support: Scan IPv6 addresses
- Web interface: Flask dashboard for results
- Parallel host scanning: Scan entire subnets efficiently
Real-World Connections
How Nmap Does It
Your scanner is a simplified Nmap. The real Nmap:
- Uses a sophisticated timing engine
- Has 600+ service probes
- Includes 600+ NSE scripts
- Does OS fingerprinting via TCP/IP stack analysis
After this project, read the Nmap source code to see professional implementation.
Shodan and Censys
Commercial services like Shodan scan the entire internet continuously. They use:
- Distributed scanning nodes
- Massive parallelization
- Historical data tracking
Your skills translate to understanding how these services work.
Bug Bounty Applications
Many bug bounties start with reconnaissance:
- Subdomain enumeration reveals forgotten assets
- Open ports expose services you didnโt know existed
- Banner grabbing identifies vulnerable versions
Self-Assessment Checklist
Before considering this project complete, verify:
Core Functionality
- TCP connect scan correctly identifies open/closed/filtered ports
- Multi-threaded scanning completes 1000 ports in < 30 seconds
- DNS enumeration returns A, MX, NS, TXT records
- Zone transfer attempt works (even if server refuses)
- Banner grabbing returns version strings for SSH, HTTP
Code Quality
- CLI has โhelp with clear usage
- Errors are handled gracefully (no crashes)
- Output is structured (JSON export works)
- Code is documented with docstrings
Understanding
- Can explain TCP three-way handshake whiteboard-style
- Can explain difference between SYN and connect scans
- Understand why zone transfers are security issues
- Know which scan types require root and why
Comparison
- Results match Nmap for same target/options
- Performance is comparable for connect scans
- Output is parseable by other tools
Resources
Primary Reading
- โTCP/IP Illustrated, Volume 1โ by W. Richard Stevens - Chapters 17-18 (TCP Connection)
- โBlack Hat Pythonโ by Justin Seitz - Chapter 3 (Network Scanning)
- โThe Linux Programming Interfaceโ by Michael Kerrisk - Chapters 56-61 (Sockets)
Online Resources
- Nmap Reference Guide - Understand the reference implementation
- Scapy Documentation - Raw packet manipulation
- DNS RFC 1035 - DNS protocol specification
Practice Targets
scanme.nmap.org- Nmap provides this for testing- Your own VMs - Set up services to scan
- TryHackMe/HTB - Use recon tools on CTF challenges
This project is part of the Ethical Hacking & Penetration Testing learning path.