def brute(self): # Bruteforce URLs cmd = "wfuzz -w '%s' -c -u '%s/FUZZ' -L --hc 400,403,404,405,500,501,502,503 \ -f '%s,html'|tee '%s'" % (self.get_resource_path('urls.txt'), self.url, self.get_output_path('wfuzz.html'), self.get_output_path('wfuzz.txt')) utils.run_cmd(cmd) # Detect and bruteforce HTTP Basic authentication if 'WWW-Authenticate: Basic' not in subprocess.check_output('curl -kLI %s' % self.url, shell=True).decode('utf8'): return utils.log('Starting HTTP bruteforce against %s' % (self.url), 'info') user_list = self.get_resource_path('http_users.txt') pass_list = self.get_resource_path('http_passwords.txt') userpass_list = self.get_resource_path('http_userpass.txt') outfile = self.get_output_path('brute.txt') if not config.ONLY_CUSTOM_BRUTE: self.do_bruteforce(outfile, user_list=user_list, pass_list=pass_list) self.do_bruteforce(outfile, userpass_list=userpass_list) if config.CUSTOM_USER_LIST: outfile = self.get_output_path('brute_custom1.txt') self.do_bruteforce(outfile, user_list=config.CUSTOM_USER_LIST, pass_list=config.CUSTOM_PASS_LIST) if config.CUSTOM_USERPASS_LIST: outfile = self.get_output_path('brute_custom2.txt') self.do_bruteforce(outfile, userpass_list=config.CUSTOM_USERPASS_LIST)
def _port_scan(target, output_dir): output_path = os.path.join(output_dir, target) if not os.path.exists(output_path): os.mkdir(output_path) # TCP scan cmd = 'nmap -v -sV -sT -Pn --open -oX %s %s' % (output_path + '/ports-tcp.xml', target) if config.FULL_SCAN: cmd += " -p- -T4" else: cmd += " -T5" utils.run_cmd(cmd) # UDP scan cmd = 'nmap -v -n -sV --defeat-icmp-ratelimit -Pn -sU -T4 --open -oX %s %s' % ( output_path + '/ports-udp.xml', target) if config.FULL_SCAN: cmd += " " else: cmd += " --top-ports 200" utils.run_cmd(cmd) tcp_scan = os.path.join(output_path, "ports-tcp.xml") udp_scan = os.path.join(output_path, "ports-udp.xml") port_scan_file = os.path.join(output_path, "port-scan.xml") utils.merge_nmap_files([tcp_scan, udp_scan], port_scan_file) os.remove(tcp_scan) os.remove(udp_scan) results = utils.parse_nmap_xml(port_scan_file) if not results: utils.log("No open ports on %s, deleting directory..." % target, "warning") shutil.rmtree(output_path)
def get_target_modules(target, output_dir): jobs = [] output_path = os.path.join(output_dir, target) nmap_xml_file = os.path.join(output_path, "port-scan.xml") if not os.path.exists(nmap_xml_file): return nmap_results = utils.parse_nmap_xml(nmap_xml_file) if not nmap_results: utils.log("No open ports on %s, skipping..." % target, "warning") return for port in nmap_results[target]['tcp']: if not nmap_results[target]['tcp'][port]: continue service = nmap_results[target]['tcp'][port]['name'] module_output_dir = os.path.join(output_path, 'tcp-' + port + "-" + service) for module_name in config.MODULES: module_obj = getattr(globals()['modules'], module_name) module_instance = module_obj.ModuleInstance( target, port, service, nmap_results[target]['tcp'][port], module_output_dir, 'tcp') if module_instance.can_run(): if not os.path.exists(module_output_dir): os.makedirs(module_output_dir) jobs.append(module_instance) return jobs
def enum(self): utils.log('Starting HTTP enumeration against %s' % (self.url), 'info') self.whatweb(self.target) self.screenshot(self.target) if self.hostnames: for hostname in self.hostnames: self.whatweb(hostname) self.screenshot(hostname)
def enum(self): utils.log('Starting HTTP enumeration against %s' % (self.url), 'info') cmd = "whatweb --color=never --log-brief=%s %s" % ( self.get_output_path('whatweb.txt'), self.url) utils.run_cmd(cmd) cmd = "dirb %s %s -l -r -o %s" % (self.url, self.get_ressource_path('urls.txt'), self.get_output_path('dirb.txt')) utils.run_cmd(cmd) cmd = "chromium --headless --no-sandbox --screenshot=%s %s" % ( self.get_output_path('screenshot.png'), self.url) utils.run_cmd(cmd)
def brute(self): utils.log('Starting SSH bruteforce against %s:%s' % (self.target, self.port), 'info') user_list = self.get_resource_path('ssh_usernames.txt') pass_list = self.get_resource_path('ssh_passwords.txt') userpass_list = self.get_resource_path('ssh_userpass.txt') outfile = self.get_output_path('brute.txt') if not config.ONLY_CUSTOM_BRUTE: self.do_bruteforce(outfile, user_list=user_list, pass_list=pass_list) self.do_bruteforce(outfile, userpass_list=userpass_list) if config.CUSTOM_USER_LIST: outfile = self.get_output_path('brute_custom1.txt') self.do_bruteforce(outfile, user_list=config.CUSTOM_USER_LIST, pass_list=config.CUSTOM_PASS_LIST) if config.CUSTOM_USERPASS_LIST: outfile = self.get_output_path('brute_custom2.txt') self.do_bruteforce(outfile, userpass_list=config.CUSTOM_USERPASS_LIST)
def run(output_dir): jobs = [] sweep_file = os.path.join(output_dir, 'sweep.xml') if not os.path.exists(sweep_file): utils.log( "Could not parse host list... have you performed a ping sweep first (--sweep) or specified the --no-sweep flag ? ", 'info') exit(1) for target in utils.get_host_list(sweep_file): scan_p = (target, output_dir) jobs.append(scan_p) pool = multiprocessing.Pool() pool.starmap(_recon_scan, jobs) pool.close() pool.join()
def run(output_dir): jobs = [] utils.log('Initiating port scan on targets', 'info') sweep_file = os.path.join(output_dir, 'sweep.xml') if not os.path.exists(sweep_file): utils.log( "Could not parse host list... have you performed a ping sweep first (--sweep) or specified the --no-sweep flag ? ", 'error') exit(1) for target in utils.get_host_list(sweep_file): scan_p = (target, output_dir) jobs.append(scan_p) pool = multiprocessing.Pool(10) pool.starmap(_port_scan, jobs) pool.close() pool.join() scan_files = glob.glob(os.path.join(output_dir, '*', '*.xml')) utils.update_nmap_summary(scan_files)
def brute(self): # Detect HTTP Basic authentication if 'WWW-Authenticate: Basic' not in subprocess.check_output( 'curl -LI %s' % self.url, shell=True).decode('utf8'): return utils.log('Starting HTTP bruteforce against %s' % (self.url), 'info') user_list = self.get_ressource_path('users.txt') pass_list = self.get_ressource_path('pass.txt') outfile = self.get_output_path('brute.txt') self.do_bruteforce(outfile, user_list=user_list, pass_list=pass_list) if config.CUSTOM_USER_LIST: outfile = self.get_output_path('brute_custom1.txt') self.do_bruteforce(outfile, user_list=config.CUSTOM_USER_LIST, pass_list=config.CUSTOM_PASS_LIST) if config.CUSTOM_USERPASS_LIST: outfile = self.get_output_path('brute_custom2.txt') self.do_bruteforce(outfile, userpass_list=config.CUSTOM_USERPASS_LIST)
def run(output_dir): global remaining_jobs global running_jobs utils.log('Initiating reconscan on targets', 'info') sweep_file = os.path.join(output_dir, 'sweep.xml') if not os.path.exists(sweep_file): utils.log( "Could not parse host list... have you performed a ping sweep first (--sweep) or specified the --no-sweep flag ? ", 'error') exit(1) enum_jobs = [] brute_jobs = [] for target in utils.get_host_list(sweep_file): target_modules = get_target_modules(target, output_dir) if target_modules: for module in target_modules: if config.ENUM: proc = ReconProcess(module.enum) enum_jobs.append(proc) if config.BRUTE: proc = ReconProcess(module.brute) brute_jobs.append(proc) remaining_jobs = enum_jobs + brute_jobs while remaining_jobs or running_jobs: cmd = get_user_input() if cmd: if cmd.strip().endswith('b'): interrupt_menu() continue for job in running_jobs: if not job.is_alive(): running_jobs.remove(job) continue if len(running_jobs) < config.MAX_JOBS and remaining_jobs: next_job = remaining_jobs[0] running_jobs.append(next_job) next_job.start() remaining_jobs.remove(next_job) utils.log( 'Queued jobs: %s Currently running: %s' % (len(remaining_jobs), len(running_jobs)), 'info') continue utils.log('Waiting remaining jobs...', 'info') for job in running_jobs: job.join()
def _recon_scan(target, output_dir): utils.log('Performing recon scan on target %s' % target, 'info') jobs = [] output_path = os.path.join(output_dir, target) nmap_xml_file = os.path.join(output_path, "ports-tcp.xml") if not os.path.exists(nmap_xml_file): utils.log( "Could not find scan file %s ... have you performed a --scan operation first ?" % nmap_xml_file, 'info') return nmap_results = utils.parse_nmap_xml(nmap_xml_file) if not nmap_results: utils.log("No open ports on %s, skipping..." % target, "info") return for port in nmap_results[target]['tcp']: service = nmap_results[target]['tcp'][port]['name'] output_dir = os.path.join(output_path, 'tcp', port + "-" + service) if not os.path.exists(output_dir): os.makedirs(output_dir) for module_name in utils.get_module_list(): module_obj = getattr(globals()['modules'], module_name) module_instance = module_obj.ModuleInstance( target, port, service, nmap_results[target]['tcp'][port], output_dir, 'tcp') if module_instance.can_run(): if config.ENUM: jobs.append(threading.Thread(target=module_instance.enum)) if config.BRUTE: jobs.append(threading.Thread(target=module_instance.brute)) for i in jobs: utils.log("Starting job %s ..." % i, 'info') i.start() for i in jobs: utils.log("Waiting for job %s ..." % i, 'info') i.join()
def main(): print(r""" __________.__ __ ___. .__ .___ \______ \ | _____ ____ | | _\_ |__ |__|______ __| _/ | | _/ | \__ \ _/ ___\| |/ /| __ \| \_ __ \/ __ | | | \ |__/ __ \\ \___| < | \_\ \ || | \/ /_/ | |______ /____(____ /\___ >__|_ \|___ /__||__| \____ | \/ \/ \/ \/ \/ \/ ./\. ./ `\. \. `\. `\. `\. `\. `\. `\. `\. ./ `\. ./ ____`\. ./ < `\. \-------\ `> `\. `\=====> ___< `\. ./-----/ __________`\. \.------\ _____ ___(_)(_\.`\ `\=====> < ./' ./-----/ `> ./ \. ___< ./ `\. ./ `\. ./ `\. ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ ./ \. ./ `\. ./ `\/ (Artwork by Carl Pilcher) """) parser = argparse.ArgumentParser( description="Network reconnaissance and enumeration tool.") parser.add_argument( '-t', '--target', help='Target (nmap format) or file with targets (one per line)', required=True) parser.add_argument('-o', '--output', help='Output directory (created if does not exist)', required=True) parser.add_argument('--sweep', help='Ping sweep targets', action='store_true') parser.add_argument('--no-sweep', help='Treat all hosts as alive (no ping sweep)', action='store_true') parser.add_argument('-U', '--userlist', help='Custom userlist to try on all services') parser.add_argument('-P', '--passlist', help='Custom password list to try on all service') parser.add_argument( '-C', '--userpasslist', help='User/password combinations (user:pass one by line)') parser.add_argument('-F', '--fast', action='store_true', help='Fast scan (not all ports checked)') parser.add_argument('--enum', action='store_true', help='Enumerate target') parser.add_argument('--scan', action='store_true', help='Perform port scan') parser.add_argument('--brute', action='store_true', help='Perform login bruteforce') args = parser.parse_args() # Scan configuration config.NOSWEEP = args.no_sweep config.FAST_SCAN = args.fast config.ENUM = args.enum config.BRUTE = args.brute config.SCAN = args.scan config.OUTPUT_PATH = args.output config.SWEEP = args.sweep # Custom dictionnaries if args.userlist and not args.passlist or args.passlist and not args.userlist: print('userlist and password list should be used together.') exit(1) if args.userlist: if os.path.exists(args.userlist) and os.path.isfile(args.userlist): config.CUSTOM_USER_LIST = args.userlist else: print('No such file : %s' % args.userlist) exit(1) if os.path.exists(args.passlist) and os.path.isfile(args.passlist): config.CUSTOM_PASS_LIST = args.passlist else: print('No such file : %s' % args.passlist) exit(1) if args.userpasslist: if os.path.exists(args.userpasslist) and os.path.isfile( args.userpasslist): config.CUSTOM_USERPASS_LIST = args.userpasslist else: print('No such file : %s' % args.userpasslist) exit(1) # Output directory handling if not os.path.exists(config.OUTPUT_PATH): os.mkdir(config.OUTPUT_PATH) utils.log('Created output directory %s.' % config.OUTPUT_PATH, 'info') # Load targets targets = args.target if os.path.exists(targets) and os.path.isfile(targets): targets_file = targets with open(targets_file, 'r') as f: targets = ' '.join(f.readlines()).replace('\n', '') utils.log("Parsed targets : " + targets, 'info') output_path = config.OUTPUT_PATH # Do sweep scan or import all targets if config.NOSWEEP: core.nosweep.run(targets, output_path) elif config.SWEEP: core.sweep.run(targets, output_path) if config.SCAN: # Do port scan core.portscan.run(output_path) if config.ENUM or config.BRUTE: # Do recon scan core.reconscan.run(output_path)
def brute(self): utils.log("The brute() method is not implemented in %s" % self.module_dir)
def enum(self): utils.log("The enum() method is not implemented in %s" % self.module_dir)
def run(target_file, output_dir): utils.log("Performing ping sweep on targets ...", "info") cmd = "nmap -v -n --open -sn -iL %s -oA %s/sweep" % (target_file, output_dir) utils.run_cmd(cmd)
def run(target_file, output_dir): utils.log("Importing all targets as alive", "info") utils.run_cmd("nmap -n -T4 -v -sL -oA %s -iL %s" % (os.path.join(output_dir, 'sweep'), target_file))
def main(): parser = argparse.ArgumentParser( description="Network reconnaissance and enumeration tool.", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=LOGO) parser.add_argument( '-t', '--target', help='Target (nmap format) or file with targets (one per line)') parser.add_argument('-w', '--working-dir', help='Working directory (created if does not exist)') parser.add_argument('--no-sweep', help='Treat all hosts as alive (no ping sweep)', action='store_true') parser.add_argument('-U', '--userlist', help='Custom userlist to try on all services') parser.add_argument('-P', '--passlist', help='Custom password list to try on all services') parser.add_argument( '-C', '--userpasslist', help='User/password combinations (user:pass one by line)') parser.add_argument('-F', '--full', action='store_true', help='Full port scan (all ports checked)') parser.add_argument('--enum', action='store_true', help='Run service enumeration modules') parser.add_argument('--scan', action='store_true', help='Perform port scan') parser.add_argument('--brute', action='store_true', help='Run service bruteforce modules') parser.add_argument('--nmap-import', help='Import nmap XML files (comma separated)') parser.add_argument( '-M', '--modules', help='Run only selected modules (for --enum and --brute operations)') parser.add_argument( '--only-custom-brute', action='store_true', help='--brute will run only custom wordlists on bruteforce attempts') parser.add_argument('--search', help='Find hosts running a particular ' 'service, e.g "ldap", "Apache", ...') parser.add_argument('--list-modules', action='store_true', help='List available modules') args = parser.parse_args() if args.list_modules: print("Available modules:") print("=" * 20) for module in utils.get_module_list(): print("*", module) exit(0) if not args.working_dir: parser.print_help() print("") utils.log("-w/--working-dir parameter missing", 'error') exit(1) # Scan configuration config.NOSWEEP = args.no_sweep config.FULL_SCAN = args.full config.ENUM = args.enum config.BRUTE = args.brute config.SCAN = args.scan if os.path.isabs(args.working_dir): config.OUTPUT_PATH = args.working_dir else: config.OUTPUT_PATH = os.path.join(os.getcwd(), args.working_dir) if not os.path.exists(config.OUTPUT_PATH): os.makedirs(config.OUTPUT_PATH) utils.log('Created output directory %s' % config.OUTPUT_PATH, 'info') config.MODULES = utils.get_module_list() config.ONLY_CUSTOM_BRUTE = args.only_custom_brute if args.search: nmap_path = os.path.join(config.OUTPUT_PATH, 'nmap_summary.xml') print(termcolor.colored('%s services:' % args.search, 'green')) print('=' * 30) for result in utils.find_services(nmap_path, args.search): print(result) exit(0) # Module selection if args.modules: config.MODULES = args.modules.split(',') installed_modules = utils.get_module_list() for i in config.MODULES: if i not in installed_modules: utils.log('Module not found: %s' % i, 'error') exit(1) # Import nmap file if args.nmap_import: nmap_xml_files = [] for path in args.nmap_import.split(','): nmap_xml_files += glob.glob(path) utils.import_nmap_scans(nmap_xml_files, config.OUTPUT_PATH) # Custom dictionnaries if args.userlist and not args.passlist or args.passlist and not args.userlist: utils.log('userlist and password list should be used together', 'error') exit(1) if args.userlist: if os.path.exists(args.userlist) and os.path.isfile(args.userlist): config.CUSTOM_USER_LIST = args.userlist else: utils.log('No such file : %s' % args.userlist, 'error') exit(1) if os.path.exists(args.passlist) and os.path.isfile(args.passlist): config.CUSTOM_PASS_LIST = args.passlist else: utils.log('No such file : %s' % args.passlist, 'error') exit(1) if args.userpasslist: if os.path.exists(args.userpasslist) and os.path.isfile( args.userpasslist): config.CUSTOM_USERPASS_LIST = args.userpasslist else: utils.log('No such file : %s' % args.userpasslist, 'error') exit(1) if config.ONLY_CUSTOM_BRUTE and not (args.userlist or args.userpasslist): utils.log('No custom wordlist given for bruteforce', 'error') exit(1) # Load targets file if args.target: target_file = os.path.join(config.OUTPUT_PATH, 'targets.txt') targets = args.target if os.path.exists(targets) and os.path.isfile(targets): shutil.copyfile(targets, target_file) else: with open(target_file, 'w') as f: for i in targets.split(' '): f.write(i + "\n") config.TARGET_FILE = target_file utils.log("Parsed targets : " + targets, 'info') # Ignore SIGINT signal.signal(signal.SIGINT, signal.SIG_IGN) output_path = config.OUTPUT_PATH if config.TARGET_FILE: # Do sweep scan or import all targets (no sweep) if config.NOSWEEP: core.nosweep.run(config.TARGET_FILE, output_path) else: core.sweep.run(config.TARGET_FILE, output_path) else: nmap_summary = os.path.join(output_path, "nmap_summary.xml") if os.path.exists(nmap_summary) and os.path.isfile(nmap_summary): shutil.copyfile(nmap_summary, os.path.join(output_path, 'sweep.xml')) utils.log('Targeting all hosts discovered so far', 'info') else: utils.log( 'Provide targets (-t) to scan at least for the first scan', 'error') exit(1) if config.SCAN: # Do port scan core.portscan.run(output_path) if config.ENUM or config.BRUTE: # Do recon scan core.reconscan.run(output_path) utils.log('Blackbird done.', 'info')
else: core.sweep.run(config.TARGET_FILE, output_path) else: nmap_summary = os.path.join(output_path, "nmap_summary.xml") if os.path.exists(nmap_summary) and os.path.isfile(nmap_summary): shutil.copyfile(nmap_summary, os.path.join(output_path, 'sweep.xml')) utils.log('Targeting all hosts discovered so far', 'info') else: utils.log( 'Provide targets (-t) to scan at least for the first scan', 'error') exit(1) if config.SCAN: # Do port scan core.portscan.run(output_path) if config.ENUM or config.BRUTE: # Do recon scan core.reconscan.run(output_path) utils.log('Blackbird done.', 'info') if __name__ == "__main__": try: main() except Exception as exc: utils.log('Unhandled exception : %s' % exc, 'error') utils.log(traceback.format_exc())
def interrupt_menu(*args): global remaining_jobs global running_jobs for i in running_jobs: i.suspend() utils.log("Invoking interactive menu...", "info") time.sleep(1) print(termcolor.colored("*" * 80, 'green')) print("Running processes:") for i in range(len(running_jobs)): job = running_jobs[i] print("\n" + termcolor.colored(i, 'green') + " - %s" % job.to_str()) print(termcolor.colored("*" * 80, 'green')) to_kill = input( "Choose processes to kill (comma separated) (-1 to kill all): ") to_kill = to_kill.split(',') for item in to_kill: try: item = int(item) if item not in range(len(running_jobs)) and item != -1: utils.log("Invalid choice", 'error') break except: utils.log("Invalid choice", 'error') break # No error in input, proceed to kill processes else: killed_procs = [] for choice in to_kill: choice = int(choice) if choice >= 0: proc_to_kill = running_jobs[choice] utils.log("Killing pid %s" % proc_to_kill.pid, 'warning') proc_to_kill.stop() killed_procs.append(proc_to_kill) elif choice == -1: utils.log("Killing all remaining jobs", 'warning') for i in running_jobs: i.stop() remaining_jobs = [] running_jobs = [] return for proc in killed_procs: running_jobs.remove(proc) utils.log("Resuming jobs...", 'info') for i in running_jobs: i.resume()
def run(target, output_dir): utils.log("Performing ping sweep on target %s" % target, "info") cmd = "nmap -v -n --open -T4 -sn %s -oA %s/sweep" % (target, output_dir) utils.run_cmd(cmd)
def run(targets, output_dir): utils.log("Importing target list", "info") utils.run_cmd("nmap -n -T4 -v -sL -oA %s %s" % (os.path.join(output_dir, 'sweep'), targets))