An automated reconnaissance tool for DNS enumeration, subdomain discovery, port scanning, banner grabbing, and JSON report generation — built for pentesting workflows.
This command-line reconnaissance tool automates the initial information gathering phase of a penetration test. It combines multiple recon techniques into a single modular Python script that outputs structured JSON reports.
Built to speed up the recon phase during CTFs and pentest labs, combining DNS lookups, subdomain brute-forcing, port scanning, and service banner grabbing in one tool.
#!/usr/bin/env python3
"""
recon.py — Automated Reconnaissance Tool
Author: Abderraouf Atsamnia (github.com/raoufats26)
"""
import socket
import json
import dns.resolver
import concurrent.futures
from datetime import datetime
class ReconTool:
def __init__(self, target: str):
self.target = target
self.results = {
"target": target,
"timestamp": datetime.now().isoformat(),
"dns_records": {},
"open_ports": [],
"banners": {}
}
def dns_enum(self):
"""Enumerate DNS records for target."""
record_types = ['A', 'MX', 'NS', 'TXT', 'AAAA']
for rtype in record_types:
try:
answers = dns.resolver.resolve(self.target, rtype)
self.results["dns_records"][rtype] = [r.to_text() for r in answers]
print(f"[+] {rtype}: {[r.to_text() for r in answers]}")
except Exception:
pass
def port_scan(self, ports=range(1, 1025), timeout=0.5):
"""Threaded TCP port scanner."""
open_ports = []
def check_port(port):
try:
with socket.create_connection((self.target, port), timeout):
return port
except (socket.timeout, ConnectionRefusedError, OSError):
return None
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as ex:
futures = {ex.submit(check_port, p): p for p in ports}
for future in concurrent.futures.as_completed(futures):
result = future.result()
if result:
open_ports.append(result)
print(f"[+] Port {result}/tcp OPEN")
self.results["open_ports"] = sorted(open_ports)
def grab_banner(self, port: int) -> str:
"""Grab service banner from open port."""
try:
with socket.create_connection((self.target, port), 2) as s:
s.send(b"HEAD / HTTP/1.0\r\n\r\n")
return s.recv(1024).decode("utf-8", errors="ignore").strip()
except Exception:
return ""
def export_report(self, filename: str = None):
"""Export results as JSON report."""
filename = filename or f"recon_{self.target}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(filename, 'w') as f:
json.dump(self.results, f, indent=2)
print(f"\n[✓] Report saved: {filename}")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Recon Tool by raoufats26")
parser.add_argument("target", help="Target domain or IP")
parser.add_argument("--ports", default="1-1024", help="Port range (e.g. 1-1024)")
args = parser.parse_args()
tool = ReconTool(args.target)
print(f"[*] Starting recon on {args.target}\n")
tool.dns_enum()
tool.port_scan()
tool.export_report()
# Basic scan
python3 recon.py target.com
# Specify port range
python3 recon.py target.com --ports 1-65535
# Sample output
[*] Starting recon on target.com
[+] A: ['93.184.216.34']
[+] MX: ['mail.target.com.']
[+] NS: ['ns1.target.com.', 'ns2.target.com.']
[+] Port 22/tcp OPEN
[+] Port 80/tcp OPEN
[+] Port 443/tcp OPEN
[+] Port 8080/tcp OPEN
[✓] Report saved: recon_target.com_20260215_143022.json