1+ #! /usr/bin/env bash
2+ # ======================================================
3+ # Automated Scan Script for bug bounty targets
4+ # ======================================================
5+ # Author: Naveen Jagadeesan(thevillagehacker)
6+ # Description: Runs reconnaissance against the targets
7+ # ======================================================
8+
9+ # Color codes for output
10+ RED=' \033[0;31m'
11+ GREEN=' \033[0;32m'
12+ YELLOW=' \033[1;33m'
13+ NC=' \033[0m' # No Color
14+
15+ # Logging functions
16+ log () {
17+ echo -e " ${GREEN} [+]${NC} $1 "
18+ }
19+
20+ error () {
21+ echo -e " ${RED} [-]${NC} $1 "
22+ exit 1
23+ }
24+
25+ # Check if required tool is installed
26+ check_tool () {
27+ if ! command -v " $1 " & > /dev/null; then
28+ error " $1 is not installed. Please install it first."
29+ fi
30+ }
31+
32+ # Function to setup target directory
33+ setup_target () {
34+ local target_id=" $1 "
35+ local scope_path=" $ppath /scope/$target_id "
36+
37+ # Create scope and target directories
38+ mkdir -p " $scope_path "
39+
40+ # Ask for roots content (send prompts to stderr so they don't get captured by command substitution)
41+ echo " " >&2
42+ echo -e " ${YELLOW} [*]${NC} Enter the target roots (domains/IPs) for $target_id " >&2
43+ echo -e " ${YELLOW} [*]${NC} You can enter multiple roots, one per line." >&2
44+ echo -e " ${YELLOW} [*]${NC} Press Ctrl+D (or Ctrl+Z on Windows) when done:" >&2
45+ echo " ---" >&2
46+
47+ # Read user input and write to roots.txt
48+ cat > " $scope_path /roots.txt"
49+
50+ echo " ---" >&2
51+ echo " " >&2
52+ echo -e " ${GREEN} [+]${NC} Target directory created at: $scope_path " >&2
53+ echo -e " ${GREEN} [+]${NC} Roots file saved at: $scope_path /roots.txt" >&2
54+ echo " " >&2
55+
56+ # Only echo the target_id to stdout so it gets captured by command substitution
57+ echo " $target_id "
58+ }
59+
60+ # Set vars
61+ ppath=" $( pwd) "
62+ lists_path=" $ppath /lists"
63+
64+ # Usage and disclaimer
65+ if [ " $1 " == " -h" ]; then
66+ echo " Usage: ./scan.sh [id]"
67+ echo " "
68+ echo " This script performs a scan for a given target ID."
69+ echo " "
70+ echo " Options:"
71+ echo " [id] - Optional. If provided, uses existing scope/[id]/roots.txt"
72+ echo " -h - Show this help message"
73+ echo " "
74+ echo " If no ID is provided, the script will prompt you to:"
75+ echo " 1. Enter a target name (will create scope/[target_name]/ directory)"
76+ echo " 2. Enter roots (domains/IPs to scan, one per line)"
77+ echo " "
78+ echo " Directory structure:"
79+ echo " ├── scan.sh"
80+ echo " ├── scans"
81+ echo " └── scope"
82+ echo " └── [target_name]"
83+ echo " └── roots.txt"
84+ echo " "
85+ echo " Examples:"
86+ echo " ./scan.sh example # Use existing scope/example/roots.txt"
87+ echo " ./scan.sh # Interactive mode - create new target"
88+ exit 0
89+ fi
90+
91+ # Prompt for target if not provided as argument
92+ if [ -z " $1 " ]; then
93+ echo -e " ${YELLOW} [-]${NC} No target ID provided"
94+ read -p " Enter target name: " id
95+ if [ -z " $id " ]; then
96+ error " Target name cannot be empty"
97+ fi
98+ id=$( setup_target " $id " )
99+ else
100+ id=" $1 "
101+ fi
102+
103+ scope_path=" $ppath /scope/$id "
104+
105+ timestamp=" $( date +%s) "
106+ scan_path=" $ppath /scans/$id -$timestamp "
107+
108+ # Check required tools
109+ log " Checking required tools..."
110+ check_tool " haktrails"
111+ check_tool " subfinder"
112+ check_tool " alterx"
113+ check_tool " puredns"
114+ check_tool " dnsx"
115+ check_tool " nmap"
116+ check_tool " httpx"
117+ check_tool " gospider"
118+ check_tool " jq"
119+ check_tool " wget"
120+
121+ # Create necessary directories
122+ log " Creating necessary directories..."
123+ mkdir -p " $lists_path "
124+ mkdir -p " $scan_path "
125+
126+ log " Scan path: $scan_path "
127+
128+ # ## PERFORM SCAN ###
129+ log " Starting scan against roots:"
130+ cat " $scope_path /roots.txt" > " $scan_path /roots.txt"
131+ sleep 2
132+
133+
134+ # DNS Enumeration - Find Subdomains
135+ log " DNS Enumeration: Running haktrails..."
136+ cat " $scan_path /roots.txt" | haktrails subdomains | anew " $scan_path /subs.txt" | wc -l
137+
138+ log " DNS Enumeration: Running subfinder..."
139+ subfinder -d " $( cat " $scan_path /roots.txt" ) " -all -silent | anew " $scan_path /subs.txt" | wc -l
140+
141+ # alterx subdomain wordlist generation
142+ log " Generating subdomain permutations with alterx..."
143+ cat " $scan_path /roots.txt" | alterx -silent | anew " $scan_path /subs.txt" | wc -l
144+
145+ # Download resolver lists (only if they don't exist or are older than 7 days)
146+ download_if_needed () {
147+ local url=" $1 "
148+ local output=" $2 "
149+ if [ ! -f " $output " ] || [ " $( find " $output " -mtime +7 2> /dev/null) " ]; then
150+ log " Downloading $( basename " $output " ) ..."
151+ wget -q --show-progress " $url " -O " $output "
152+ else
153+ log " Using cached $( basename " $output " ) ..."
154+ fi
155+ }
156+
157+ download_if_needed " https://raw.githubusercontent.com/trickest/resolvers/refs/heads/main/resolvers.txt" " $lists_path /resolvers.txt"
158+ download_if_needed " https://raw.githubusercontent.com/trickest/resolvers/refs/heads/main/resolvers-trusted.txt" " $lists_path /resolvers-trusted.txt"
159+ download_if_needed " https://raw.githubusercontent.com/trickest/resolvers/refs/heads/main/resolvers-extended.txt" " $lists_path /resolvers-extended.txt"
160+ download_if_needed " https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/DNS/combined_subdomains.txt" " $lists_path /combined_subdomains.txt"
161+
162+ # Sort and unique resolvers
163+ log " Sorting resolvers..."
164+ cat " $lists_path " /resolvers* .txt | anew > " $lists_path /sorted_resolvers.txt"
165+
166+ # Copy sorted resolvers to puredns config
167+ log " Copying resolvers to puredns config folder..."
168+ mkdir -p " $HOME /.config/puredns"
169+ cp " $lists_path /sorted_resolvers.txt" " $HOME /.config/puredns/resolvers.txt"
170+
171+ # DNS Resolution - Resolve Discovered Subdomains
172+ log " DNS Resolution: Resolving subdomains with puredns..."
173+ puredns resolve " $scan_path /subs.txt" -r " $lists_path /resolvers.txt" --resolvers-trusted " $lists_path /resolvers-trusted.txt" -w " $scan_path /resolved.txt" | wc -l
174+
175+ log " DNS Resolution: Extracting IP addresses with dnsx..."
176+ dnsx -l " $scan_path /resolved.txt" -json -o " $scan_path /dns.json"
177+ log " Extracting IP addresses from $scan_path /dns.json"
178+
179+ # DEBUG: Check if dns.json exists and has content
180+ echo " [DEBUG] Checking dns.json file..." >&2
181+ if [ -f " $scan_path /dns.json" ]; then
182+ file_size=$( wc -c < " $scan_path /dns.json" )
183+ echo " [DEBUG] dns.json exists. File size: $file_size bytes" >&2
184+ echo " [DEBUG] First 500 chars of dns.json:" >&2
185+ head -c 500 " $scan_path /dns.json" >&2
186+ echo " " >&2
187+ else
188+ error " dns.json not found at $scan_path /dns.json"
189+ fi
190+
191+ # DEBUG: Extract with grep and show count
192+ echo " [DEBUG] Running grep to extract IPs..." >&2
193+ grep_count=$( grep -oE ' ([0-9]{1,3}\.){3}[0-9]{1,3}' " $scan_path /dns.json" | wc -l)
194+ echo " [DEBUG] Grep found $grep_count IP matches" >&2
195+
196+ # DEBUG: Show first 10 IPs found by grep
197+ echo " [DEBUG] First 10 IPs found by grep:" >&2
198+ grep -oE ' ([0-9]{1,3}\.){3}[0-9]{1,3}' " $scan_path /dns.json" | head -10 >&2
199+
200+ # Extract, sort, validate, and write to ips.txt
201+ echo " [DEBUG] Sorting and validating IPs..." >&2
202+ grep -oE ' ([0-9]{1,3}\.){3}[0-9]{1,3}' " $scan_path /dns.json" | sort -u > " $scan_path /ips.tmp"
203+ tmp_count=$( wc -l < " $scan_path /ips.tmp" )
204+ echo " [DEBUG] After sort -u: $tmp_count unique IPs" >&2
205+
206+ # Validate octets
207+ awk -F' .' ' ($1<=255 && $2<=255 && $3<=255 && $4<=255){print}' " $scan_path /ips.tmp" > " $scan_path /ips.txt"
208+ final_count=$( wc -l < " $scan_path /ips.txt" )
209+ echo " [DEBUG] After validation: $final_count valid IPs written to ips.txt" >&2
210+ echo " [DEBUG] First 10 IPs in ips.txt:" >&2
211+ head -10 " $scan_path /ips.txt" >&2
212+
213+ rm -f " $scan_path /ips.tmp"
214+ log " Wrote $final_count IPs to $scan_path /ips.txt"
215+
216+ # Port Scanning & HTTP Server Discovery
217+ log " Port Scanning: Running nmap on discovered IPs..."
218+ nmap -iL " $scan_path /ips.txt" --top-ports 3000 -oN " $scan_path /nmap.txt" -v
219+
220+ log " HTTP Discovery: Finding live HTTP services..."
221+ cat " $scan_path /nmap.txt" | dnsx -l " $scan_path /dns.json" --hosts | httpx -json -o " $scan_path /http.json"
222+
223+ cat " $scan_path /http.json" | jq -r ' .url' | sed -e ' s/:80$//' -e ' s/:443$//' | sort -u > " $scan_path /http.txt"
224+
225+ log " Found $( wc -l < " $scan_path /http.txt" ) live HTTP services"
226+
227+ # Crawling
228+ log " Web Crawling: Running gospider..."
229+ gospider -S " $scan_path /http.txt" --json | grep ' {}' | jq -r ' .output?' | tee " $scan_path /crawl.txt"
230+
231+ # more crawling with katana
232+ # katana -u "$scan_path/resolved.txt" -xhr -jsl -d 6
233+
234+ # Calculate time diff
235+ end_time=$( date +%s)
236+ seconds=$( expr $end_time - $timestamp )
237+
238+ if [ " $seconds " -gt 59 ]; then
239+ minutes=$( expr $seconds / 60)
240+ time=" $minutes minutes"
241+ else
242+ time=" $seconds seconds"
243+ fi
244+
245+ log " Scan completed for '$id ' in $time "
246+ log " Results saved to: $scan_path "
247+ # log "Scan $id took $time" | notify
0 commit comments