def get_crack_mode(login_list, password_list, user, password): """Checks the mode the brute forcer will use, i.e. Whether nested loops are used for guessign or not""" #Check files exist and set mode if password_list and login_list: if not exists(password_list): bc.err("Password list : {} does not exist!".format(password_list)) return False elif not exists(login_list): bc.err("User list : {} does not exist!".format(login_list)) return False else: return 'double' elif password_list and user: if not exists(password_list): bc.err("Password list : {} does not exist!".format(password_list)) return False else: return "password" elif login_list and password: if not exists(login_list): bc.err("User list : {} does not exist!".format(login_list)) return False else: return "user" else: bc.err( "No valid brute force options. Try supplying a userlist, passwordlist or both." ) return
def check_config(args, config): """Parse all our settings and return sanitised hook information, also check for argument and config file correct-ness""" # Work out what hook is being used and report if args.web_hook_url: job_hook = args.web_hook_url nm = job_hook else: try: nm = config[ 'default_hook'] if args.web_hook == 'default' else args.web_hook job_hook = config['hook_urls'][nm] except Exception as e: bcolors.err( "Error parsing webhook from config file:\n{}".format(e)) bcolors.warn("Exiting") exit() # Get user information from config try: job_user = config['instance_info'] except Exception as e: bcolors.err("Error getting User Config:\n{}".format(e)) bcolors.warn("Continuing without user information") job_user = None return nm, job_hook, job_user
def get_crack_mode(login_list, password_list, user, password): #Check files exist and set mode if password_list and login_list: if not exists(password_list): bc.err("Password list : {} does not exist!".format(password_list)) return False elif not exists(login_list): bc.err("User list : {} does not exist!".format(login_list)) return False else: return 'double' elif password_list and user: if not exists(password_list): bc.err("Password list : {} does not exist!".format(password_list)) return False else: return "password" elif login_list and password: if not exists(login_list): bc.err("User list : {} does not exist!".format(login_list)) return False else: return "user" else: bc.err("No valid brute force options. Try supplying a userlist, passwordlist or both.") return
def knock(host, ports, syn, default_proto, delay, verbose): for port in ports: #Handle tcp vs udp settings, either getting from global or port-specific setting if len(port.split(':')) == 2: port, proto = port.split(':') else: proto = default_proto #Now we're rid of proto, convert ports to integer try: port = int(port) except: bc.info("Unexpected error in port integer conversion:", sys.exc_info()[0]) raise if verbose: bc.info("Hitting Port {} with Proto {}".format( port, proto.upper())) if proto.lower() == "tcp" and not syn: result = tcp_connect(host, port) elif proto.lower() == "tcp": result = send_syn(host, port) elif proto.lower() == "syn": result = send_syn(host, port) elif proto.lower() == "udp": result = send_udp(host, port, b"") else: bc.err("Improper protocol '{}' set for port {}.".format( proto, port)) #Wait if delay > 0: time.sleep(delay) return result
def get_config(config_file): try: with open(config_file, 'r') as y: config = yaml.load(y, Loader=yaml.FullLoader) except Exception as e: bcolors.err("Error getting yaml configuration:\n{}".format(e)) bcolors.warn("Exiting") exit() return config
def send_syn(host, port): syn_response = None try: #Send it, no waiting! syn_response = sr(IP(dst=host) / TCP(dport=port, flags='S'), timeout=0) except Exception as e: bc.err("Could not send SYN to {}:{} : \n{}".format(host, port, e)) bc.warn("Check you have permissions to craft packets.") bc.err("Exiting.") sys.exit(0) #TODO validate Syn response and return 0 open, or 1 for closed/filtered return syn_response
def check_root(): if os.getuid() != 0: bc.err( "You're not running at root, you may not be able to knock properly." ) decision = 'decision_placeholder' while decision != "y" or decision != "n": decision = input("Would you like to continue anyway?(y/n)").lower() if decision.lower() == "n": sys.exit(0) elif decision.lower() == 'y': break
def tcp_connect(host, port): try: #Instantiate socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setblocking(False) #Timeouts are bad socket_addr = (host, port) #Setting up socket address result = s.connect_ex(socket_addr) if not s.connect_ex(socket_addr): return 0 #select.select([s], [s], [s], self.timeout) #Close socket s.close() except: bc.err("Could not TCP connect to host on port {}.".format(port)) return 1
def main(): #CLI Parsing - simple and dirty: if len(argv[1:]) != 1: app = basename(__file__) print("Usage: {} [number]".format(app)) exit(0) #Set up variables from CLI try: num = int(argv[1]) except: bc.err('Cannot process argument. Is your input an integer?') exit(0) if is_prime(num): bc.success('Yes, {} is prime!'.format(num), True) else: bc.info('No, {} is not prime, sorry!'.format(num), True)
def format_hash(hash_string, hash_dict): """Takes the input hash string from our file and rationalises it into the algo salt, digest and if applicable, iterations for HMAC.""" # We know mosquitto_passwd bans colons in the name and B64 is safe, so split user, hash_info = hash_string.split(":") if hash_info.count("$") == 4: junk, morejunk, salt, iterations, digest = hash_info.split("$") hash_type = 'pw_sha512_pbkdf2' elif hash_info.count("$") == 3: junk, morejunk, salt, digest = hash_info.split("$") hash_type = 'sha512' iterations = "1" else: bc.err("Error parsing hash - bad format:\n{}".format(hash_string)) exit(0) return [hash_type, b64decode(salt), digest, user, iterations]
def main(): args = get_args() print_banner() check_root() #Set scan type, remove default TCP connect if Syn Scan #Also setup default protocols and TCP flags (if applicable) if args.syn: args.tcp_connect = False if args.udp: default_proto = "udp" else: default_proto = "tcp" #Format ports into list, check number of ports first if len(args.knock_ports.split(',')) < 2: bc.err("Error parsing knock ports!\t" + bc.UNDERLINE + \ "Did you supply comma delimited ports?" + bc.ENDC) sys.exit(0) else: knock_ports = args.knock_ports.split(',') #If not brute, knock if not args.brute: if args.verbose: bc.success("Starting knock against ports: {}".format(knock_ports)) knock(args.host, knock_ports, args.syn, default_proto, args.delay, args.verbose) else: #BRUTE! bc.info("Bruting...") #If port to test - NOTE syn set to False, because we're looking for connection if args.target_port and knock(args.host, [args.target_port], False, \ default_proto, args.delay, args.verbose) == 0: bc.success("Knock complete - {}, test port open!".format( bc.bold_format("success"))) elif args.target_port: bc.err( "Knock complete - {} - test port filtered or closed... BEWARE UDP." .format(bc.bold_format("Failure"))) else: bc.info("Knock complete.")
def send_udp(host, port, message): #Todo - consider ICMP dest unreach as a filtered option try: #Instantiate socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) socket_addr = (host, port) #Setting up socket address data = b'/?help\n' s.sendto(data, socket_addr) #Test for UDP response - Quick and dirty s.settimeout(5) try: s.recvfrom(1024) return 0 except: return 1 #Close socket s.close() except: bc.err("Could not send UDP packet to host on port {}.".format(port))
def single_crack(bruter, single, single_first, login_q, len_q): i = 0 try: n_bruter = file_len(bruter) if single_first: bc.info("Attempting login for 1 user and {} passwords.".format(n_bruter), True) else: bc.info("Attempting login for {} users and 1 password.".format(n_bruter), True) len_q.put(n_bruter) #For each line in the file, bang it in the queue with open(bruter, 'r', encoding='latin-1') as bl: #with open(bruter, 'r', encoding='utf-8') as bl: for b in bl: b = b.strip() if not b: continue i+=1 if single_first: login_q.put([single, b]) else: login_q.put([b, single]) except UnicodeDecodeError as e: bc.err("Error decoding on wordlist line {}\n{}.".format(i, e)) bc.warn("Skipping guess") except BrokenPipeError as e: bc.err("Error communicating between processes : {}".format(e)) bc.info("Continuing") except ConnectionResetError as e: bc.err("Error communicating between processes : {}".format(e)) bc.info("Continuing") except KeyboardInterrupt: return
def double_crack(login_list, password_list, login_q, len_q): i = 0 j = 0 try: n_login = file_len(login_list) n_pass = file_len(password_list) bc.info("Attempting login for {} users and {} passwords.".format(n_login, n_pass), True) len_q.put(n_login*n_pass) #For each line in the file, bang it in the queue with open(login_list, 'r', encoding='latin-1') as ul: for u in ul: u = u.strip() if not u: continue i += 1 with open(password_list, 'r', encoding='latin-1') as pl: for p in pl: p = p.strip() if not p: continue j += 1 login_q.put([u, p]) except UnicodeDecodeError as e: bc.err("Error decoding at login_list line {} & password_list line {}\n{}.".format(i,j, e)) bc.warn("Skipping guess") except BrokenPipeError as e: bc.err("Error communicating between processes : {}".format(e)) bc.info("Continuing") except ConnectionResetError as e: bc.err("Error communicating between processes : {}".format(e)) bc.info("Continuing") except KeyboardInterrupt: return
def main(): #Mega basic command line parsing will do fine for our purposes try: if len(sys.argv[1:]) == 1: addresses = scrape_emails(sys.argv[1]) if addresses is not None: bc.success("Found addresses :") for a in addresses: print("\t{}".format(a)) elif len(sys.argv[1:]) == 2: addresses = scrape_emails(sys.argv[1]) if addresses is not None and not exists(sys.argv[2]): with open(sys.argv[2], "w") as f: for address in addresses: f.write(address + '\n') elif addresses is not None and exists(sys.argv[2]): answer = 'placeholder' fmt_str = bc.blue_format( "[!] ", "- {} exists, overwrite, append or cancel [o/a/c]? :".format( sys.argv[2])) while answer.lower() not in ['o','a','c']: answer = input(fmt_str) if answer == 'c': bc.info("Exiting.") sys.exit(0) else: mode = 'w' if answer == 'o' else 'a' with open(sys.argv[2], mode) as f: for address in addanswerresses: f.write(address + '\n') else: app = basename(__file__) print('Usage: {} [target_url] [outfile (optional)]'.format(app)) except Exception as e: bc.err("Error parsing emails: {}".format(e))
def main(): #Setup initial variables args = get_args() #HTML Request Variables #Request data fmt_str = "{}={}&{}={}".format(args.user_param, "{}", args.pass_param, "{}") if args.extra_param: for a in args.extra_param: fmt_str = fmt_str + "&{}".format(a[0]) #Headers hdr = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246", "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language" : "en-US,en;q=0.5", "Accept-Encoding" : "gzip, deflate", "Referer" : args.url, "Content-Type" : "application/x-www-form-urlencoded", "Connection" : "close", } #Get crack mode crack_mode = get_crack_mode(args.login_list, \ args.password_list, args.login, args.password) #If there's a bad file provided or some other error in crack_mode derivation if not crack_mode : exit(0) #Instantiate workers m = multiprocessing.Manager() login_q = m.Queue() done_q = m.Queue() len_q = m.Queue() struck_gold = multiprocessing.Event() kill_flag = multiprocessing.Event() start_time = time() for i in range(args.threads): t = multiprocessing.Process(target=guesser, args=(args.url, fmt_str, hdr, \ login_q, args.success_match, args.success_exclude, \ kill_flag, struck_gold, done_q)) t.start() #Now we have mode, carry out attack in whatever way specified if crack_mode == 'double': #double_crack(args.login_list, args.password_list, login_q, len_q) t = multiprocessing.Process(target=double_crack, args=( args.login_list, args.password_list, login_q, len_q, )) elif crack_mode == 'user': #single_crack(args.login_list, args.password, False, login_q, len_q) t = multiprocessing.Process(target=single_crack, args=( args.login_list, args.password, False, login_q, len_q, )) elif crack_mode == 'password': #single_crack(args.password_list, args.login, True, login_q, len_q) t = multiprocessing.Process(target=single_crack, args=( args.password_list, args.login, True, login_q, len_q, )) else: bc.err("Brute force mode invalid - {}. Exiting.".format(crack_mode)) kill_flag.set() sleep(0.5) exit(0) bc.info("Workers initialised. Calculating effort required.") #Start the bruteforce thread, reading passwords into the worker queue t.start() #When available get the number of guesses n_guesses = len_q.get() #bc.info("guesses total : {}".format(n_guesses)) last_progress = 0.0 with progressbar.ProgressBar(max_value= n_guesses) as bar: while True: try: done = done_q.qsize() except Exception as e: bc.warn("Error when checking progress : {}".format(e)) bc.info("Continuing") progress = round( (done / n_guesses ) * 100 , 0) if struck_gold.is_set() and not args.cont: kill_flag.set() bc.info("Creds found, continue flag not set. Finishing.") break elif progress >= 100.0 and login_q.empty(): kill_flag.set() sleep(1) print() bc.info("Brute complete. Shutting down...") break else: #Just waiting for a mate bar.update(done) sleep(1) #Gracefully kill everything for p in multiprocessing.active_children(): p.join(0.5)
def main(): """ACtually do the bruting""" #Setup initial variables args = get_args() #SMB variables t = args.timeout #Get crack mode crack_mode = get_crack_mode(args.login_list, \ args.password_list, args.login, args.password) #If there's a bad file provided or some other error in crack_mode derivation if not crack_mode: exit(0) #Instantiate workers m = multiprocessing.Manager() login_q = m.Queue() done_q = m.Queue() len_q = m.Queue() struck_gold = multiprocessing.Event() kill_flag = multiprocessing.Event() start_time = time() for i in range(args.threads): t = multiprocessing.Process(target=guesser, args=(args.host,\ args.domain, args.port, login_q, args.timeout, kill_flag, \ struck_gold, done_q)) t.start() #Now we have mode, carry out attack in whatever way specified if crack_mode == 'double': double_mode = double_crack if not args.spray else spray #double_crack(args.login_list, args.password_list, login_q, len_q) t = multiprocessing.Process(target=double_mode, args=( args.login_list, args.password_list, login_q, len_q, )) elif crack_mode == 'user': #single_crack(args.login_list, args.password, False, login_q, len_q) t = multiprocessing.Process(target=single_crack, args=( args.login_list, args.password, False, login_q, len_q, )) elif crack_mode == 'password': #single_crack(args.password_list, args.login, True, login_q, len_q) t = multiprocessing.Process(target=single_crack, args=( args.password_list, args.login, True, login_q, len_q, )) else: bc.err("Brute force mode invalid - {}. Exiting.".format(crack_mode)) kill_flag.set() sleep(0.5) exit(0) bc.info("Workers initialised. Calculating effort required.") #Start the bruteforce thread, reading passwords into the worker queue t.start() #When available get the number of guesses n_guesses = len_q.get() #bc.info("guesses total : {}".format(n_guesses)) last_progress = 0.0 with progressbar.ProgressBar(max_value=n_guesses) as bar: while True: try: done = done_q.qsize() except Exception as e: bc.warn("Error when checking progress : {}".format(e)) bc.info("Continuing") progress = round((done / n_guesses) * 100, 0) if struck_gold.is_set() and not args.cont: kill_flag.set() bc.info("Creds found, continue flag not set. Finishing.") break elif progress >= 100.0 and login_q.empty(): kill_flag.set() sleep(1) print() bc.info("Brute complete. Shutting down...") break else: #Just waiting for a mate bar.update(done) sleep(1) #Gracefully kill everything for p in multiprocessing.active_children(): p.join(0.5)
if struck_gold.is_set() and not args.cont: kill_flag.set() bc.info("Creds found, continue flag not set. Finishing.") break elif progress >= 100.0 and login_q.empty(): kill_flag.set() sleep(1) print() bc.info("Brute complete. Shutting down...") break else: #Just waiting for a mate bar.update(done) sleep(1) #Gracefully kill everything for p in multiprocessing.active_children(): p.join(0.5) #login_q.close() #login_q.join_thread() if __name__ == '__main__': try: main() except KeyboardInterrupt: bc.err("Keyboard interrupt.Exiting.") for p in multiprocessing.active_children(): p.join(0.5)
def main(): """Do the main lifting!""" # Configuration and config stuff args = get_args() if args.config == 'resources/discordnotify.yml': config_file = dirname(realpath(__file__)) + \ '/resources/discordnotify.yml' config = get_config(config_file) hook_name, hook, user = check_config(args, config) bcolors.info("Executing job: {}".format(bcolors.bold_format(args.command)), strong=True) #Create main webhook for proc completion wh = DiscordWebhook(url=hook, \ content="You've just started a job. Brace for updates...",\ username=user['username']) embed = DiscordEmbed(title="Process running",\ description="Full command line: {}".format(args.command), color=242424) if user['image']: embed.set_author(name="Job: {}".format(args.command.split(' ')[0]), icon_url=user['image']) else: embed.set_author(name="Job: {}".format(args.command.split(' ')[0])) embed.set_footer( text="Sent with DiscordNotify by @blackf3ll - [email protected]") wh.add_embed(embed) sent_wh = wh.execute() #Pre-ampble and process start t1 = time() t2 = time() worker = False start_time = ctime() #Human friendly :) output = '' p = subprocess.Popen( args.command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,\ shell=True , encoding='utf-8', errors='replace') # Manage beat updates if args.beat: worker = True embed.add_embed_field(name="Job ongoing", value="No updates yet...", inline=False) stdout_q = multiprocessing.Queue() stdout_worker = multiprocessing.Process(target=stdout_reader, args=(p, stdout_q)) stdout_worker.start() while p.poll() == None: try: while not stdout_q.empty(): output += stdout_q.get() t3 = time() if round(t3 - t2) >= args.beat: t2 = int(t3) # update embed summary data with stdout summary and time info embed.fields[0]['value'] = \ "Started: {} Elapsed : {}s Output summary:\n{}".format( start_time, round(t3-t1),trim_output( output, config['instance_info']['max_embed_lines'])) wh.edit(sent_wh) # and send it except Exception as e: bcolors.err("Error sending update:\n{}".format(e)) # Mop up any un-read stdout and print to console output += p.stdout.read() #.decode() duration = round(time() - t1) print(output) #Configure final report & embed in webhook was_error = "with errors" if p.returncode != 0 else "without errors" embed.add_embed_field(name="Process Complete", value="Completed {} \ (exit code {}) in {} Seconds".format(was_error, p.returncode, duration), inline=False) if output: out_summary = trim_output(output, config['instance_info']['max_embed_lines']) else: out_summary = "No data on STDOUT or STDERR." embed.add_embed_field(name="Stdout Summary", value=out_summary, inline=False) # Add any requested image - TODO - fix this so it works - add to file attachment? if args.image: embed.set_thumbnail(url='attachment://{}'.format(args.image)) # Now send try: wh.edit(sent_wh) except Exception as e: bcolors.err("Failed to send update to Discord:\n{}".format(e)) # Send any file on afterwards, to avoid conflictings file space/embed requirements if args.file: # Use a fresh webhook to avoid API limits and issues with large embeds filewh = DiscordWebhook(url=hook, \ content="Here's the associated file for your job: {}.".format( args.command), username=user['username']) try: with open(args.file, "rb") as f: filewh.add_file(file=f.read(), filename=args.file) filewh.execute() except Exception as e: bcolors.err("Couldn't attach file : {} :\n{}".format(args.file, e)) # Worker process cleanup if worker: stdout_worker.terminate() stdout_worker.join(5)