def parse_command(cmd): global slow_stop_flag if cmd == 's': Cracker.print_status() elif cmd == 'q': Comunicator.printer("Stopping...", reprint=False) fast_stop() elif cmd == 'f': slow_stop_flag = True Comunicator.finished = True Comunicator.printer( "Will finnish current job and stop. Press 'd' to cancel.") elif cmd == 'd': if Comunicator.finished: slow_stop_flag = False Comunicator.finished = False Comunicator.printer( "Finish command cancelled. Will continue working.") elif Comunicator.interactive: if cmd == 'p': # TODO if finished pause might not work... Comunicator.paused = True Comunicator.printer("Pause command sent to hashcat") # TODO send pause command elif cmd == 'r': # TODO if process stops resume might not work Comunicator.paused = False Comunicator.printer("Resume command sent to hashcat") # TODO send resume command elif cmd == 'c': # TODO implement checkpoint command pass # checkpoint
def stopwork(self, suppress_stdout=False): """ Stop current job :return: True - An error occurred None - Current job stopped :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "stopwork" Comunicator.info_logger("Stopping work from '%s'" % url) response = None try: response = requests.post(url, data={"apikey": self.apikey}, timeout=10) except requests.exceptions.ConnectionError: raise Requester.ServerDown except requests.exceptions.Timeout: Configuration.log_fatal("Backend is unresponsive") if response.status_code == 502: raise Requester.ServerDown _, err = Requester._decode_json(response) if err != "": msg = "Error stopping work '%s'" % err if suppress_stdout: Comunicator.error_logger(msg) else: self.err_printer(msg) return True return None
def getmissing(self): """ Get missing capabilities :return: True - An error occurred [{capability}] - List of capabilities :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "getmissing" Comunicator.info_logger("Getting missing capabilites at '%s'" % url) response = None try: response = requests.post(url, json={ "apikey": self.apikey, "capabilities": Configuration.capabilities }, timeout=10) except requests.exceptions.ConnectionError: raise Requester.ServerDown except requests.exceptions.Timeout: Comunicator.fatal_regular_message("Backend is unresponsive") if response.status_code == 502: raise Requester.ServerDown data, err = Requester._decode_json(response) if err != "": self.err_printer( "Error while retrieving missing capabilites '%s'" % err) return True return data
def process_result(): # Disable communicator until we start another job Comunicator.disable() # Check if process exited cleanly Cracker.crt_process.check_clean_exit() show_stdout = list( filter( None, SingleProcess(Cracker.attack_command + " --show").split_stdout())) password = "" # Check if we cracked something! if len(show_stdout) != 0: for line in show_stdout: cracked_obj = Configuration.hashcat_show_regex.match(line) die( cracked_obj is None, "REGEX error! could not match the --show line:%s" % show_stdout) password = cracked_obj.group(1) Cracker.safe_send_result(password) Cracker.clean_variables()
def _force_cleanup(self): try: if self.fst_proc and self.fst_proc.poll() is None: self.interrupt(self.fst_proc, self.fst_cmd) if self.snd_proc and self.snd_proc.poll() is None: self.interrupt(self.snd_proc, self.snd_cmd) # Close both processes writing pipe if they are still open self.fst_err_w = DoubleProcess._close_helper( self.fst_err_w)[0] # Stops fst_err_reader_thread self.snd_err_w = DoubleProcess._close_helper( self.snd_err_w)[0] # Stops snd_err_reader_thread self.snd_out_w = DoubleProcess._close_helper( self.snd_out_w)[0] # Stops snd_out_reader_thread # Close interprocess pipe if it not killed yet self.comm_r = DoubleProcess._close_helper(self.comm_r)[0] self.comm_w = DoubleProcess._close_helper(self.comm_w)[0] # Join threads if they are still running. Stopping the threads also closes the respective pipes self.fst_err_reader_thread = DoubleProcess._join_helper( self.fst_err_reader_thread)[0] self.snd_err_reader_thread = DoubleProcess._join_helper( self.snd_err_reader_thread)[0] self.snd_out_reader_thread = DoubleProcess._join_helper( self.snd_out_reader_thread)[0] # The reading ends of the pipes were closed by the threads self.snd_err_r = self.snd_out_r = self.fst_err_r = None except AttributeError as e: Comunicator.error_logger("Attribute error raised %s" % e) pass
def checkfile(self, filename): """ Check if a capability can be downloaded :return: True - An error occurred None - The file can be downloaded :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "checkfile" Comunicator.info_logger("Checking if file '%s' exists at '%s'" % (filename, url)) response = None try: response = requests.post(url, data={ "apikey": self.apikey, "file": filename }, timeout=10) except requests.exceptions.ConnectionError: raise Requester.ServerDown except requests.exceptions.Timeout: Comunicator.fatal_regular_message("Backend is unresponsive") if response.status_code == 502: raise Requester.ServerDown _, err = Requester._decode_json(response) if err != "": self.err_printer("Error downloading '%s': '%s'" % (filename, err)) return True return None
def getfile(self, filename, path): """ Download capability file :param filename: Filename of the capability to download :param path: Local relative path where to save the downloaded file :return: None - File downloaded :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "getfile" Comunicator.info_logger("Getting file '%s' from '%s'" % (filename, url)) try: with requests.post(url, data={ "apikey": self.apikey, "file": filename }, stream=True, timeout=10) as req: req.raise_for_status() with open(path, "wb+") as fd: for chunk in req.iter_content(chunk_size=8192): if chunk: fd.write(chunk) except requests.exceptions.ConnectionError: raise Requester.ServerDown except requests.exceptions.Timeout: Comunicator.fatal_regular_message("Backend is unresponsive") return None
def _force_cleanup(self): try: if self.proc and self.proc.poll() is None: self.interrupt(self.proc, self.cmd) # Stop ___hashcat_writer_thread as soon as possible (takes a bit because of the sleep(1)) self.stop_in_thread = True # Close both processes writing pipe if they are still open self.err_w = SingleProcess._close_helper( self.err_w)[0] # Stops err_reader_thread self.out_w = SingleProcess._close_helper( self.out_w)[0] # Stops out_reader_thread # Join threads if they are still running. Stopping the threads also closes the respective pipes self.in_writer_thread = SingleProcess._join_helper( self.in_writer_thread)[0] self.err_reader_thread = SingleProcess._join_helper( self.err_reader_thread)[0] self.out_reader_thread = SingleProcess._join_helper( self.out_reader_thread)[0] # The reading/writing ends of the pipes were closed by the threads self.err_r = self.out_r = self.in_w = None # Close the reading end of the stdin pipe self.in_r = SingleProcess._close_helper(self.in_r)[0] except AttributeError as e: Comunicator.error_logger("Attribute error raised %s" % e) pass
def sendeta(self, eta): """ Send eta for current :return: True - An error occurred None - Eta successfully sent :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "sendeta" Comunicator.info_logger("Sending eta to '%s': '%s'" % (url, eta)) response = None try: response = requests.post(url, data={ "apikey": self.apikey, "eta": eta }, timeout=10) except requests.exceptions.ConnectionError: raise Requester.ServerDown except requests.exceptions.Timeout: Comunicator.fatal_regular_message("Backend is unresponsive") if response.status_code == 502: raise Requester.ServerDown _, err = Requester._decode_json(response) if err != "": self.err_printer("Error sending eta '%s'" % err) return True return None
def interrupt(process, cmd, wait_time=2.0): try: pid = process.pid if type(cmd) is list: cmd = ' '.join(cmd) Comunicator.info_logger('sending interrupt to PID %d (%s)' % (pid, cmd)) if wait_time == 0.0: os.kill(pid, signal.SIGTERM) process.terminate() return os.kill(pid, signal.SIGINT) start_time = time.time() # Time since Interrupt was sent while process.poll() is None: # Process is still running time.sleep(0.1) if time.time() - start_time > wait_time: # We waited too long for process to die, terminate it. Comunicator.info_logger( 'Waited > %0.2f seconds for process to die, killing it' % wait_time) os.kill(pid, signal.SIGTERM) process.terminate() break except OSError as e: if 'No such process' in str(e): return raise e # process cannot be killed
def update_eta(): new_eta_dict = Cracker.crt_process.get_dict() if Cracker.eta_dict is None: is_changed = True else: is_changed = False for key, value in new_eta_dict.items(): if value != Cracker.eta_dict[key]: is_changed = True break # If no changes were made no updates are necessary if not is_changed: return Cracker.eta_dict = new_eta_dict # TODO This message is wrongly displayed right around when a hashcat process stops eta = "Error calculating ETA" # TODO maksfile eta is not properly calculated because hashcat outputs eta for current queue # TODO each mask has it's own queue # TODO implement rule 5 with hashcat only if Cracker.crt_rule["type"] == "filemask_hashcat" or Cracker.crt_rule[ "wordsize"] <= 0: eta = "No ETA available" elif Cracker.eta_dict["progress"] == -1 and Cracker.eta_dict[ "eta"] == "": eta = "Cracking process starting" elif Cracker.eta_dict["eta"] != "" and Cracker.eta_dict[ "eta"] != "(0 secs)": eta = Cracker.eta_dict["eta"] elif Cracker.eta_dict["speed"] != -1 and Cracker.eta_dict[ "progress"] != -1: # For rules generated at runtime with variable base dictionary length we cannot calculate ETA speed = Cracker.eta_dict["speed"] if speed != 0: if Cracker.crt_rule["wordsize"] < Cracker.eta_dict["progress"]: Comunicator.error_logger( "Dict size (%d) seems less than current attacked (%d)" % (Cracker.crt_rule["wordsize"], Cracker.eta_dict["progress"])) eta_seconds = (Cracker.crt_rule["wordsize"] - Cracker.eta_dict["progress"]) / speed eta = Cracker.seconds_to_time(eta_seconds) else: eta = "Generating dict..." # Check if the eta already has the desired value in order to avoid an update # Usually happens when 'Cracker.crt_rule["wordsize"] <= 0' if Cracker.old_eta == eta: return Cracker.old_eta = eta try: Cracker.req.sendeta(eta) except Cracker.req.ServerDown: pass
def die(condition, message): if condition: msg = "File '%s', line %s, in %s: '%s'" % \ (inspect.getmodule(inspect.stack()[1][0]).__file__, inspect.currentframe().f_back.f_lineno, inspect.stack()[1][3], message) Comunicator.dual_printer(Comunicator.logger.critical, msg) sys.exit(-1)
def process_result(): # Disable communicator until we start another job Comunicator.disable() # Check if process exited cleanly if Cracker.crt_process is not None: Cracker.crt_process.check_clean_exit() show_stdout = list( filter( None, SingleProcess(Cracker.attack_command + " --show").split_stdout())) password = "" # Check if we cracked something! if len(show_stdout) != 0: for line in show_stdout: cracked_obj = Configuration.hashcat_show_regex.match(line) die( cracked_obj is None, "REGEX error! could not match the --show line:%s" % show_stdout) password = cracked_obj.group(1) msg = "[FAIL] Password for '%s' is not contained in rule '%s'" %\ (Cracker.mac_ssid_job, Cracker.crt_rule["name"]) if len(password) > 7: msg = "[SUCCESS] The password for '%s' is '%s'" % ( Cracker.mac_ssid_job, password) Comunicator.printer(msg) Cracker.safe_send_result(password) Cracker.clean_variables()
def safe_send_result(password): written_flag = False while True: try: res = Cracker.req.sendresult(password) die( res is True, "Sending result '%s' for job '%s' produced an error" % (password, Cracker.mac_ssid_job)) if os.path.exists(Configuration.save_result_filename): os.remove(Configuration.save_result_filename) if res is False: Comunicator.warning_logger( "Server cancelled last job. Requesting stopwork.") Cracker.req.stopwork() break except Cracker.req.ServerDown: if not written_flag: msg = "Trying to send result '%s' for last job but the server is unreachable" % password Comunicator.dual_printer(Comunicator.logger.warning, msg) written_flag = True with open(Configuration.save_result_filename, "w") as fp: fp.write(password) sleep(10)
def print_status(): def pad(msg): width = 13 return msg.ljust(width, '.') + ": " def human_format(num): magnitude = 0 while abs(num) >= 1000: magnitude += 1 num /= 1000.0 # add more suffixes if you need them return '%.1f%sH/s' % (num, ['', 'K', 'M', 'G', 'T', 'P' ][magnitude]) def space_format(num): return f'{num:,}' hashcat_status = Cracker.crt_process.get_dict() output = pad("Current rule") + "%s\n" % Cracker.crt_rule["name"] eta = hashcat_status["eta"] if hashcat_status["eta"] == "": eta = "Calculating" output += pad("Eta") + "%s\n" % eta if hashcat_status["speed"] > 0: if len(hashcat_status["devices"]) > 2: total_speed = -1 for idx, speed in enumerate( sorted(hashcat_status["devices"].keys())): if total_speed == -1: total_speed = speed continue output += pad( "Speed #%d" % idx) + "%s\n" % human_format(speed) if total_speed != -1: output += pad( "Total Speed") + "%s\n" % human_format(total_speed) else: output += pad("Total Speed") + "%s\n" % human_format( hashcat_status["speed"]) if hashcat_status["progress"] > 0: progress_len = len(space_format(Cracker.crt_rule["wordsize"])) output += pad("Progress") + "%s/%s\n" % (space_format( hashcat_status["progress"]).rjust( progress_len, ' '), space_format(Cracker.crt_rule["wordsize"])) if output.endswith("\n"): output = output[:-1] Comunicator.printer(output)
def test_capabilities(): """ Test cracking capabilities and run dummy programs to check for errors Removes capabilities from 'capabilities' if the test fails :return: None """ if "john" in Configuration.capabilities: res = Configuration.test_john() if res is not True: del Configuration.capabilities["john"] Comunicator.dual_printer( Comunicator.logger.warn, "John is currently not available:\n%s" % res)
def _reap(self, now=False): if self.reaped: return True if now and self.proc.poll() is None: # Wait for the first process to stop executing self.proc.wait() if self.proc.poll() is not None: # Stop ___hashcat_writer_thread as soon as possible (takes a bit because of the sleep(1)) self.stop_in_thread = True # This stops the ___hashcat_writer_thread # The process stopped executing, close it's write pipes self.err_w = SingleProcess._close_helper( self.err_w)[0] # Stops err_reader_thread self.out_w = SingleProcess._close_helper( self.out_w)[0] # Stops out_reader_thread # After we closed the writing end of the pipe _all_reader_thread should stop self.err_reader_thread = SingleProcess._join_helper( self.err_reader_thread)[0] self.out_reader_thread = SingleProcess._join_helper( self.out_reader_thread)[0] # This process might take a bit to shutdown because it has a sleep(1) # Mark stop_in_thread as true ASAP in order to give the thread time to stop self.in_writer_thread = SingleProcess._join_helper( self.in_writer_thread)[0] # Convert error from list to string self.err = "".join(self.err) # Mark the second process as completely stopped self.reaped = True if self.critical and self.proc.poll() != 0: # Second process could be hashcat which sometimes returns 1 but no error if SingleProcess.command_is_hashcat( self.cmd) and self.proc.poll() != 1: Comunicator.debug_logger( "Process %s exited with status %d. Stderr:\n%s" % (self.cmd, self.proc.poll(), self.err)) self._force_cleanup() Comunicator.fatal_debug_printer( "Fatal error encountered in critical single process. See logs." ) return True return False
def _reap_snd(self, now=False): if self.snd_reaped: return True if now and self.snd_proc.poll() is None: self.snd_proc.wait() # self.snd_out, _ = self.snd_proc.get_output() if self.snd_proc.poll() is not None: # Process stopped so close the writing end of the pipes self.snd_err_w.close() self.snd_err_w = None self.snd_out_w.close() self.snd_out_w = None # Cleanup the reading pipe self.comm_r.close() self.comm_r = None # After we closed the writing end of the pipe _all_reader_thread should stop self.snd_err_reader_thread.join() self.snd_err_reader_thread = None self.snd_out_reader_thread.join() self.snd_out_reader_thread = None # Convert error from list to string self.snd_err = "".join(self.snd_err) # Mark the second process as completely stopped self.snd_reaped = True if self.critical and self.snd_proc.poll() != 0: # Second process could be hashcat which sometimes returns 1 but no error if DoubleProcess.command_is_hashcat( self.snd_cmd) and self.snd_proc.poll() != 1: Comunicator.debug_logger( "Second process %s exited with status %d. Stderr:\n%s" % (self.snd_cmd, self.snd_proc.poll(), self.snd_err)) self._force_cleanup() Comunicator.fatal_debug_printer( "Fatal error encountered in critical second process. See logs." ) return True return False
def resume_work(): if os.path.exists(Configuration.save_result_filename): with open(Configuration.save_result_filename) as fp: password = fp.read() Cracker.safe_send_result(password) return while True: try: Cracker.req.stopwork(suppress_stdout=True) break except Cracker.req.ServerDown: Comunicator.printer(Requester.DownMessage) sleep(10) return
def fast_stop(): if Cracker.crt_process is not None: Comunicator.info_logger("Killing running process %s" % Cracker.crt_process.get_command()) # Kill currently running process Cracker.crt_process.terminate() # Clean current varibles so all tempfiles are deleted Cracker.clean_variables() try: if Cracker.req is not None: Cracker.req.stopwork() except Cracker.req.ServerDown: pass Comunicator.stop() sys.exit(0)
def start_cracking(work): Cracker.mac_ssid_job = "%s-%s" % (work["handshake"]["mac"], work["handshake"]["ssid"]) msg = "Running '%s' with rule '%s'" % (Cracker.mac_ssid_job, work["rule"]["name"]) Comunicator.enable(interactive=False) Comunicator.dual_printer(msg, Configuration.logger.info) _, Cracker.path_temp_file = mkstemp(prefix="psknow_crack") if work["handshake"]["file_type"] == "16800": with open(Cracker.path_temp_file, "w") as fd: fd.write(work["handshake"]["data"]) else: with open(Cracker.path_temp_file, "wb") as fd: fd.write(b64decode(work["handshake"]["data"].encode("utf8"))) # Memorize attack type - we need it to decode the output attack_type = work["handshake"]["handshake_type"] Cracker.crt_rule = work["rule"] attacked_file = Cracker.path_temp_file # Get commands needed to run hashcat generator_command, Cracker.attack_command, Cracker.scrambler =\ Cracker.get_attack_command(Cracker.crt_rule, attack_type, attacked_file, work["handshake"]["ssid"]) Configuration.logger.info( "Trying rule %s on '%s-%s'" % (Cracker.crt_rule["name"], work["handshake"]["mac"], work["handshake"]["ssid"])) if Cracker.is_potfile_duplicated(Cracker.attack_command): msg = "Duplication for %s happened. It is already present in potfile!" % Cracker.mac_ssid_job Configuration.dual_print(Configuration.logger.critical, msg) fast_stop() if generator_command == "": Cracker.crt_process = SingleProcess(Cracker.attack_command) else: Cracker.crt_process = DoubleProcess(generator_command, Cracker.attack_command)
def do_work(): # Something just finished! if Cracker.crt_process is not None and Cracker.crt_process.isdead(): Cracker.process_result() # Process is still running - update eta if Cracker.crt_process is not None: Cracker.update_eta() return if slow_stop_flag: Comunicator.info_logger( "Slow shutdown signal received - shutting down!") sys.exit(0) # Before getting more work make sure we are up to date Cracker.complete_missing() # Test capabilities once if not Cracker.capabilities_tested: Configuration.test_capabilities() Cracker.capabilities_tested = True # Nothing is running - getting more work try: work = Cracker.req.getwork() except Cracker.req.ServerDown: Comunicator.printer(Comunicator.printer(Requester.DownMessage)) return die(work is True, "A server side error occured while getting work!") # No work to be done right now if work is None: Comunicator.printer( "No work to be done, checking in 10 seconds again.") return # Redundant check if work is False: Comunicator.warning_logger("Capabilities out of date!") return # Make status seem a bit more responsive Cracker.old_eta = "Cracking process starting" Cracker.start_cracking(work)
def run(): Configuration.initialize() Cracker.crt_workload = 4 # TODO get value from parameters, adjust from keyboard signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) Cracker.req = Requester(Configuration.apikey, Comunicator.error_printer) Cracker.resume_work() Comunicator.initialize() Comunicator.printer("Cracker initialized", reprint=False) # Disable terminal echo os.system("stty -echo") try: last_time = None while True: now_time = datetime.now() if last_time is None or (now_time - last_time).total_seconds() > 10: last_time = now_time Cracker.crack_existing_handshakes() cmd = Comunicator.get_command() if cmd is not None: Cracker.parse_command(cmd) sleep(0.1) except Exception as e: Configuration.dual_print( Configuration.logger.critical, "Caught unexpected exception: '%s'" % (traceback.format_exc())) Cracker.clean_variables() die(True, e) finally: # Reenable terminal echo os.system("stty echo") pass
class SwitcherCom(object): cmd_off = 'OFF' cmd_on = 'ON' cmd_status = 'STATUS' cmd_reload = 'RELOAD' cmd_gpio_pin = 'GPIO{0:02d}' state_on = 'ON' state_off = 'OFF' state_unknow = None resp_error = 'ERROR' resp_timeout = 'TIMEOUT' resp_ok = 'OK' resp_reloading = 'RELOADING' reps_configured = 'CONFIGURED' def __init__(self, log): self._log = log self.comm = Comunicator( Comunicator.MODE_CLIENT, SWITCHER_PIPE_IN, SWITCHER_PIPE_OUT, log ) def send_command(self, command): response = None if self.comm.send_message(os.getpid(), command, timeout=15): self._log.info("Inviato comando %s", command) response = self.comm.read_message() else: return self.resp_error return response[1] def is_response_ok(self, response): return response[0:2] == self.resp_ok def get_response_msg(self, response): return response[3:].strip()
def getwork(self): """ Send a request for work to the server :return: None - Nothing can be down with capabilities False - A sha1 has does not match, capabilities need updating True - An error occurred {data} - Work data requested :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "getwork" Comunicator.info_logger("Requesting work from '%s'" % url) response = None try: response = requests.post(url, json={ "apikey": self.apikey, "capabilities": Configuration.capabilities }, timeout=10) except requests.exceptions.ConnectionError: raise Requester.ServerDown except requests.exceptions.Timeout: Comunicator.fatal_regular_message("Backend is unresponsive") if response.status_code == 502: raise Requester.ServerDown data, err = Requester._decode_json(response) if err != "": if err == Configuration.cap_updated: return False if err == Configuration.no_work_message: return None self.err_printer("Error retrieving data from server '%s'" % err) return True return data
def complete_missing(): gather_flag = False try: missings = Cracker.req.getmissing() except Cracker.req.ServerDown: return die(missings is True, "Server side error occurred.") if missings is None: return for missing in missings: if missing["type"] == "program": Comunicator.info_logger("Please install program '%s'" % missing["name"]) elif missing["type"] in [ "dict", "maskfile", "generator", "john-local.conf" ]: Comunicator.dual_printer( Comunicator.logger.info, "Downloading '%s'..." % missing["path"]) gather_flag = True if "/" in missing["path"]: directory, filename = missing["path"].rsplit('/', 1) # Create directory if they do not exist os.makedirs(directory, exist_ok=True) else: filename = missing["path"] try: if Cracker.req.checkfile(filename) is None and \ Cracker.req.getfile(filename, missing["path"]) is None: Comunicator.dual_printer( Comunicator.logger.info, "Downloaded '%s'" % missing["path"]) if missing["type"] == "generator": os.chmod( missing["path"], stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) except Cracker.req.ServerDown: return else: Comunicator.warning_logger("Unknown missing type '%s'" % missing) if gather_flag: Configuration.gather_capabilities()
def _reap_fst(self, now=False): if self.fst_reaped: return True if now and self.fst_proc.poll() is None: # Wait for the first process to stop executing self.fst_proc.wait() if self.fst_proc.poll() is not None: # The first process stopped executing, close it's write pipes self.fst_err_w.close() self.fst_err_w = None self.comm_w.close() self.comm_w = None # After we closed the writing end of the err pipe _all_reader_thread should stop self.fst_err_reader_thread.join() self.fst_err_reader_thread = None # Convert error from list to string self.fst_err = "".join(self.fst_err) # Mark the first process as completely stopped self.fst_reaped = True # TODO this can be generic. If this becomes static the poll needs to be checked against None if self.critical and self.fst_proc.poll() != 0: Comunicator.error_logger( "First process %s exited with status %d. Stderr:\n%s" % (self.fst_cmd, self.fst_proc.poll(), self.fst_err)) self._force_cleanup() Comunicator.fatal_debug_printer( "Fatal error encountered in critical first process. See logs." ) return True return False
def pausework(self): """ Pause current job :return: True - An error occurred None - Current job paused :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "pausework" Comunicator.info_logger("Pausing work from '%s'" % url) try: response = requests.post(url, data={"apikey": self.apikey}) except requests.exceptions.ConnectionError: raise Requester.ServerDown if response.status_code == 502: raise Requester.ServerDown _, err = Requester._decode_json(response) if err != "": self.err_printer("Error pausing work '%s'" % err) return True return None
def load_sha1s(): """ To reduce startup time sha1's are stored in the file Configuration.sha1s_filename and only recalculated if the file has changed after the hash was calculated. This function loads the sha1 hashes along with the time when the hash was calculated into the variable Configuration.old_sha1s :return: None """ Configuration.old_sha1s = {} if not os.path.exists(Configuration.sha1s_filename): with open(Configuration.sha1s_filename, "w+") as _: return try: with open(Configuration.sha1s_filename) as fd: Configuration.old_sha1s = json.load(fd) except json.decoder.JSONDecodeError: return except Exception as e: Comunicator.fatal_debug_printer( "Error trying to load %s data: %s" % (Configuration.sha1s_filename, e))
def sendresult(self, password): """ Send results for current job :param password: password for the current job, can be "" :return: False - The job expired True - An error occurred None - Current job stopped :raises Requester.ServerDown: The server could not be reached """ url = Configuration.remote_server + "sendresult" Comunicator.info_logger("Sending result at '%s'" % url) response = None try: response = requests.post(url, data={ "apikey": self.apikey, "password": password }, timeout=10) except requests.exceptions.ConnectionError: raise Requester.ServerDown except requests.exceptions.Timeout: Comunicator.fatal_regular_message("Backend is unresponsive") if response.status_code == 502: raise Requester.ServerDown _, err = Requester._decode_json(response) if err != "": if err == Configuration.no_job_message: return False self.err_printer("Error while sending result '%s'" % err) return True return None
def start_cracking(work): Cracker.mac_ssid_job = "%s-%s" % (work["handshake"]["mac"], work["handshake"]["ssid"]) msg = "Running '%s' with rule '%s'" % (Cracker.mac_ssid_job, work["rule"]["name"]) Comunicator.enable(interactive=False) Comunicator.dual_printer(Comunicator.logger.info, msg) _, Cracker.path_temp_file = mkstemp(prefix="psknow_crack") if work["handshake"]["file_type"] == "16800": with open(Cracker.path_temp_file, "w") as fd: fd.write(work["handshake"]["data"]) else: with open(Cracker.path_temp_file, "wb") as fd: fd.write(b64decode(work["handshake"]["data"].encode("utf8"))) # Memorize attack type - we need it to decode the output attack_type = work["handshake"]["handshake_type"] Cracker.crt_rule = work["rule"] attacked_file = Cracker.path_temp_file # Get commands needed to run hashcat generator_command, Cracker.attack_command, Cracker.scrambler =\ Cracker.get_attack_command(Cracker.crt_rule, attack_type, attacked_file, work["handshake"]["ssid"]) Comunicator.info_logger( "Trying rule %s on '%s-%s'" % (Cracker.crt_rule["name"], work["handshake"]["mac"], work["handshake"]["ssid"])) if Cracker.is_already_cracked(Cracker.attack_command): Comunicator.warning_logger( "'%s' has already been cracked. Attempting to send result." % Cracker.mac_ssid_job) Cracker.process_result() return if generator_command == "": Cracker.crt_process = SingleProcess(Cracker.attack_command) else: Cracker.crt_process = DoubleProcess(generator_command, Cracker.attack_command)
class Switcher(Daemon): DEF_LOG_LEVEL = WARNING def __init__( self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', logfile='/dev/null', invert_state=False ): super(Switcher, self).__init__(pidfile, stdin, stdout, stderr, logfile) self.invert_state = invert_state def run(self): # Configuro le pipe di comunicazione self.comm = Comunicator( Comunicator.MODE_SERVER, SWITCHER_PIPE_IN, SWITCHER_PIPE_OUT, self.log) if self.invert_state: self.STATE_ON, self.STATE_OFF = GPIO.LOW, GPIO.HIGH self.log.debug( 'Stato ON -> GPIO.LOW (%s), Stato OFF -> GPIO.HIGH (%s)', GPIO.LOW, GPIO.HIGH) else: self.STATE_ON, self.STATE_OFF = GPIO.HIGH, GPIO.LOW self.log.debug( 'Stato ON -> GPIO.HIGH (%s), Stato OFF -> GPIO.LOW (%s)', GPIO.HIGH, GPIO.LOW) # Init GPIO Board self.log.debug( 'Inizializzazione GPIO: revisione %s', GPIO.RPI_REVISION) # Registro funzioni reload e uscita signal.signal(signal.SIGHUP, self._load_config) signal.signal(signal.SIGTERM, self._cleanup) state = self.STATE_OFF self.reset_state = True self.pin = None while True: if self.reset_state: # In attesa di configurazione pin GPIO self.pin = self._wait_for_gpio_pin() state = self.STATE_OFF self.reset_state = False # Attendo un nuovo comando msg = self.comm.read_message(None) cmd = msg[1] self.log.debug("Ricevuto comando: %s", cmd) if cmd == 'ON' or cmd == 'OFF': response = 'OK:%s' % (cmd) res = True if cmd == 'ON' and state != self.STATE_ON: res = self._set_pin_on(self.pin) elif cmd == 'OFF' and state != self.STATE_OFF: res = self._set_pin_off(self.pin) if not res: response = "ERROR" else: state = self.STATE_ON if cmd == 'ON' else self.STATE_OFF elif cmd == 'STATUS': response = 'OK:%s' % (self._get_pin_status(self.pin, state)) elif cmd == 'RELOAD': self.log.warning("Ricarico configurazione...") self.reset_state = True response = "OK:RELOADING" GPIO.cleanup() elif cmd == 'TIMEOUT': self.log.info("Timeout in lettura") continue else: response = 'ERROR' self.log.debug("Invio risposta: %s", response) # Attendo qualche istante per sincronizzare l'actuator time.sleep(0.5) self.comm.send_message(getpid(), response, timeout=15) def _load_config(self, signum, frame): self.log.warning( "Ricevuto segnale %s frame %s: ricarico configurazione", signum, frame) GPIO.cleanup() self.reset_state = True def _cleanup(self, signum, frame): self.log.warning( "Ricevuto segnale %s frame %s: uscita", signum, frame) GPIO.setwarnings(False) GPIO.cleanup() exit(0) def _set_pin_on(self, pin): return self._set_pin_state(pin, self.STATE_ON) def _set_pin_off(self, pin): return self._set_pin_state(pin, self.STATE_OFF) def _set_pin_state(self, pin, state): stato_raw = 'HIGH' if state == GPIO.HIGH else 'LOW' try: GPIO.output(pin, state) self.log.debug("Pin: %s impostato in %s", pin, stato_raw) ret = True except Exception as e: self.log.error( "Impossibile commutare pin %s in %s: %s", pin, stato_raw, repr(e)) ret = False return ret def _get_pin_status(self, pin, raw_state): state = 'ON' if raw_state == self.STATE_ON else 'OFF' self.log.debug("Pin: %s stato %s", pin, state) return state def _wait_for_gpio_pin(self): pin = None self.log.info("Attendo configurazione pin GPIO") while pin is None: msg = self.comm.read_message(None) gpio = msg[1] if 'GPIO' in gpio: try: pin = int(gpio[-2:]) # Modo numerazione pin: Broadcom's SoC GPIO.setmode(GPIO.BCM) # Init del relè default off GPIO.setup(pin, GPIO.OUT, initial=self.STATE_OFF) self.log.info('Configuro GPIO %s per Relè', pin) self.comm.send_message(getpid(), 'OK:CONFIGURED') except Exception as e: pin = None self.log.error( 'Impossibile inizializzare il pin GPIO %s', repr(e)) else: self.comm.send_message(getpid(), 'ERROR', timeout=5) self.log.warning('Ignorato messaggio %s', msg) return pin
def __init__(self, log): self._log = log self.comm = Comunicator( Comunicator.MODE_CLIENT, SWITCHER_PIPE_IN, SWITCHER_PIPE_OUT, log )
def run(self): # Configuro le pipe di comunicazione self.comm = Comunicator( Comunicator.MODE_SERVER, SWITCHER_PIPE_IN, SWITCHER_PIPE_OUT, self.log) if self.invert_state: self.STATE_ON, self.STATE_OFF = GPIO.LOW, GPIO.HIGH self.log.debug( 'Stato ON -> GPIO.LOW (%s), Stato OFF -> GPIO.HIGH (%s)', GPIO.LOW, GPIO.HIGH) else: self.STATE_ON, self.STATE_OFF = GPIO.HIGH, GPIO.LOW self.log.debug( 'Stato ON -> GPIO.HIGH (%s), Stato OFF -> GPIO.LOW (%s)', GPIO.HIGH, GPIO.LOW) # Init GPIO Board self.log.debug( 'Inizializzazione GPIO: revisione %s', GPIO.RPI_REVISION) # Registro funzioni reload e uscita signal.signal(signal.SIGHUP, self._load_config) signal.signal(signal.SIGTERM, self._cleanup) state = self.STATE_OFF self.reset_state = True self.pin = None while True: if self.reset_state: # In attesa di configurazione pin GPIO self.pin = self._wait_for_gpio_pin() state = self.STATE_OFF self.reset_state = False # Attendo un nuovo comando msg = self.comm.read_message(None) cmd = msg[1] self.log.debug("Ricevuto comando: %s", cmd) if cmd == 'ON' or cmd == 'OFF': response = 'OK:%s' % (cmd) res = True if cmd == 'ON' and state != self.STATE_ON: res = self._set_pin_on(self.pin) elif cmd == 'OFF' and state != self.STATE_OFF: res = self._set_pin_off(self.pin) if not res: response = "ERROR" else: state = self.STATE_ON if cmd == 'ON' else self.STATE_OFF elif cmd == 'STATUS': response = 'OK:%s' % (self._get_pin_status(self.pin, state)) elif cmd == 'RELOAD': self.log.warning("Ricarico configurazione...") self.reset_state = True response = "OK:RELOADING" GPIO.cleanup() elif cmd == 'TIMEOUT': self.log.info("Timeout in lettura") continue else: response = 'ERROR' self.log.debug("Invio risposta: %s", response) # Attendo qualche istante per sincronizzare l'actuator time.sleep(0.5) self.comm.send_message(getpid(), response, timeout=15)