#!/usr/bin/env python3 import os import sys R = "\033[31m" # red G = "\033[32m" # green C = "\033[36m" # cyan W = "\033[0m" # white from modules.write_log import log_writer log_writer("Importing config...") import settings as config home = config.home usr_data = config.usr_data conf_path = config.conf_path path_to_script = config.path_to_script src_conf_path = config.src_conf_path meta_file_path = config.meta_file_path keys_file_path = config.keys_file_path log_writer( f"PATHS = HOME:{home}, SCRIPT_LOC:{path_to_script},\ METADATA:{meta_file_path}, KEYS:{config.keys_file_path},\ CONFIG:{config.conf_file_path}, LOG:{config.log_file_path}" ) import argparse VERSION = config.version log_writer(f"FinalRecon v{VERSION}") parser = argparse.ArgumentParser( description=f"FinalRecon - All in One Web Recon | v{VERSION}" ) parser.add_argument("--url", help="Target URL") parser.add_argument("--headers", help="Header Information", action="store_true") parser.add_argument( "--sslinfo", help="SSL Certificate Information", action="store_true" ) parser.add_argument("--whois", help="Whois Lookup", action="store_true") parser.add_argument("--crawl", help="Crawl Target", action="store_true") parser.add_argument("--dns", help="DNS Enumeration", action="store_true") parser.add_argument("--sub", help="Sub-Domain Enumeration", action="store_true") parser.add_argument("--dir", help="Directory Search", action="store_true") parser.add_argument("--wayback", help="Wayback URLs", action="store_true") parser.add_argument("--ps", help="Fast Port Scan", action="store_true") parser.add_argument("--full", help="Full Recon", action="store_true") ext_help = parser.add_argument_group("Extra Options") ext_help.add_argument("-nb", action="store_false", help="Hide Banner") ext_help.add_argument( "-dt", type=int, help="Number of threads for directory enum [ Default : 30 ]" ) ext_help.add_argument( "-pt", type=int, help="Number of threads for port scan [ Default : 50 ]" ) ext_help.add_argument("-T", type=float, help="Request Timeout [ Default : 30.0 ]") ext_help.add_argument( "-w", help="Path to Wordlist [ Default : wordlists/dirb_common.txt ]" ) ext_help.add_argument( "-r", action="store_true", help="Allow Redirect [ Default : False ]" ) ext_help.add_argument( "-s", action="store_false", help="Toggle SSL Verification [ Default : True ]" ) ext_help.add_argument("-sp", type=int, help="Specify SSL Port [ Default : 443 ]") ext_help.add_argument("-d", help="Custom DNS Servers [ Default : 1.1.1.1 ]") ext_help.add_argument("-e", help="File Extensions [ Example : txt, xml, php ]") ext_help.add_argument("-o", help="Export Format [ Default : txt ]") ext_help.add_argument( "-cd", help="Change export directory [ Default : ~/.local/share/finalrecon ]" ) ext_help.add_argument( "-of", help="Change export folder name [ Default :fr__ ]" ) ext_help.add_argument("-k", help="Add API key [ Example : shodan@key ]") ext_help.set_defaults( dt=config.dir_enum_th, pt=config.port_scan_th, T=config.timeout, w=config.dir_enum_wlist, r=config.dir_enum_redirect, s=config.dir_enum_sslv, sp=config.ssl_port, d=config.custom_dns, e=config.dir_enum_ext, o=config.export_fmt, cd=config.usr_data, of=None, ) try: args = parser.parse_args() except SystemExit: log_writer("[finalrecon] Help menu accessed") log_writer(f"{'-' * 30}") sys.exit() target = args.url headinfo = args.headers sslinfo = args.sslinfo whois = args.whois crawl = args.crawl dns = args.dns dirrec = args.dir wback = args.wayback pscan = args.ps full = args.full threads = args.dt pscan_threads = args.pt tout = args.T wdlist = args.w redir = args.r sslv = args.s sslp = args.sp dserv = args.d filext = args.e subd = args.sub output = args.o show_banner = args.nb add_key = args.k output_dir = args.cd folder_name = args.of import datetime import ipaddress import socket from json import dumps, loads from urllib import parse import tldextract type_ip = False data = {} def banner(): with open(meta_file_path, "r") as metadata: json_data = loads(metadata.read()) twitter_url = json_data["twitter"] comms_url = json_data["comms"] art = r""" ______ __ __ __ ______ __ /\ ___\/\ \ /\ "-.\ \ /\ __ \ /\ \ \ \ __\\ \ \\ \ \-. \\ \ __ \\ \ \____ \ \_\ \ \_\\ \_\\"\_\\ \_\ \_\\ \_____\ \/_/ \/_/ \/_/ \/_/ \/_/\/_/ \/_____/ ______ ______ ______ ______ __ __ /\ == \ /\ ___\ /\ ___\ /\ __ \ /\ "-.\ \ \ \ __< \ \ __\ \ \ \____\ \ \/\ \\ \ \-. \ \ \_\ \_\\ \_____\\ \_____\\ \_____\\ \_\\"\_\ \/_/ /_/ \/_____/ \/_____/ \/_____/ \/_/ \/_/""" print(f"{C}{art}{W}\n") print(f"{G}[>]{W} Created By : thewhiteh4t") print(f"{G} |--->{W} Twitter : {twitter_url}") print(f"{G} |--->{W} Community : {comms_url}") print(f"{G}[>]{W} Version : {VERSION}\n") def save_key(key_string): valid_keys = [ "bevigil", "netlas", "shodan", "virustotal", "zoomeye", "hunter", "alienvault", "chaos", "leakix", "github", ] key_parts = key_string.split("@", 1) key_name = key_parts[0] key_str = key_parts[1] if key_name not in valid_keys: print(f"{R}[-]{W} Invalid key name!") log_writer("Invalid key name, exiting") sys.exit(1) with open(keys_file_path, "r") as keyfile: keys_json = loads(keyfile.read()) keys_json[key_name] = key_str with open(keys_file_path, "w") as key_update: key_update.write(dumps(keys_json)) print(f"{G}[+]{W} {key_name} Key Added!") sys.exit(1) try: if show_banner: banner() if add_key: save_key(add_key) if not target: print(f"{R}[-]{W} No Target Specified!") sys.exit(1) if not target.startswith(("http", "https")): print(f"{R}[-]{W} Protocol Missing, Include {C}http://{W} or {C}https://{W} \n") log_writer(f"Protocol missing in {target}, exiting") sys.exit(1) if target.endswith("/"): target = target[:-1] print(f"{C}[*]{W} Target : {target}") split_url = parse.urlsplit(target) protocol = split_url.scheme hostname = split_url.hostname try: ipaddress.ip_address(hostname) type_ip = True ip = hostname except ValueError: try: ip = socket.gethostbyname(hostname) print(f"\n{C}[*]{W} IP Address : {str(ip)}") except Exception as e: print(f"\n{R}[-]{W} Unable to Get IP : {str(e)}") sys.exit(1) private_ip = ipaddress.ip_address(ip).is_private port = split_url.port if type_ip: netloc = f"{hostname}:{port}" if port else hostname domain = "" domain_suffix = "" apex_domain = "" elif not private_ip: extractor = tldextract.TLDExtract() parsed_url = extractor.extract_urllib(split_url) domain = parsed_url.domain domain_suffix = parsed_url.suffix parsed_fqdn = parsed_url.fqdn if parsed_url.fqdn else hostname netloc = f"{parsed_fqdn}:{port}" if port else parsed_fqdn apex_domain = f"{domain}.{domain_suffix}" else: netloc = f"{hostname}:{port}" if port else hostname domain = "" domain_suffix = "" apex_domain = "" start_time = datetime.datetime.now() if output != "None": fpath = output_dir if not folder_name: dt_now = str(datetime.datetime.now().strftime("%d-%m-%Y_%H:%M:%S")) fname = f"{fpath}fr_{hostname}_{dt_now}.{output}" respath = f"{fpath}fr_{hostname}_{dt_now}" else: fname = f"{fpath}{folder_name}.{output}" respath = f"{fpath}{folder_name}" if not os.path.exists(respath): os.makedirs(respath) out_settings = {"format": output, "directory": respath, "file": fname} log_writer(f"OUTPUT = FORMAT: {output}, DIR: {respath}, FILENAME: {fname}") if full: log_writer("Starting full recon...") from modules.crawler import crawler from modules.dirrec import hammer from modules.dns import dnsrec from modules.headers import headers from modules.portscan import scan from modules.sslinfo import cert headers(target, out_settings, data) cert(hostname, sslp, out_settings, data) dnsrec(apex_domain, dserv, out_settings, data) if not type_ip and not private_ip: from modules.subdom import subdomains from modules.wayback import timetravel from modules.whois import whois_lookup whois_lookup(domain, domain_suffix, path_to_script, out_settings, data) subdomains(apex_domain, tout, out_settings, data, conf_path) timetravel(target, data, out_settings) scan(ip, out_settings, data, pscan_threads) crawler(target, protocol, netloc, out_settings, data) hammer(target, threads, tout, wdlist, redir, sslv, out_settings, data, filext) if headinfo: from modules.headers import headers log_writer("Starting header enum...") headers(target, out_settings, data) if sslinfo: from modules.sslinfo import cert log_writer("Starting SSL enum...") cert(hostname, sslp, out_settings, data) if whois: from modules.whois import whois_lookup log_writer("Starting whois enum...") whois_lookup(domain, domain_suffix, path_to_script, out_settings, data) if crawl: from modules.crawler import crawler log_writer("Starting crawler...") crawler(target, protocol, netloc, out_settings, data) if dns: from modules.dns import dnsrec log_writer("Starting DNS enum...") dnsrec(hostname, dserv, out_settings, data) if subd and not type_ip and not private_ip: from modules.subdom import subdomains log_writer("Starting subdomain enum...") subdomains(hostname, tout, out_settings, data, conf_path) elif subd and type_ip: print(f"{R}[-]{W} Sub-Domain Enumeration is Not Supported for IP Addresses\n") log_writer("Sub-Domain Enumeration is Not Supported for IP Addresses, exiting") sys.exit(1) if wback: from modules.wayback import timetravel log_writer("Starting wayback enum...") timetravel(hostname, data, out_settings) if pscan: from modules.portscan import scan log_writer("Starting port scan...") scan(ip, out_settings, data, threads) if dirrec: from modules.dirrec import hammer log_writer("Starting dir enum...") hammer(target, threads, tout, wdlist, redir, sslv, out_settings, data, filext) if not any( [full, headinfo, sslinfo, whois, crawl, dns, subd, wback, pscan, dirrec] ): print(f"\n{R}[-]{W} Error : At least One Argument is Required with URL") log_writer("At least One Argument is Required with URL, exiting") output = "None" sys.exit(1) end_time = datetime.datetime.now() - start_time total_seconds = int(end_time.total_seconds()) hours, remainder = divmod(total_seconds, 3600) minutes, seconds = divmod(remainder, 60) if hours: readable = f"{hours}h {minutes}m {seconds}s" elif minutes: readable = f"{minutes}m {seconds}s" else: readable = f"{seconds}s" print(f"\n{G}[+]{W} Completed in {readable}\n") log_writer(f"Completed in {readable}") print(f"{G}[+]{W} Exported : {respath}") log_writer(f"Exported to {respath}") log_writer(f"{'-' * 30}") sys.exit() except KeyboardInterrupt: print(f"{R}[-]{W} Keyboard Interrupt.\n") log_writer("Keyboard interrupt, exiting") log_writer(f"{'-' * 30}") sys.exit(130)