def prince_keyspace(self, task, chunk): binary = "pp64." if Initialize.get_os() != 1: binary = "./" + binary + "bin" else: binary += "exe" full_cmd = binary + " --keyspace " + get_wordlist( update_files(task['attackcmd'], True).replace( task['hashlistAlias'], "")) if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') try: logging.debug("CALL: " + full_cmd) output = subprocess.check_output(full_cmd, shell=True, cwd="prince") except subprocess.CalledProcessError: logging.error("Error during PRINCE keyspace measure") send_error("PRINCE keyspace measure failed!", self.config.get_value('token'), task['taskId'], None) sleep(5) return False output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") keyspace = "0" for line in output: if not line: continue keyspace = line # as the keyspace of prince can get very very large, we only save it in case it's small enough to fit in a long, # otherwise we assume that the user will abort the task earlier anyway if int(keyspace ) > 9000000000000000000: # close to max size of a long long int return chunk.send_keyspace(-1, task['taskId']) return chunk.send_keyspace(int(keyspace), task['taskId'])
def preprocessor_keyspace(self, task, chunk): preprocessor = task.get_preprocessor() if preprocessor['keyspaceCommand'] is None: # in case there is no keyspace flag, we just assume the task will be that large to run forever return chunk.send_keyspace(-1, task.get_task()['taskId']) binary = preprocessor['executable'] if Initialize.get_os() != 1: binary = "./" + binary if not os.path.isfile(binary): split = binary.split(".") binary = '.'.join(split[:-1]) + get_bit() + "." + split[-1] full_cmd = binary + " " + preprocessor['keyspaceCommand'] + " " + update_files(task.get_task()['preprocessorCommand']) if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') try: logging.debug("CALL: " + full_cmd) output = subprocess.check_output(full_cmd, shell=True, cwd="preprocessor/" + str(task.get_task()['preprocessor'])) except subprocess.CalledProcessError: logging.error("Error during preprocessor keyspace measure") send_error("Preprocessor keyspace measure failed!", self.config.get_value('token'), task.get_task()['taskId'], None) sleep(5) return False output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") keyspace = "0" for line in output: if not line: continue keyspace = line # as the keyspace of preprocessors can get very very large, we only save it in case it's small enough to fit in a long, # otherwise we assume that the user will abort the task earlier anyway if int(keyspace) > 9000000000000000000: # close to max size of a long long int return chunk.send_keyspace(-1, task.get_task()['taskId']) return chunk.send_keyspace(int(keyspace), task.get_task()['taskId'])
def run_speed_benchmark(self, task): args = " --machine-readable --quiet --progress-only" args += " --restore-disable --potfile-disable --session=hashtopolis " args += update_files(task['attackcmd']).replace(task['hashlistAlias'], "../../hashlists/" + str(task['hashlistId'])) args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out" full_cmd = self.callPath + args if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') try: logging.debug("CALL: " + full_cmd) output = subprocess.check_output(full_cmd, shell=True, cwd=self.cracker_path) except subprocess.CalledProcessError as e: logging.error("Error during keyspace measure, return code: " + str(e.returncode)) send_error("Keyspace measure failed!", self.config.get_value('token'), task['taskId']) return 0 output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") sum = [0, 0] for line in output: if len(line) == 0: continue line = line.split(":") if len(line) != 3: continue sum[0] += int(line[1]) sum[1] += float(line[2]) return str(sum[0]) + ":" + str(sum[1])
def measure_keyspace(self, task, chunk): if 'usePrince' in task.get_task() and task.get_task()['usePrince']: return self.prince_keyspace(task.get_task(), chunk) elif 'usePreprocessor' in task.get_task() and task.get_task()['usePreprocessor']: return self.preprocessor_keyspace(task, chunk) task = task.get_task() # TODO: refactor this to be better code full_cmd = self.callPath + " --keyspace --quiet " + update_files(task['attackcmd']).replace(task['hashlistAlias'] + " ", "") + ' ' + task['cmdpars'] if 'useBrain' in task and task['useBrain']: full_cmd += " -S" if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') try: logging.debug("CALL: " + full_cmd) output = subprocess.check_output(full_cmd, shell=True, cwd=self.cracker_path) except subprocess.CalledProcessError as e: logging.error("Error during keyspace measure: " + str(e)) send_error("Keyspace measure failed!", self.config.get_value('token'), task['taskId'], None) sleep(5) return False output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") keyspace = "0" for line in output: if not line: continue keyspace = line return chunk.send_keyspace(int(keyspace), task['taskId'])
def run_speed_benchmark(self, task): args = " --machine-readable --quiet --progress-only" args += " --restore-disable --potfile-disable --session=hashtopolis -p \"" + str(chr(9)) + "\" " if task['usePrince']: args += get_rules_and_hl(update_files(task['attackcmd']), task['hashlistAlias']).replace(task['hashlistAlias'], "../../hashlists/" + str(task['hashlistId'])) + ' ' args += " example.dict" + ' ' + task['cmdpars'] else: args += update_files(task['attackcmd']).replace(task['hashlistAlias'], "../../hashlists/" + str(task['hashlistId'])) + ' ' + task['cmdpars'] if 'useBrain' in task and task['useBrain']: args += " -S" args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out" full_cmd = self.callPath + args if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') try: logging.debug("CALL: " + full_cmd) output = subprocess.check_output(full_cmd, shell=True, cwd=self.cracker_path) except subprocess.CalledProcessError as e: logging.error("Error during speed benchmark, return code: " + str(e.returncode)) send_error("Speed benchmark failed!", self.config.get_value('token'), task['taskId'], None) return 0 output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") benchmark_sum = [0, 0] for line in output: if not line: continue line = line.split(":") if len(line) != 3: continue # we need to do a weighted sum of all the time outputs of the GPUs benchmark_sum[0] += int(line[1]) benchmark_sum[1] += float(line[2])*int(line[1]) return str(benchmark_sum[0]) + ":" + str(float(benchmark_sum[1]) / benchmark_sum[0])
def measure_keyspace(self, task, chunk): if 'usePrince' in task.get_task() and task.get_task()['usePrince']: return self.prince_keyspace(task.get_task(), chunk) elif 'usePreprocessor' in task.get_task() and task.get_task()['usePreprocessor']: return self.preprocessor_keyspace(task, chunk) task = task.get_task() # TODO: refactor this to be better code full_cmd = self.callPath + " --keyspace --quiet " + update_files(task['attackcmd']).replace(task['hashlistAlias'] + " ", "") + ' ' + task['cmdpars'] if 'useBrain' in task and task['useBrain']: full_cmd += " -S" if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') output = b'' try: logging.debug("CALL: " + full_cmd) output = subprocess.check_output(full_cmd, shell=True, cwd=self.cracker_path, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: logging.error("Error during keyspace measure: " + str(e) + " Output: " + output.decode(encoding='utf-8')) send_error("Keyspace measure failed!", self.config.get_value('token'), task['taskId'], None) sleep(5) return False output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") ks = 0 # try to parse each line as a keyspace result integer (normally only one line should be in output, but some warnings might show up) for line in output: if not line: continue try: ks = int(line) except ValueError: pass return chunk.send_keyspace(ks, task['taskId'])
def measure_keyspace(self, task, chunk): full_cmd = self.callPath + " --keyspace --quiet " + update_files(task['attackcmd']).replace(task['hashlistAlias'] + " ", "") if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') try: output = subprocess.check_output(full_cmd, shell=True, cwd=self.cracker_path) except subprocess.CalledProcessError: logging.error("Error during keyspace measure") send_error("Keyspace measure failed!", self.config.get_value('token'), task['taskId']) return output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") keyspace = "0" for line in output: if len(line) == 0: continue keyspace = line chunk.send_keyspace(int(keyspace), task['taskId'])
def measure_keyspace(self, task, chunk): task = task.get_task() full_cmd = self.callPath + " keyspace " + task['attackcmd'].replace( "-a " + task['hashlistAlias'] + " ", "") if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') try: logging.debug("CALL: " + full_cmd) output = subprocess.check_output(full_cmd, shell=True, cwd='files') except subprocess.CalledProcessError as e: logging.error("Error during keyspace measurement: " + str(e)) send_error("Keyspace measure failed!", self.config.get_value('token'), task['taskId'], None) sleep(5) return False output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") keyspace = "0" for line in output: if not line: continue keyspace = line self.keyspace = int(keyspace) return chunk.send_keyspace(int(keyspace), task['taskId'])
def run_loop(self, proc, chunk, task): self.cracks = [] piping_threshold = 95 enable_piping = False if self.config.get_value('piping-threshold'): piping_threshold = self.config.get_value('piping-threshold') if self.config.get_value('allow-piping') != '': enable_piping = self.config.get_value('allow-piping') while True: try: # Block for 1 second. if not self.first_status and self.last_update < time.time() - 5: # send update query = copy_and_set_token(dict_sendProgress, self.config.get_value('token')) query['chunkId'] = chunk['chunkId'] query['keyspaceProgress'] = chunk['skip'] query['relativeProgress'] = 0 query['speed'] = 0 query['state'] = 2 query['cracks'] = [] req = JsonRequest(query) logging.info( "Sending keepalive progress to avoid timeout...") req.execute() self.last_update = time.time() item = self.io_q.get(True, 1) except Empty: # No output in either streams for a second. Are we done? if proc.poll() is not None: # is the case when the process is finished break else: identifier, line = item if identifier == 'OUT': status = HashcatStatus(line.decode()) if status.is_valid(): self.statusCount += 1 # test if we have a low utility # not allowed if brain is used if enable_piping and not self.uses_slow_hash_flag and ( 'useBrain' not in task or not task['useBrain'] ) and 'slowHash' in task and task[ 'slowHash'] and not self.usePipe: if task['files'] and not ( 'usePrince' in task and task['usePrince'] ) and not ( 'usePreprocessor' in task and task['usePreprocessor'] ) and 1 < self.statusCount < 10 and status.get_util( ) != -1 and status.get_util() < piping_threshold: # we need to try piping -> kill the process and then wait for issuing the chunk again self.usePipe = True chunk_start = int( status.get_progress_total() / (chunk['skip'] + chunk['length']) * chunk['skip']) self.progressVal = status.get_progress_total( ) - chunk_start logging.info( "Detected low UTIL value, restart chunk with piping..." ) try: kill_hashcat(proc.pid, Initialize.get_os()) except ProcessLookupError: pass return self.first_status = True # send update to server logging.debug(line.decode().replace('\n', '').replace( '\r', '')) total = status.get_progress_total() if self.usePipe: # if we are piping, we might have saved the total progress before switching to piping, so we can use this total = self.progressVal # we need to calculate the chunk start, because progress does not start at 0 for a chunk chunk_start = int(status.get_progress_total() / (chunk['skip'] + chunk['length']) * chunk['skip']) if total > 0: relative_progress = int( (status.get_progress() - chunk_start) / float(total - chunk_start) * 10000) else: # this is the case when we cannot say anything about the progress relative_progress = 0 speed = status.get_speed() initial = True if status.get_state() == 4 or status.get_state() == 5: time.sleep( 5 ) # we wait five seconds so all output is loaded from file # reset piping stuff when a chunk is successfully finished self.progressVal = 0 self.usePipe = False while self.cracks or initial: self.lock.acquire() initial = False cracks_backup = [] if len(self.cracks) > 1000: # we split cnt = 0 new_cracks = [] for crack in self.cracks: cnt += 1 if cnt > 1000: cracks_backup.append(crack) else: new_cracks.append(crack) self.cracks = new_cracks query = copy_and_set_token( dict_sendProgress, self.config.get_value('token')) query['chunkId'] = chunk['chunkId'] query['keyspaceProgress'] = status.get_curku() if (self.usePipe or 'usePrince' in task and task['usePrince'] or 'usePreprocessor' in task and task['usePreprocessor'] ) and status.get_curku() == 0: query['keyspaceProgress'] = chunk['skip'] query['relativeProgress'] = relative_progress query['speed'] = speed query['state'] = status.get_state() # crack format: hash[:salt]:plain:hex_plain:crack_pos (separator will be tab instead of :) prepared = [] for crack in self.cracks: prepared.append(crack.rsplit(":", 3)) query['cracks'] = prepared if status.get_temps(): query['gpuTemp'] = status.get_temps() if status.get_all_util(): query['gpuUtil'] = status.get_all_util() query['cpuUtil'] = [round(psutil.cpu_percent(), 1)] req = JsonRequest(query) logging.debug("Sending " + str(len(self.cracks)) + " cracks...") ans = req.execute() if ans is None: logging.error("Failed to send solve!") elif ans['response'] != 'SUCCESS': self.wasStopped = True logging.error("Error from server on solve: " + str(ans)) try: kill_hashcat(proc.pid, Initialize.get_os()) except ProcessLookupError: pass sleep(5) return elif 'agent' in ans.keys( ) and ans['agent'] == 'stop': # server set agent to stop self.wasStopped = True logging.info( "Received stop order from server!") try: kill_hashcat(proc.pid, Initialize.get_os()) except ProcessLookupError: pass sleep(5) return else: cracks_count = len(self.cracks) self.cracks = cracks_backup zaps = ans['zaps'] if zaps: logging.debug("Writing zaps") zap_output = "\tFF\n".join(zaps) + '\tFF\n' f = open( "hashlist_" + str(task['hashlistId']) + "/" + str(time.time()), 'a') f.write(zap_output) f.close() logging.info("Progress:" + str("{:6.2f}".format( relative_progress / 100)) + "% Speed: " + print_speed(speed) + " Cracks: " + str(cracks_count) + " Accepted: " + str(ans['cracked']) + " Skips: " + str(ans['skipped']) + " Zaps: " + str(len(zaps))) self.lock.release() else: # hacky solution to exclude warnings from hashcat if str(line[0]) not in string.printable: continue else: pass # logging.warning("HCOUT: " + line.strip()) elif identifier == 'ERR': msg = escape_ansi( line.replace(b"\r\n", b"\n").decode('utf-8')).strip() if msg and str( msg ) != '^C': # this is maybe not the fanciest way, but as ctrl+c is sent to the underlying process it reports it to stderr logging.error("HC error: " + msg) send_error(msg, self.config.get_value('token'), task['taskId'], chunk['chunkId']) sleep( 0.1 ) # we set a minimal sleep to avoid overreaction of the client sending a huge number of errors, but it should not be slowed down too much, in case the errors are not critical and the agent can continue
def run_loop(self, proc, chunk, task): self.cracks = [] while True: try: # Block for 1 second. if not self.first_status and self.last_update < time.time() - 5: # send update query = copyAndSetToken(dict_sendProgress, self.config.get_value('token')) query['chunkId'] = chunk['chunkId'] query['keyspaceProgress'] = chunk['skip'] query['relativeProgress'] = 0 query['speed'] = 0 query['state'] = 2 query['cracks'] = [] req = JsonRequest(query) logging.info("Sending keepalive progress to avoid timeout...") req.execute() self.last_update = time.time() item = self.io_q.get(True, 1) except Empty: # No output in either streams for a second. Are we done? if proc.poll() is not None: # is the case when the process is finished break else: identifier, line = item if identifier == 'OUT': status = HashcatStatus(line.decode()) if status.is_valid(): self.first_status = True # send update to server chunk_start = int(status.get_progress_total() / (chunk['skip'] + chunk['length']) * chunk['skip']) relative_progress = int((status.get_progress() - chunk_start) / float(status.get_progress_total() - chunk_start) * 10000) speed = status.get_speed() initial = True if status.get_state() == 5: time.sleep(1) # we wait for a second so all output is loaded from file while len(self.cracks) > 0 or initial: self.lock.acquire() initial = False cracks_backup = [] if len(self.cracks) > 1000: # we split cnt = 0 new_cracks = [] for crack in self.cracks: cnt += 1 if cnt > 1000: cracks_backup.append(crack) else: new_cracks.append(crack) self.cracks = new_cracks query = copyAndSetToken(dict_sendProgress, self.config.get_value('token')) query['chunkId'] = chunk['chunkId'] query['keyspaceProgress'] = status.get_curku() query['relativeProgress'] = relative_progress query['speed'] = speed query['state'] = status.get_state() query['cracks'] = self.cracks req = JsonRequest(query) logging.debug("Sending " + str(len(self.cracks)) + " cracks...") ans = req.execute() if ans is None: logging.error("Failed to send solve!") elif ans['response'] != 'SUCCESS': logging.error("Error from server on solve: " + str(ans)) try: kill_hashcat(proc.pid, Initialize.get_os()) except ProcessLookupError: pass return elif 'agent' in ans.keys() and ans['agent'] == 'stop': # server set agent to stop logging.info("Received stop order from server!") try: kill_hashcat(proc.pid, Initialize.get_os()) except ProcessLookupError: pass return else: cracks_count = len(self.cracks) self.cracks = cracks_backup zaps = ans['zaps'] if len(zaps) > 0: logging.debug("Writing zaps") zap_output = '\n'.join(zaps) + '\n' f = open("hashlist_" + str(task['hashlistId']) + "/" + str(time.time()), 'a') f.write(zap_output) f.close() logging.info("Progress:" + str( "{:6.2f}".format(relative_progress / 100)) + "% Speed: " + print_speed( speed) + " Cracks: " + str(cracks_count) + " Accepted: " + str( ans['cracked']) + " Skips: " + str(ans['skipped']) + " Zaps: " + str(len(zaps))) self.lock.release() else: # hacky solution to exclude warnings from hashcat if str(line[0]) not in string.printable: continue else: pass # logging.warning("HCOUT: " + line.strip()) else: logging.error("HC error: " + str(line).strip()) msg = str(line).strip() send_error(msg, self.config.get_value('token'), task['taskId'])