-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathport_scanner.py
More file actions
89 lines (76 loc) · 3.43 KB
/
Copy pathport_scanner.py
File metadata and controls
89 lines (76 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import socket
import ipaddress
import argparse
import os
import time
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor
# Create reports directory if it does not exist
REPORT_DIR = "scan_reports"
os.makedirs(REPORT_DIR, exist_ok=True)
# Generate a timestamped report filename
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
report_filename = os.path.join(REPORT_DIR, f"scan_report_{timestamp}.txt")
# Open report file
report_file = open(report_filename, "w")
# Write both to terminal and to file
def log_result(message):
print(message)
report_file.write(message + "\n")
# Scan one port
def scan_port(target_ip, port, timeout):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as scanner:
scanner.settimeout(timeout)
result = scanner.connect_ex((target_ip, port))
if result == 0:
try:
scanner.sendall(b"Hello\r\n")
banner = scanner.recv(1024).decode(errors="ignore").strip()
except Exception:
banner = "No banner retrieved"
log_result(f"Port {port} is OPEN | Banner: {banner}")
except Exception as e:
log_result(f"Error scanning port {port} on {target_ip}: {e}")
# Process single IP or hostname
def process_single_target(target, start_port, end_port, timeout, threads):
try:
target_ip = socket.gethostbyname(target)
except socket.gaierror:
log_result(f"Could not resolve {target}")
return
log_result(f"\nScanning target {target} [{target_ip}] from port {start_port} to {end_port}...")
log_result(f"Using timeout = {timeout} seconds | Threads = {threads}\n")
with ThreadPoolExecutor(max_workers=threads) as executor:
for port in range(start_port, end_port + 1):
executor.submit(scan_port, target_ip, port, timeout)
# Process subnet
def process_subnet(subnet, start_port, end_port, timeout, threads):
try:
network = ipaddress.ip_network(subnet, strict=False)
except ValueError:
log_result(f"Invalid target or subnet: '{subnet}' does not appear to be an IPv4 or IPv6 network")
return
for ip in network.hosts():
log_result(f"\nScanning host {ip} from port {start_port} to {end_port}...")
with ThreadPoolExecutor(max_workers=threads) as executor:
for port in range(start_port, end_port + 1):
executor.submit(scan_port, str(ip), port, timeout)
# Parse CLI arguments
parser = argparse.ArgumentParser(description="Multi-target Python Port Scanner with Banner Grabbing")
parser.add_argument("target", help="Target IP address, hostname, or subnet (e.g. 192.168.1.1, scanme.nmap.org, 192.168.1.0/24)")
parser.add_argument("start_port", type=int, help="Start port number")
parser.add_argument("end_port", type=int, help="End port number")
parser.add_argument("--timeout", type=float, default=1.0, help="Timeout in seconds (default: 1)")
parser.add_argument("--threads", type=int, default=100, help="Number of threads (default: 100)")
args = parser.parse_args()
# Main logic
try:
# Check if it's a subnet
if "/" in args.target:
process_subnet(args.target, args.start_port, args.end_port, args.timeout, args.threads)
else:
process_single_target(args.target, args.start_port, args.end_port, args.timeout, args.threads)
finally:
report_file.close()
log_result(f"\nScan complete. Report saved to {report_filename}")