Press enter or click to view image in full size
Stop doing recon manually. Let your machine find bugs while you sleep.
I used to spend 4–5 hours manually doing recon on every target.
Subdomain enumeration. Port scanning. Vulnerability checking. Directory bruteforcing. It was repetitive, slow, and exhausting.
Then I automated it.
Now I run one script before bed and wake up to a report of potential vulnerabilities. This article shows you exactly how I built that system — and how you can copy it for your own bug bounty workflow.
Recon (reconnaissance) is the first step in bug bounty hunting. Before you can find vulnerabilities, you need to map the target:
Doing this manually for every target is a waste of your most valuable resource time.
Automation solves this. You define the logic once, and the machine runs it thousands of times faster than you ever could.
Subfinder Subdomain discovery
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
Httpx HTTP probing (live hosts)
go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest
Nuclei Vulnerability scanning
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
Nmap Port scanning
sudo apt install nmap
Python 3 Glue everything together
Join Medium for free to get updates from this writer.
Pre-installed on Kali Linux
Press enter or click to view image in full size
All tools are free and open source. Install Go first if you haven’t:
sudo apt install golang-gHere is the full Python script. Save it as recon.py:
import subprocess
import os
import sys
import datetimedef banner():
print("""
██████╗ ███████╗ ██████╗ ██████╗ ███╗ ██╗
██╔══██╗██╔════╝██╔════╝██╔═══██╗████╗ ██║
██████╔╝█████╗ ██║ ██║ ██║██╔██╗ ██║
██╔══██╗██╔══╝ ██║ ██║ ██║██║╚██╗██║
██║ ██║███████╗╚██████╗╚██████╔╝██║ ╚████║
╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝
Bug Bounty Recon Automation - by @HackerMD
""")
def create_output_dir(domain):
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
output_dir = f"recon_{domain}_{timestamp}"
os.makedirs(output_dir, exist_ok=True)
return output_dir
def run_subfinder(domain, output_dir):
print(f"\n[*] Running Subfinder on {domain}...")
output_file = f"{output_dir}/subdomains.txt"
cmd = f"subfinder -d {domain} -silent -o {output_file}"
subprocess.run(cmd, shell=True)
print(f"[+] Subdomains saved to {output_file}")
return output_file
def run_httpx(subdomains_file, output_dir):
print("\n[*] Probing for live hosts with Httpx...")
output_file = f"{output_dir}/live_hosts.txt"
cmd = f"httpx -l {subdomains_file} -silent -o {output_file} -status-code -title -tech-detect"
subprocess.run(cmd, shell=True)
print(f"[+] Live hosts saved to {output_file}")
return output_file
def run_nuclei(live_hosts_file, output_dir):
print("\n[*] Running Nuclei vulnerability scan...")
output_file = f"{output_dir}/nuclei_results.txt"
cmd = f"nuclei -l {live_hosts_file} -severity critical,high,medium -o {output_file} -silent"
subprocess.run(cmd, shell=True)
print(f"[+] Nuclei results saved to {output_file}")
return output_file
def run_nmap(domain, output_dir):
print(f"\n[*] Running Nmap port scan on {domain}...")
output_file = f"{output_dir}/nmap_results.txt"
cmd = f"nmap -sV --top-ports 1000 {domain} -oN {output_file}"
subprocess.run(cmd, shell=True)
print(f"[+] Nmap results saved to {output_file}")
def generate_report(domain, output_dir):
print("\n[*] Generating final report...")
report_file = f"{output_dir}/REPORT_{domain}.txt"
with open(report_file, "w") as report:
report.write(f"=== BUG BOUNTY RECON REPORT ===\n")
report.write(f"Target: {domain}\n")
report.write(f"Date: {datetime.datetime.now()}\n")
report.write(f"Tool: @HackerMD Recon Automation\n\n")
for filename in os.listdir(output_dir):
filepath = os.path.join(output_dir, filename)
if filename.endswith(".txt") and filename != f"REPORT_{domain}.txt":
report.write(f"\n{'='*50}\n")
report.write(f"[{filename}]\n")
report.write(f"{'='*50}\n")
with open(filepath, "r") as f:
report.write(f.read())
print(f"\n[✓] Report generated: {report_file}")
print(f"[✓] All files saved in: {output_dir}/\n")
def main():
banner()
if len(sys.argv) != 2:
print("Usage: python3 recon.py <target-domain>")
print("Example: python3 recon.py example.com")
sys.exit(1)
domain = sys.argv[1]
output_dir = create_output_dir(domain)
print(f"[+] Target: {domain}")
print(f"[+] Output Directory: {output_dir}")
subdomains_file = run_subfinder(domain, output_dir)
live_hosts_file = run_httpx(subdomains_file, output_dir)
run_nuclei(live_hosts_file, output_dir)
run_nmap(domain, output_dir)
generate_report(domain, output_dir)
if __name__ == "__main__":
main()
# Save the script
nano recon.py
# Make it executable
chmod +x recon.py
# Run against a target (only on programs you have permission for!)
python3 recon.py targetdomain.comOutput you’ll get:
recon_targetdomain.com_20260225_210000/
├── subdomains.txt ← All discovered subdomains
├── live_hosts.txt ← Only live/active hosts
├── nuclei_results.txt ← Vulnerability scan results
├── nmap_results.txt ← Open ports & services
└── REPORT_targetdomain.txt ← Full combined reportSubfinder queries over 50 passive DNS sources simultaneously — Shodan, VirusTotal, CertSpotter, and more. A target like example.com might have 500+ subdomains that are invisible to normal browsing. Many of these subdomains have older, forgotten, vulnerable services running on them — these are goldmines for bug hunters.
Out of 500 subdomains, maybe only 200 are actually live. Httpx filters these out quickly, shows you their HTTP status codes, page titles, and what technologies they’re running (Apache, Nginx, WordPress, etc.). Tech detection alone can tell you which exploits to try.
This is where the magic happens. Nuclei has 9,000+ vulnerability templates maintained by the ProjectDiscovery team. It checks for:
One Nuclei scan can surface findings that would take hours to find manually.
Port scanning reveals services running outside port 80/443. An FTP server on port 21, a Redis instance on 6379, or an exposed Elasticsearch on 9200 — these are all potential critical findings.
Want to find even more attack surface? Add historical URL discovery:
pip install waybackpyAdd this function to the script:
def run_wayback(domain, output_dir):
print(f"\n[*] Fetching historical URLs from Wayback Machine...")
output_file = f"{output_dir}/wayback_urls.txt"
cmd = f"echo {domain} | waybackurls > {output_file}"
subprocess.run(cmd, shell=True)
print(f"[+] Historical URLs saved to {output_file}")Historical URLs often reveal forgotten endpoints — old API versions, backup pages, internal paths — that developers forgot to secure.
Before you run this on any target:
-rate-limit 100 to Nuclei to avoid overwhelming serversRunning unauthorized scans is illegal. Stick to your authorized scope — always.
Using this exact automation pipeline, I have found:
Not every scan returns critical findings — but consistency pays off. Run this against 10 targets and you will find something reportable.
The automation finds the lead. You close the deal with a good report.
Manual recon is dead for serious bug hunters. The hunters who are consistently earning are the ones who built systems that work while they sleep.
This script is your starting point. Customize it, add more tools, improve the report format, add Slack/email notifications for critical findings.
The best recon pipeline is the one you build yourself — because you understand every line of it.
Now go automate. 🐛
I’m @HackerMD — a cybersecurity researcher and bug bounty hunter from India. Follow me for more practical security content, real writeups, and automation scripts.
#BugBounty #Hacking #Cybersecurity #Hacking #Infosec