├── install.sh ├── README.md ├── recon88r.sh └── recon88r.py /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to install Go tools 4 | install_go_tools() { 5 | go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest 6 | go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest 7 | go install -v github.com/projectdiscovery/notify/cmd/notify@latest 8 | go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest 9 | go install github.com/d3mondev/puredns/v2@latest 10 | go install github.com/glebarez/cero@latest 11 | go install github.com/Emoe/kxss@latest 12 | go install github.com/lc/gau/v2/cmd/gau@latest 13 | go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@latest 14 | } 15 | 16 | # Function to install massdns 17 | install_massdns() { 18 | git clone https://github.com/blechschmidt/massdns.git 19 | cd massdns 20 | make 21 | sudo make install 22 | cd .. 23 | } 24 | 25 | # Clone nuclei_templates and nuclei-templates repositories 26 | git clone https://github.com/h0tak88r/nuclei_templates.git 27 | git clone https://github.com/projectdiscovery/nuclei-templates.git 28 | 29 | # Install Go tools 30 | install_go_tools 31 | 32 | # Install massdns 33 | install_massdns 34 | 35 | # Clone Wordlists repository 36 | git clone --depth 1 https://github.com/h0tak88r/Wordlists.git & 37 | wait 38 | 39 | # Copy .gau.toml to user's home directory 40 | cp .gau.toml $HOME/.gau.toml 41 | 42 | # Add the line for local file access to Nuclei configuration 43 | echo "allow-local-file-access: true" >> ~/.config/nuclei/config.yaml 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Recon88r Script 2 | 3 | This Python script automates the reconnaissance process for penetration testers and bug hunters. It is designed to streamline subdomain enumeration, port scanning, template-based scanning, XSS, JS file analysis, and searching for exposed panels. The script sends live results via Discord, eliminating the need to manually check logs. It can be run as a cron job or within a tmux session, allowing users to efficiently await results. 4 | 5 | ## Prerequisites 6 | 7 | Before using the script, ensure you have the following tools and dependencies installed: 8 | 9 | - Python 3.x 10 | - [Subfinder](https://github.com/projectdiscovery/subfinder) 11 | - [PureDNS](https://github.com/d3mondev/puredns) 12 | - [Naabu](https://github.com/projectdiscovery/naabu) 13 | - [Nuclei](https://github.com/projectdiscovery/nuclei) 14 | - [HTTPX](https://github.com/projectdiscovery/httpx) 15 | - [Gau](https://github.com/lc/gau) 16 | - [kxss](https://github.com/tomnomnom/hacks/tree/main/kxss) 17 | - [Notify](https://github.com/projectdiscovery/notify) 18 | - [Wordlists](https://github.com/h0tak88r/Wordlists) 19 | - [nuclei_templates](https://github.com/h0tak88r/nuclei_templates) 20 | 21 | ## Setup 22 | 23 | 1. Clone the repository: 24 | 25 | ```bash 26 | git clone https://github.com/h0tak88r/Recon88r.git 27 | ``` 28 | 29 | 2. Navigate to the script directory: 30 | 31 | ```bash 32 | cd Recon88r 33 | ``` 34 | 35 | 3. Set up a virtual environment (optional but recommended): 36 | 37 | ```bash 38 | python -m venv venv 39 | source venv/bin/activate # On Windows, use 'venv\Scripts\activate' 40 | ``` 41 | 42 | 4. Install the required prerequisites: 43 | 44 | ```bash 45 | bash install.sh 46 | ``` 47 | 5. Configure Discord Webhook URL in the Notify tool configuration file: 48 | 49 | ```bash 50 | nano $HOME/.config/notify/provider-config.yaml 51 | ``` 52 | ## Usage 53 | 54 | Run the script with the desired options to perform reconnaissance tasks. Below are some examples: 55 | 56 | ```bash 57 | python3 recon88r.py -d wurl.com -ps -ac -p -nt -nf -ep -js -xss -f -wh your_discord_webhook_url 58 | ``` 59 | 60 | ### Available Options: 61 | 62 | - `-d, --domain`: Target domain for reconnaissance (required). 63 | - `-ps, --passive`: Perform passive subdomain enumeration. 64 | - `-ac --active` : Active subdoamins enumeration 65 | - `-p, --portscan`: Perform port scanning. 66 | - `-nt, --new-templates`: Scan with newly added templates to the nuclei templates repo. 67 | - `-nf, --nuclei-full`: Perform a full nuclei scan. 68 | - `-ep, --exposed-panels`: Perform Panels dorking with nuclei templates. 69 | - `-js, --js-exposures`: Perform JS Exposures. 70 | - `-sl, --subs-file`: Path to the subdomains file(Sometimes you got the subdomains from other tools and wanna do just the other features only so pass the subs list and enjoy other features). 71 | - `-xss, --xss-scan`: Perform XSS scans. 72 | - `-wh, --webhook`: Webhook URL for Discord. 73 | - '-f, --fuzzing': Fuzzing with GET/POST using various techniques. 74 | 75 | 76 | ## Workflow Mind-Map 77 | url -> https://xmind.works/share/jhW6EyeZ 78 | Recon88r py Workflow-Map 1 79 | 80 | 81 | # Bash Version 82 | - Simply run it using command `bash recon88r.sh` 83 | 84 | ## Contributing 85 | 86 | If you encounter any issues or have suggestions for improvements, feel free to open an issue or submit a pull request. Collaboration is welcome, and don't hesitate to reach out for assistance. 87 | -------------------------------------------------------------------------------- /recon88r.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check_required_tools() { 4 | local required_tools=("subfinder" "naabu" "httpx" "gau" "kxss" "nuclei") 5 | 6 | for tool in "${required_tools[@]}"; do 7 | if ! command -v "$tool" &> /dev/null; then 8 | echo "Error: $tool is not installed. Please install it before running the script." 9 | exit 1 10 | fi 11 | done 12 | } 13 | 14 | banner() { 15 | cat << "EOF" 16 | _____ ___ ___ 17 | | __ \ / _ \ / _ \ 18 | | |__) |___ ___ ___ _ __ | (_) | (_) |_ __ 19 | | _ // _ \/ __/ _ \| '_ \ > _ < > _ <| '__| 20 | | | \ \ __/ (_| (_) | | | | (_) | (_) | | 21 | |_| \_\___|\___\___/|_| |_|\___/ \___/|_| 22 | 23 | EOF 24 | } 25 | 26 | cleanup_subs_directory() { 27 | echo "[+] Cleaning up the subs directory" 28 | rm -rf subs/ 29 | mkdir subs 30 | } 31 | 32 | get_target_domain() { 33 | read -p "Enter the target domain: " target_domain 34 | echo "$target_domain" 35 | } 36 | 37 | get_discord_webhooks() { 38 | read -p "Enter the Discord webhook URL for passive scan: " DISCORD_WEBHOOK_PASSIVE 39 | read -p "Enter the Discord webhook URL for active scan: " DISCORD_WEBHOOK_ACTIVE 40 | } 41 | 42 | passive_subdomain_enumeration() { 43 | echo "[+] Performing passive subdomain enumeration" 44 | target_domain=$1 45 | 46 | urls=( 47 | "https://rapiddns.io/subdomain/$target_domain?full=1#result" 48 | "http://web.archive.org/cdx/search/cdx?url=*.$target_domain/*&output=text&fl=original&collapse=urlkey" 49 | "https://crt.sh/?q=%.$target_domain" 50 | "https://crt.sh/?q=%.%.$target_domain" 51 | "https://crt.sh/?q=%.%.%.$target_domain" 52 | "https://crt.sh/?q=%.%.%.%.$target_domain" 53 | "https://otx.alienvault.com/api/v1/indicators/domain/$target_domain/passive_dns" 54 | "https://api.hackertarget.com/hostsearch/?q=$target_domain" 55 | "https://urlscan.io/api/v1/search/?q=$target_domain" 56 | "https://jldc.me/anubis/subdomains/$target_domain" 57 | "https://www.google.com/search?q=site%3A$target_domain&num=100" 58 | "https://www.bing.com/search?q=site%3A$target_domain&count=50" 59 | ) 60 | 61 | for url in "${urls[@]}"; do 62 | curl -s "$url" | grep -o '([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.'"$target_domain"'' >> "subs/passive.txt" 63 | done 64 | 65 | cat "subs/passive.txt" | sort -u > "subs/quick_passive.txt" 66 | rm "subs/passive.txt" 67 | subfinder -d $target_domain --all --silent > "subs/subfinder.txt" 68 | } 69 | 70 | active_subdomain_enumeration() { 71 | echo "[+] Performing active subdomain enumeration" 72 | target_domain=$1 73 | 74 | puredns bruteforce "Wordlists/dns/dns_2m.txt" "$target_domain" -r "Wordlists/dns/valid_resolvers.txt" -w "subs/dns_bf.txt" --skip-wildcard-filter --skip-validation 75 | cero "$target_domain" | sed 's/^*.//' | grep "\." | sort -u | grep ".$target_domain$" > "subs/tls_probing.txt" 76 | cat "subs/"* | sort -u > "subs/all_subs_filtered.txt" 77 | puredns resolve "subs/all_subs_filtered.txt" -r "Wordlists/dns/valid_resolvers.txt" -w "subs/all_subs_resolved.txt" --skip-wildcard-filter --skip-validation 78 | cat "subs/all_subs_filtered.txt" | httpx -random-agent -retries 2 -o "subs/filtered_hosts.txt" 79 | } 80 | 81 | send_file_to_discord() { 82 | local webhook_url="$1" 83 | local file_path="$2" 84 | 85 | if [ -f "$file_path" ]; then 86 | curl -X POST -F "file=@$file_path" "$webhook_url" 87 | echo "File '$file_path' successfully sent to Discord." 88 | else 89 | echo "Error: File '$file_path' not found." 90 | fi 91 | } 92 | 93 | perform_port_scanning() { 94 | echo "[+] Performing port scanning" 95 | naabu -list subs/all_subs_filtered.txt -top-ports 1000 | notify -bulk 96 | } 97 | 98 | perform_exposed_panels_scan() { 99 | echo "[+] Performing exposed panels scan" 100 | cat subs/filtered_hosts.txt | nuclei -t nuclei_templates/panels | notify -bulk 101 | } 102 | 103 | perform_js_exposure_scan() { 104 | echo "[+] Performing JS exposure scan" 105 | gau "$TARGET_DOMAIN" | grep "\\.js$" | sort -u | tee JS.txt 106 | nuclei -l JS.txt -t nuclei_templates/js/information-disclosure-in-js-files.yaml | notify -bulk 107 | } 108 | 109 | scan_with_new_nuclei_templates() { 110 | echo "[+] Scan with newly added templates to the nuclei templates repo" 111 | cat subs/filtered_hosts.txt | nuclei -t nuclei-templates/ -nt -es info | notify -bulk 112 | } 113 | 114 | perform_full_nuclei_scan() { 115 | echo "[+] Performing a full nuclei scan" 116 | cat subs/filtered_hosts.txt | nuclei -t nuclei_templates/Others -es info | notify -bulk 117 | } 118 | 119 | xss_scan() { 120 | echo "[+] Scanning for XSS" 121 | gau "$TARGET_DOMAIN" | kxss | notify --bulk 122 | } 123 | 124 | fuuzing() { 125 | echo "[+] Fuzzing using h0tak88r_fuzz.txt wordlist" 126 | nuclei -t nuclei_templates/fuzzing/h0tak88r/ -l subs/filtered_hosts.txt | notify -bulk 127 | } 128 | 129 | recon() { 130 | check_required_tools 131 | 132 | banner 133 | cleanup_subs_directory 134 | 135 | TARGET_DOMAIN=$(get_target_domain) 136 | get_discord_webhooks 137 | 138 | passive_subdomain_enumeration "$TARGET_DOMAIN" 139 | active_subdomain_enumeration "$TARGET_DOMAIN" 140 | 141 | send_file_to_discord "$DISCORD_WEBHOOK_PASSIVE" "subs/all_subs_filtered.txt" 142 | send_file_to_discord "$DISCORD_WEBHOOK_ACTIVE" "subs/filtered_hosts.txt" 143 | 144 | xss_scan 145 | perform_port_scanning 146 | perform_exposed_panels_scan 147 | perform_js_exposure_scan 148 | scan_with_new_nuclei_templates 149 | perform_full_nuclei_scan 150 | fuuzing 151 | } 152 | 153 | # Main execution 154 | recon 155 | -------------------------------------------------------------------------------- /recon88r.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import requests 3 | import os 4 | import re 5 | import glob 6 | import argparse 7 | import tempfile 8 | import concurrent.futures 9 | 10 | banner =""" 11 | 12 | _____ ___ ___ 13 | | __ \ / _ \ / _ \ 14 | | |__) |___ ___ ___ _ __ | (_) | (_) |_ __ 15 | | _ // _ \/ __/ _ \| '_ \ > _ < > _ <| '__| 16 | | | \ \ __/ (_| (_) | | | | (_) | (_) | | 17 | |_| \_\___|\___\___/|_| |_|\___/ \___/|_| 18 | 19 | 20 | 21 | """ 22 | print(banner) 23 | 24 | 25 | 26 | # Get the directory of the currently running script 27 | absolute_path = os.path.dirname(os.path.abspath(__file__)) 28 | 29 | # Arguments Functions -------------------------------- 30 | def parse_args(): 31 | parser = argparse.ArgumentParser(description='Reconnaissance script with various modules.') 32 | 33 | # Specify the available command-line options 34 | parser.add_argument('-d', '--domain', type=validate_domain, help='Target domain for reconnaissance') 35 | parser.add_argument('-ps', '--passive', action='store_true', help='Perform passive subdomain enumeration') 36 | parser.add_argument('-ac', '--active', action='store_true', help='Perform active scan phase') 37 | parser.add_argument('-p', '--portscan', action='store_true', help='Perform port scanning') 38 | parser.add_argument('-nt', '--new-templates', action='store_true', help='Scan with newly added templates to the nuclei templates repo') 39 | parser.add_argument('-nf', '--nuclei-full', action='store_true', help='Perform a full nuclei scan') 40 | parser.add_argument('-ep', '--exposed-panels', action='store_true', help='Perform Panels dorking with nuclei templates') 41 | parser.add_argument('-js', '--js-exposures', action='store_true', help='Perform JS Exposures') 42 | parser.add_argument('-sl', '--subs-file', help='Path to the subdomains file') 43 | parser.add_argument('-xss', '--xss-scan', action='store_true', help='Perform xss scans') 44 | parser.add_argument('-wh', '--webhook', help='Webhook URL for Discord') 45 | parser.add_argument('-f', '--fuzzing', action='store_true' , help='fuzzing with h0tak88r.txt wordlist') 46 | 47 | try: 48 | return parser.parse_args() 49 | except argparse.ArgumentError as e: 50 | print(f"Error: {e}") 51 | parser.print_help() 52 | exit(1) 53 | 54 | def send_file_to_discord(webhook_url, file_path): 55 | """ 56 | Send a file to Discord via webhook. 57 | """ 58 | try: 59 | with open(file_path, 'rb') as file: 60 | files = {'file': file} 61 | response = requests.post(webhook_url, files=files) 62 | 63 | if response.status_code == 200: 64 | print(f"File '{file_path}' successfully sent to Discord.") 65 | else: 66 | print(f"Failed to send file to Discord. Status code: {response.status_code}") 67 | except Exception as e: 68 | print(f"An error occurred: {e}") 69 | 70 | 71 | def run_command(command, input_data=None, capture_output=True): 72 | try: 73 | result = subprocess.run(command, input=input_data, capture_output=capture_output, text=True, check=True) 74 | return result.stdout.strip() if capture_output else None 75 | except subprocess.CalledProcessError as e: 76 | print(f"Error while running command {command}: {e}") 77 | print("Command Output:") 78 | print(e.output.decode()) 79 | return None 80 | except Exception as e: 81 | print(f"An unexpected error occurred: {e}") 82 | return None 83 | 84 | def validate_domain(domain): 85 | """ 86 | Validates the domain name using a regular expression. 87 | """ 88 | pattern = re.compile(r'^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]\.)?([a-zA-Z]{2,})$') 89 | if not pattern.match(domain): 90 | raise ValueError('Invalid domain name') 91 | return domain 92 | 93 | def xss_scan(domain): 94 | """ 95 | Scans a domain for XSS vulnerabilities. 96 | """ 97 | gau = run_command(["gau", domain]) 98 | if gau: 99 | xss_scan_cmd = ["kxss"] 100 | xss_scan_output = run_command(xss_scan_cmd, input_data=gau) 101 | if xss_scan_output: 102 | notify_cmd = ["notify", "-bulk"] 103 | run_command(notify_cmd, input_data=xss_scan_output) 104 | 105 | def fetch_subdomains(url, domain): 106 | """ 107 | Fetches subdomains from a given URL and returns them as a set. 108 | """ 109 | try: 110 | response = requests.get(url) 111 | response.raise_for_status() 112 | pattern = re.compile(rf'((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.{domain})') 113 | return set(pattern.findall(response.text)) 114 | except requests.exceptions.RequestException as e: 115 | print(f"Error fetching subdomains from {url}: {e}") 116 | return set() 117 | 118 | def fetch_all_subdomains(domain): 119 | """ 120 | Fetches subdomains from all URLs concurrently and returns them as a set. 121 | """ 122 | urls = [ 123 | f'https://rapiddns.io/subdomain/{domain}?full=1#result', 124 | f'http://web.archive.org/cdx/search/cdx?url=*.{domain}/*&output=text&fl=original&collapse=urlkey', 125 | f'https://crt.sh/?q=%25.{domain}&output=json', 126 | f'https://otx.alienvault.com/api/v1/indicators/domain/{domain}/passive_dns', 127 | f'https://api.hackertarget.com/hostsearch/?q={domain}', 128 | f'https://urlscan.io/api/v1/search/?q={domain}', 129 | f'https://jldc.me/anubis/subdomains/{domain}', 130 | ] 131 | 132 | with concurrent.futures.ThreadPoolExecutor() as executor: 133 | futures = [executor.submit(fetch_subdomains, url, domain) for url in urls] 134 | subdomains = set() 135 | for future in concurrent.futures.as_completed(futures): 136 | subdomains |= future.result() 137 | 138 | return subdomains 139 | 140 | def write_subdomains_to_file(subdomains, output_file): 141 | with open(output_file, 'w') as file: 142 | for subdomain in sorted(subdomains): 143 | file.write(f'{subdomain}\n') 144 | 145 | def subdomain_enumeration(target_domain, perform_passive, perform_active): 146 | print("[+] Performing subdomain enumeration") 147 | 148 | if perform_passive: 149 | print("[+] Passive Subdomain Enumeration ....") 150 | subs_directory = f"{absolute_path}/subs/" 151 | run_command(["rm", "-rf", subs_directory]) 152 | run_command(["mkdir", subs_directory]) 153 | 154 | # Fetch subdomains from all sources 155 | subdomains = fetch_all_subdomains(target_domain) 156 | 157 | # Write subdomains to a file 158 | temp_file = tempfile.NamedTemporaryFile(mode='w+', delete=False) 159 | try: 160 | write_subdomains_to_file(subdomains, temp_file.name) 161 | output_file = f'{subs_directory}/{target_domain}.txt' 162 | write_subdomains_to_file(subdomains, output_file) 163 | print(f'[+] Passive Subdomains saved to {output_file}') 164 | finally: 165 | os.unlink(temp_file.name) 166 | 167 | # Running subfinder on the target domain 168 | print(f'[+] Running passive subdomains using subfinder for {target_domain}') 169 | subfinder_output = run_command(["subfinder", "-d", target_domain, "--all", "--silent"]) 170 | if subfinder_output: 171 | subfinder_file = f"{subs_directory}/subfinder.txt" 172 | write_subdomains_to_file(subfinder_output.split('\n'), subfinder_file) 173 | 174 | if perform_active: 175 | # Actie Subdomain Enumeration using DNS brute forcing with puredns 176 | print("[+] Actie Subdomain Enumeration using DNS brute forcing with puredns") 177 | try: 178 | run_command(["puredns", "bruteforce", f"{absolute_path}/Wordlists/dns/dns_2m.txt", target_domain, "-r", f"{absolute_path}/Wordlists/dns/valid_resolvers.txt", "-w", f"{subs_directory}/dns_bf.txt", "--skip-wildcard-filter", "--skip-validation"]) 179 | except Exception as e: 180 | print(f"Error while running puredns for DNS brute forcing: {e}") 181 | 182 | ## TLS Probing 183 | print("[+] TLS probing") 184 | cero_output = run_command(["cero", target_domain]) 185 | if cero_output: 186 | sed_output = run_command(["sed", 's/^*.//'], input_data=cero_output) 187 | grep_output = run_command(["grep", "\\."], input_data=sed_output) 188 | if grep_output is not None and len(grep_output) > 0: 189 | sort_output = run_command(["sort", "-u"], input_data=grep_output) 190 | with open(f"{subs_directory}/tls_probing.txt", "w") as tls_probing_file: 191 | tls_probing_file.write(sort_output) 192 | else: 193 | print("[!] Warning: No domains found in TLS probing results.") 194 | else: 195 | print("[!] Error during TLS probing. Subdomain enumeration may not have provided any domains.") 196 | 197 | def filter_and_resolve_subdomains(): 198 | print("[+] Filtering out the results") 199 | subs_files = glob.glob(f"{absolute_path}/subs/*") 200 | 201 | # Read all content from subdomain files 202 | all_subs_content = "" 203 | for file_path in subs_files: 204 | with open(file_path, 'r') as file: 205 | all_subs_content += file.read() 206 | 207 | # Use Python's sort for sorting 208 | sorted_subs_content = "\n".join(sorted(set(all_subs_content.split('\n')))) 209 | 210 | output_file = f"{absolute_path}/subs/all_subs_filtered.txt" 211 | 212 | with open(output_file, "w") as file: 213 | file.write(sorted_subs_content) 214 | 215 | print("[+] Running puredns for resolving the subs and output in all_subs_resolved.txt") 216 | 217 | try: 218 | run_command(["puredns", "resolve", output_file, "-r", f"{absolute_path}/Wordlists/dns/valid_resolvers.txt", "-w", f"{absolute_path}/subs/all_subs_resolved.txt", "--skip-wildcard-filter", "--skip-validation"]) 219 | except Exception as e: 220 | print(f"Error while running puredns for resolving subdomains: {e}") 221 | 222 | print("[+] Running httpx for filtering the subs and output in filtered_hosts.txt") 223 | run_command(["httpx", "-l", output_file, "-random-agent", "-retries", "2", "-o", f"{absolute_path}/subs/filtered_hosts.txt"]) 224 | 225 | 226 | def port_scanning(): 227 | print("[+] Performing port scanning") 228 | naabu_command = run_command(["naabu", "-list", f"{absolute_path}/subs/all_subs_filtered.txt", "-top-ports", "1000"]) 229 | if naabu_command: 230 | run_command(["notify", "-bulk"], input_data=naabu_command) 231 | 232 | def scan_with_new_nuclei_templates(): 233 | print("[+] Scan with newly added templates to the nuclei templates repo") 234 | ntscan = run_command(["nuclei", "-l", f"{absolute_path}/subs/filtered_hosts.txt", "-t", f"{absolute_path}/nuclei-templates/", "-nt", "-es", "info"]) 235 | if ntscan: 236 | run_command(["notify", "-bulk"], input_data=ntscan) 237 | 238 | def full_nuclei_scan(): 239 | print("[+] Scan with the full nuclei template") 240 | pt_scan = run_command(["nuclei", "-l", f"{absolute_path}/subs/filtered_hosts.txt", "-t", f"{absolute_path}/nuclei_templates/Others", "-es", "info"]) 241 | if pt_scan: 242 | run_command(["notify", "-bulk"], input_data=pt_scan) 243 | 244 | def js_exposure_scan(): 245 | print("[+] Scanning js files") 246 | resolved_domains_output = run_command(["cat", f"{absolute_path}/subs/all_subs_resolved.txt"]) 247 | if resolved_domains_output: 248 | all_urls = run_command(["gau"], input_data=resolved_domains_output) 249 | js_files_filter = run_command(["grep", "\\.js$"], input_data=all_urls) 250 | js_files_output = run_command(["sort", "-u"], input_data=js_files_filter) 251 | js_scan = run_command(["nuclei", "-t", f"{absolute_path}/nuclei_templates/js/information-disclosure-in-js-files.yaml"], input_data=js_files_output) 252 | if js_scan: 253 | run_command(["notify", "-bulk"], input_data=js_scan) 254 | 255 | def exposed_panels_scan(): 256 | print("[+] Scanning for exposed panels") 257 | panels = run_command(["nuclei", "-l", f"{absolute_path}/subs/filtered_hosts.txt", "-t", f"{absolute_path}/nuclei_templates/Panels"]) 258 | if panels: 259 | run_command(["notify", "-bulk"], input_data=panels) 260 | 261 | 262 | def fuzzing(): 263 | print("[+] Fuzzing with h0tak88r.txt Wordlist:") 264 | print("[+] Please make sure that the config file for nuclei has allow-local-file-access: true") 265 | try: 266 | h0tak88r_fuzzing = run_command(["nuclei", "-l", f"{absolute_path}/subs/filtered_hosts.txt", "-t", f"{absolute_path}/nuclei_templates/fuzzing/h0tak88r/"]) 267 | if h0tak88r_fuzzing: 268 | run_command(["notify", "-bulk"], input_data=h0tak88r_fuzzing) 269 | except Exception as e: 270 | print(f"An error occurred during fuzzing: {e}") 271 | 272 | def recon(target_domain, perform_passive=False, perform_active=False, perform_portscan=False, perform_nuclei_new=False, perform_nuclei_full=False, perform_exposed_panels=False, perform_js_exposure=False, subs_file=None, perform_xss_scan=False, webhook=None, perform_fuzzing=False): 273 | try: 274 | if target_domain: 275 | subdomain_enumeration(target_domain, perform_passive, perform_active) 276 | filter_and_resolve_subdomains() 277 | if subs_file: 278 | # Use the provided subdomains file for other operations 279 | print(f"[+] Using provided subdomains file: {subs_file}") 280 | print("[+] Filtering dupliacates...") 281 | subs_directory = f"{absolute_path}/subs/" 282 | run_command(["rm", "-r", subs_directory]) 283 | run_command(["mkdir", subs_directory]) 284 | 285 | with open(subs_file, 'r') as file: 286 | subdomains = set(file.read().splitlines()) 287 | 288 | sorted_subdomains = sorted(subdomains) 289 | 290 | with open(f"{subs_directory}/all_subs_filtered.txt", 'w') as output_file: 291 | for subdomain in sorted_subdomains: 292 | output_file.write(f'{subdomain}\n') 293 | 294 | print("[+] Running httpx for filtering the subs and output in filtered_hosts.txt ") 295 | run_command(["httpx", "-l", f"{subs_directory}/all_subs_filtered.txt", "-random-agent", "-retries", "2", "-o", f"{subs_directory}/filtered_hosts.txt"]) 296 | 297 | if webhook: 298 | send_file_to_discord(webhook, f"{absolute_path}/subs/all_subs_filtered.txt" ) 299 | 300 | if perform_portscan: 301 | port_scanning() 302 | 303 | if perform_nuclei_new: 304 | scan_with_new_nuclei_templates() 305 | 306 | if perform_nuclei_full: 307 | full_nuclei_scan() 308 | 309 | if perform_js_exposure: 310 | js_exposure_scan() 311 | 312 | if perform_exposed_panels: 313 | exposed_panels_scan() 314 | 315 | if perform_xss_scan: 316 | print("[+] Scanning for XSS") 317 | xss_scan(target_domain) 318 | if perform_fuzzing: 319 | fuzzing() 320 | 321 | except Exception as e: 322 | print(f"An error occurred during reconnaissance: {e}") 323 | 324 | if __name__ == "__main__": 325 | args = parse_args() 326 | if not args.subs_file: 327 | # If no subs file is provided, the domain is required 328 | if not args.domain: 329 | print("Error: Target domain is required.") 330 | exit(1) 331 | 332 | recon(args.domain, args.passive, args.active, args.portscan, args.new_templates, args.nuclei_full, args.exposed_panels, args.js_exposures, args.subs_file, args.xss_scan, args.webhook, args.fuzzing) 333 | --------------------------------------------------------------------------------