From 272d2472a562b4244ab0e4a66a76b087bae90553 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 3 Sep 2018 17:05:12 +0200 Subject: [PATCH 01/33] prepared client to send output format 15 --- python/htpclient/hashcat_cracker.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index ab6a8cf..98bf606 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -40,7 +40,7 @@ def build_command(self, task, chunk): args += " --status-timer " + str(task['statustimer']) args += " --outfile-check-timer=" + str(task['statustimer']) args += " --outfile-check-dir=../../hashlist_" + str(task['hashlistId']) - args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out" + args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15" args += " --remove-timer=" + str(task['statustimer']) args += " -s " + str(chunk['skip']) args += " -l " + str(chunk['length']) @@ -55,7 +55,7 @@ def build_pipe_command(self, task, chunk): post_args += " --status-timer " + str(task['statustimer']) post_args += " --outfile-check-timer=" + str(task['statustimer']) post_args += " --outfile-check-dir=../../hashlist_" + str(task['hashlistId']) - post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out" + post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15" post_args += " --remove-timer=" + str(task['statustimer']) post_args += " ../../hashlists/" + str(task['hashlistId']) return self.callPath + pre_args + " | " + self.callPath + post_args + task['cmdpars'] @@ -72,7 +72,7 @@ def build_prince_command(self, task, chunk): post_args += " --status-timer " + str(task['statustimer']) post_args += " --outfile-check-timer=" + str(task['statustimer']) post_args += " --outfile-check-dir=../../hashlist_" + str(task['hashlistId']) - post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out" + post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15" post_args += " --remove-timer=" + str(task['statustimer']) post_args += " ../../hashlists/" + str(task['hashlistId']) post_args += get_rules_and_hl(update_files(task['attackcmd']), task['hashlistAlias']).replace(task['hashlistAlias'], '') @@ -216,7 +216,11 @@ def run_loop(self, proc, chunk, task): query['relativeProgress'] = relative_progress query['speed'] = speed query['state'] = status.get_state() - query['cracks'] = self.cracks + # crack format: hash[:salt]:plain:hex_plain:crack_pos + prepared = [] + for crack in self.cracks: + prepared.append([crack.split("\t")]) + query['cracks'] = prepared if status.get_temps(): query['gpuTemp'] = status.get_temps() if status.get_all_util(): @@ -250,7 +254,7 @@ def run_loop(self, proc, chunk, task): zaps = ans['zaps'] if zaps: logging.debug("Writing zaps") - zap_output = ":FF\n".join(zaps) + ':FF\n' + zap_output = "\tFF\n".join(zaps) + ':FF\n' f = open("hashlist_" + str(task['hashlistId']) + "/" + str(time.time()), 'a') f.write(zap_output) f.close() From 13c06854009b1cfe2e905cf72c6ac5bb05861c7c Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Tue, 4 Sep 2018 09:05:20 +0200 Subject: [PATCH 02/33] updating separator to static setting of tab character --- python/htpclient/hashcat_cracker.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 98bf606..07a3676 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -40,7 +40,7 @@ def build_command(self, task, chunk): args += " --status-timer " + str(task['statustimer']) args += " --outfile-check-timer=" + str(task['statustimer']) args += " --outfile-check-dir=../../hashlist_" + str(task['hashlistId']) - args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15" + args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15 -p \"" + str(chr(9)) + "\"" args += " --remove-timer=" + str(task['statustimer']) args += " -s " + str(chunk['skip']) args += " -l " + str(chunk['length']) @@ -55,7 +55,7 @@ def build_pipe_command(self, task, chunk): post_args += " --status-timer " + str(task['statustimer']) post_args += " --outfile-check-timer=" + str(task['statustimer']) post_args += " --outfile-check-dir=../../hashlist_" + str(task['hashlistId']) - post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15" + post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15 -p \"" + str(chr(9)) + "\"" post_args += " --remove-timer=" + str(task['statustimer']) post_args += " ../../hashlists/" + str(task['hashlistId']) return self.callPath + pre_args + " | " + self.callPath + post_args + task['cmdpars'] @@ -72,7 +72,7 @@ def build_prince_command(self, task, chunk): post_args += " --status-timer " + str(task['statustimer']) post_args += " --outfile-check-timer=" + str(task['statustimer']) post_args += " --outfile-check-dir=../../hashlist_" + str(task['hashlistId']) - post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15" + post_args += " -o ../../hashlists/" + str(task['hashlistId']) + ".out --outfile-format=15 -p \"" + str(chr(9)) + "\"" post_args += " --remove-timer=" + str(task['statustimer']) post_args += " ../../hashlists/" + str(task['hashlistId']) post_args += get_rules_and_hl(update_files(task['attackcmd']), task['hashlistAlias']).replace(task['hashlistAlias'], '') @@ -219,7 +219,7 @@ def run_loop(self, proc, chunk, task): # crack format: hash[:salt]:plain:hex_plain:crack_pos prepared = [] for crack in self.cracks: - prepared.append([crack.split("\t")]) + prepared.append(crack.split("\t")) query['cracks'] = prepared if status.get_temps(): query['gpuTemp'] = status.get_temps() From fc5817f5ef302a607c8ec7ef6ea3c02a4c2ddaf8 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Tue, 4 Sep 2018 16:31:56 +0200 Subject: [PATCH 03/33] added check for chunk size 0 from server to avoid crashes like in s3inlc/hashtopolis#458 --- python/__main__.py | 10 ++++++++-- python/changelog.md | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index db043cf..5850af1 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -20,9 +20,9 @@ def init(): global CONFIG, binaryDownload - logformat = '[%(asctime)s] [%(levelname)-5s] %(message)s' + logformat = '[%(asctime)s] [%(levelname)-5s] %(message)s' dateformat = '%Y-%m-%d %H:%M:%S' - logfile = 'client.log' + logfile = 'client.log' loglevel = logging.INFO logging.getLogger("requests").setLevel(logging.WARNING) @@ -126,6 +126,12 @@ def loop(): logging.info("Server accepted benchmark!") continue + # check if we have an invalid chunk + if chunk.chunk_data()['length'] == 0: + logging.error("Invalid chunk size (0) retrieved! Retrying...") + task.reset_task() + continue + # run chunk logging.info("Start chunk...") cracker.run_chunk(task.get_task(), chunk.chunk_data()) diff --git a/python/changelog.md b/python/changelog.md index 54a8d4d..df9af83 100644 --- a/python/changelog.md +++ b/python/changelog.md @@ -1,3 +1,8 @@ +## 0.2.0 -> 0.x.x + +### Enhancements + +* Added check for chunk length 0 sent from the server to avoid full agent crash on running. ## 0.1.8 -> 0.2.0 From 4eedf2008a12cfbf06b5da759bc9c8367593e133 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Thu, 6 Sep 2018 15:37:37 +0200 Subject: [PATCH 04/33] agent being able to run health check requested from server --- python/__main__.py | 73 ++++++++++++++++++++++++++++- python/htpclient/chunk.py | 2 + python/htpclient/dicts.py | 16 +++++++ python/htpclient/hashcat_cracker.py | 34 ++++++++++++++ python/htpclient/helpers.py | 5 ++ python/htpclient/task.py | 6 +++ 6 files changed, 134 insertions(+), 2 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index 5850af1..5ae5ab9 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -1,3 +1,4 @@ +import time from time import sleep from htpclient.binarydownload import BinaryDownload @@ -6,7 +7,7 @@ from htpclient.generic_cracker import GenericCracker from htpclient.hashcat_cracker import HashcatCracker from htpclient.hashlist import Hashlist -from htpclient.helpers import start_uftpd +from htpclient.helpers import start_uftpd, file_get_contents from htpclient.initialize import Initialize from htpclient.jsonRequest import * from htpclient.dicts import * @@ -18,6 +19,66 @@ binaryDownload = None +def run_health_check(): + global CONFIG, binaryDownload + logging.info("Health check requested by server!") + logging.info("Retrieving health check settings...") + query = copy_and_set_token(dict_getHealthCheck, CONFIG.get_value('token')) + req = JsonRequest(query) + ans = req.execute() + if ans is None: + logging.error("Failed to get health check!") + sleep(5) + return + elif ans['response'] != 'SUCCESS': + logging.error("Error on getting health check: " + str(ans)) + sleep(5) + return + binaryDownload.check_version(ans['crackerBinaryId']) + check_id = ans['checkId'] + logging.info("Starting check ID " + str(check_id)) + + # write hashes to file + hash_file = open("hashlists/health_check.txt", "w") + hash_file.write("\n".join(ans['hashes'])) + hash_file.close() + + # delete old file if necessary + if os.path.exists("hashlists/health_check.out"): + os.unlink("hashlists/health_check.out") + + # run task + cracker = HashcatCracker(ans['crackerBinaryId'], binaryDownload) + start = int(time.time()) + [states, errors] = cracker.run_health_check(ans['attack'], ans['hashlistAlias']) + end = int(time.time()) + + # read results + if os.path.exists("hashlists/health_check.out"): + founds = file_get_contents("hashlists/health_check.out").replace("\r\n", "\n").split("\n") + else: + founds = [] + num_gpus = len(states[0].get_temps()) + query = copy_and_set_token(dict_sendHealthCheck, CONFIG.get_value('token')) + query['checkId'] = check_id + query['start'] = start + query['end'] = end + query['numGpus'] = num_gpus + query['numCracked'] = len(founds) - 1 + query['errors'] = errors + req = JsonRequest(query) + ans = req.execute() + if ans is None: + logging.error("Failed to send health check results!") + sleep(5) + return + elif ans['response'] != 'OK': + logging.error("Error on sending health check results: " + str(ans)) + sleep(5) + return + logging.info("Health check completed successfully!") + + def init(): global CONFIG, binaryDownload logformat = '[%(asctime)s] [%(levelname)-5s] %(message)s' @@ -62,7 +123,11 @@ def loop(): if task.get_task() is not None: last_task_id = task.get_task()['taskId'] task.load_task() - if task.get_task() is None: + if task.get_task_id() == -1: + run_health_check() + task.reset_task() + continue + elif task.get_task() is None: task_change = True continue else: @@ -96,6 +161,10 @@ def loop(): # measure keyspace cracker.measure_keyspace(task.get_task(), chunk) continue + elif chunk_resp == -3: + run_health_check() + task.reset_task() + continue elif chunk_resp == -2: # measure benchmark logging.info("Benchmark task...") diff --git a/python/htpclient/chunk.py b/python/htpclient/chunk.py index 5b054d2..96aa69e 100644 --- a/python/htpclient/chunk.py +++ b/python/htpclient/chunk.py @@ -35,6 +35,8 @@ def get_chunk(self, task_id): return -2 elif ans['status'] == 'fully_dispatched': return 0 + elif ans['status'] == 'health_check': + return -3 else: self.chunk = ans return 1 diff --git a/python/htpclient/dicts.py b/python/htpclient/dicts.py index 562d9fb..628d46f 100644 --- a/python/htpclient/dicts.py +++ b/python/htpclient/dicts.py @@ -31,6 +31,22 @@ def copy_and_set_token(dictionary, token): 'type': '', 'result': ''}) +dict_getHealthCheck = MappingProxyType( + {'action': 'getHealthCheck', + 'token': ''} +) + +dict_sendHealthCheck = MappingProxyType( + {'action': 'sendHealthCheck', + 'token': '', + 'numCracked': 0, + 'start': 0, + 'end': 0, + 'numGpus': 0, + 'errors': '', + 'checkId': 0} +) + dict_checkVersion = MappingProxyType( {'action': 'checkClientVersion', 'token': '', diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 07a3676..80e6826 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -436,3 +436,37 @@ def output_watcher(self, file_path, process): def agent_stopped(self): return self.wasStopped + + def run_health_check(self, attack, hashlist_alias): + args = " --machine-readable --quiet" + args += " --restore-disable --potfile-disable --session=health " + args += update_files(attack).replace(hashlist_alias, "../../hashlists/health_check.txt") + args += " -o ../../hashlists/health_check.out" + full_cmd = self.callPath + args + if Initialize.get_os() == 1: + full_cmd = full_cmd.replace("/", '\\') + logging.debug("CALL: " + full_cmd) + proc = subprocess.Popen(full_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.cracker_path) + output, error = proc.communicate() + logging.debug("Started health check attack") + proc.wait() # wait until done + errors = [] + states = [] + if error: + error = escape_ansi(error.replace(b"\r\n", b"\n").decode('utf-8')) + error = error.split('\n') + for line in error: + if not line: + continue + errors.append(line) + if output: + output = escape_ansi(output.replace(b"\r\n", b"\n").decode('utf-8')) + output = output.split('\n') + for line in output: + if not line: + continue + logging.debug(line) + status = HashcatStatus(line) + if status.is_valid(): + states.append(status) + return [states, errors] diff --git a/python/htpclient/helpers.py b/python/htpclient/helpers.py index 7c81038..d2ce0a7 100644 --- a/python/htpclient/helpers.py +++ b/python/htpclient/helpers.py @@ -53,6 +53,11 @@ def send_error(error, token, task_id): req.execute() +def file_get_contents(filename): + with open(filename) as f: + return f.read() + + def start_uftpd(os_extension, config): try: subprocess.check_output("killall -s 9 uftpd", shell=True) # stop running service to make sure we can start it again diff --git a/python/htpclient/task.py b/python/htpclient/task.py index ff5a0c1..7ad22af 100644 --- a/python/htpclient/task.py +++ b/python/htpclient/task.py @@ -34,9 +34,15 @@ def load_task(self): logging.info("No task available!") sleep(5) return + elif ans['taskId'] == -1: + self.taskId = -1 + return self.task = ans self.taskId = ans['taskId'] logging.info("Got task with id: " + str(ans['taskId'])) def get_task(self): return self.task + + def get_task_id(self): + return self.taskId From ee22d00891281e3a4462b754004cc391567671a3 Mon Sep 17 00:00:00 2001 From: Michael Sprecher Date: Fri, 7 Sep 2018 20:46:06 +0200 Subject: [PATCH 05/33] refactored to use a requests session --- python/__main__.py | 3 +++ python/changelog.md | 1 + python/htpclient/download.py | 6 ++++-- python/htpclient/jsonRequest.py | 5 +++-- python/htpclient/session.py | 9 +++++++++ 5 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 python/htpclient/session.py diff --git a/python/__main__.py b/python/__main__.py index 5850af1..aad7002 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -36,6 +36,9 @@ def init(): logging.info("Starting client '" + Initialize.get_version() + "'...") + session = Session(requests.Session()).s + session.headers.update({'User-Agent': Initialize.get_version()}) + # connection initialization Initialize().run() # download and updates diff --git a/python/changelog.md b/python/changelog.md index df9af83..6b50222 100644 --- a/python/changelog.md +++ b/python/changelog.md @@ -3,6 +3,7 @@ ### Enhancements * Added check for chunk length 0 sent from the server to avoid full agent crash on running. +* Using requests session ## 0.1.8 -> 0.2.0 diff --git a/python/htpclient/download.py b/python/htpclient/download.py index fab923a..68de720 100644 --- a/python/htpclient/download.py +++ b/python/htpclient/download.py @@ -6,24 +6,26 @@ import os from htpclient.initialize import Initialize +from htpclient.session import Session class Download: @staticmethod def download(url, output, no_header=False): try: + session = Session().s if Initialize.get_os() == 1: output = output.replace("/", '\\') # Check header if not no_header: - head = requests.head(url) + head = session.head(url) # not sure if we only should allow 200/302, but then it's present for sure if head.status_code != 200 and head.status_code != 302: return False with open(output, "wb") as file: - response = requests.get(url, stream=True) + response = session.get(url, stream=True) total_length = response.headers.get('Content-Length') if total_length is None: # no content length header diff --git a/python/htpclient/jsonRequest.py b/python/htpclient/jsonRequest.py index 755c5e3..8b3bc57 100644 --- a/python/htpclient/jsonRequest.py +++ b/python/htpclient/jsonRequest.py @@ -1,18 +1,19 @@ import logging -import requests from htpclient.config import * +from htpclient.session import * class JsonRequest: def __init__(self, data): self.data = data self.config = Config() + self.session = Session().s def execute(self): try: logging.debug(self.data) - r = requests.post(self.config.get_value('url'), json=self.data) + r = self.session.post(self.config.get_value('url'), json=self.data) if r.status_code != 200: logging.error("Status code from server: " + str(r.status_code)) return None diff --git a/python/htpclient/session.py b/python/htpclient/session.py new file mode 100644 index 0000000..4f44d7e --- /dev/null +++ b/python/htpclient/session.py @@ -0,0 +1,9 @@ +import requests + +class Session(): + __instance = None + def __new__(cls, s=None): + if Session.__instance == None: + Session.__instance = object.__new__(cls) + Session.__instance.s = s + return Session.__instance From defdabdc7f0bae4d3996d77341d7253236b0742c Mon Sep 17 00:00:00 2001 From: Michael Sprecher Date: Fri, 7 Sep 2018 20:53:45 +0200 Subject: [PATCH 06/33] Added option to specify proxies --- python/README.md | 1 + python/__main__.py | 3 +++ python/changelog.md | 1 + 3 files changed, 5 insertions(+) diff --git a/python/README.md b/python/README.md index 144d7f3..2d4370e 100644 --- a/python/README.md +++ b/python/README.md @@ -52,6 +52,7 @@ When you run the client for the first time it will ask automatically for all the | multicast-device | string | eth0 | Device which is used to retrieve UDP multicast file distribution | | file-deletion-disable | boolean | false | Disable requesting the server for files to delete | | file-deletion-interval| integer | 600 | Interval time in seconds in which the agent should check for deleted files | +| proxies | object | | Specify proxies e.g. `"proxies": {"https": "localhost:8433"}` | ### Debug example diff --git a/python/__main__.py b/python/__main__.py index aad7002..10953b2 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -39,6 +39,9 @@ def init(): session = Session(requests.Session()).s session.headers.update({'User-Agent': Initialize.get_version()}) + if CONFIG.get_value('proxies'): + session.proxies = CONFIG.get_value('proxies') + # connection initialization Initialize().run() # download and updates diff --git a/python/changelog.md b/python/changelog.md index 6b50222..f766de4 100644 --- a/python/changelog.md +++ b/python/changelog.md @@ -4,6 +4,7 @@ * Added check for chunk length 0 sent from the server to avoid full agent crash on running. * Using requests session +* Added option for using proxies ## 0.1.8 -> 0.2.0 From bca6979ba03f7808d33e41a6f6685db5e1f6d50d Mon Sep 17 00:00:00 2001 From: Michael Sprecher Date: Fri, 7 Sep 2018 21:34:08 +0200 Subject: [PATCH 07/33] Added support for HTTP Basic Auth --- python/README.md | 2 ++ python/__main__.py | 3 +++ python/changelog.md | 1 + 3 files changed, 6 insertions(+) diff --git a/python/README.md b/python/README.md index 2d4370e..d162bf9 100644 --- a/python/README.md +++ b/python/README.md @@ -53,6 +53,8 @@ When you run the client for the first time it will ask automatically for all the | file-deletion-disable | boolean | false | Disable requesting the server for files to delete | | file-deletion-interval| integer | 600 | Interval time in seconds in which the agent should check for deleted files | | proxies | object | | Specify proxies e.g. `"proxies": {"https": "localhost:8433"}` | +| auth-user | string | | HTTP Basic Auth user | +| auth-password | string | | HTTP Basic AUth password | ### Debug example diff --git a/python/__main__.py b/python/__main__.py index 10953b2..88d1a08 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -42,6 +42,9 @@ def init(): if CONFIG.get_value('proxies'): session.proxies = CONFIG.get_value('proxies') + if CONFIG.get_value('auth-user') and CONFIG.get_value('auth-password'): + session.auth = (CONFIG.get_value('auth-user'), CONFIG.get_value('auth-password')) + # connection initialization Initialize().run() # download and updates diff --git a/python/changelog.md b/python/changelog.md index f766de4..f88e242 100644 --- a/python/changelog.md +++ b/python/changelog.md @@ -5,6 +5,7 @@ * Added check for chunk length 0 sent from the server to avoid full agent crash on running. * Using requests session * Added option for using proxies +* Added HTTP Basic Auth support ## 0.1.8 -> 0.2.0 From edb0de2e83492968e5a8d7a8f57d754bc88b76a8 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Wed, 26 Sep 2018 14:31:46 +0200 Subject: [PATCH 08/33] fixed benchmark result handling when having many GPUs --- python/changelog.md | 4 ++++ python/htpclient/hashcat_cracker.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/python/changelog.md b/python/changelog.md index df9af83..9513f26 100644 --- a/python/changelog.md +++ b/python/changelog.md @@ -1,5 +1,9 @@ ## 0.2.0 -> 0.x.x +### Bugfixes + +* Fixed benchmark results when having many GPUs in one agent. + ### Enhancements * Added check for chunk length 0 sent from the server to avoid full agent crash on running. diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 07a3676..5db3e11 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -406,8 +406,8 @@ def run_speed_benchmark(self, task): if len(line) != 3: continue benchmark_sum[0] += int(line[1]) - benchmark_sum[1] += float(line[2]) - return str(benchmark_sum[0]) + ":" + str(benchmark_sum[1]) + benchmark_sum[1] += float(line[2])*int(line[1]) + return str(benchmark_sum[0]) + ":" + str(float(benchmark_sum[1]) / benchmark_sum[0]) def output_watcher(self, file_path, process): while not os.path.exists(file_path): From 796b3fdcd49a92399bd2233e0e70105d973a15f6 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Thu, 27 Sep 2018 09:33:22 +0200 Subject: [PATCH 09/33] fixed typo in error text --- python/htpclient/hashcat_cracker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 5db3e11..1cabd7c 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -394,8 +394,8 @@ def run_speed_benchmark(self, task): 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']) + logging.error("Error during speed benchmark, return code: " + str(e.returncode)) + send_error("Speed benchmark failed!", self.config.get_value('token'), task['taskId']) return 0 output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") benchmark_sum = [0, 0] From 03ab32abe5c7028eb43f03d2e19a07f06e505d20 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Fri, 28 Sep 2018 09:46:18 +0200 Subject: [PATCH 10/33] updated changelog and fixed separator in zap writing --- python/changelog.md | 4 ++++ python/htpclient/hashcat_cracker.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/python/changelog.md b/python/changelog.md index 9513f26..6787136 100644 --- a/python/changelog.md +++ b/python/changelog.md @@ -1,5 +1,9 @@ ## 0.2.0 -> 0.x.x +### Features + +* Agents can run health checks requested from the server. + ### Bugfixes * Fixed benchmark results when having many GPUs in one agent. diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 531560a..ed4059a 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -254,7 +254,7 @@ def run_loop(self, proc, chunk, task): zaps = ans['zaps'] if zaps: logging.debug("Writing zaps") - zap_output = "\tFF\n".join(zaps) + ':FF\n' + zap_output = "\tFF\n".join(zaps) + '\tFF\n' f = open("hashlist_" + str(task['hashlistId']) + "/" + str(time.time()), 'a') f.write(zap_output) f.close() From 492ea9d9ec77c79ac509b93b05be8af0d1930cb4 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 1 Oct 2018 11:55:55 +0200 Subject: [PATCH 11/33] enforcing utf8 encoding for cracks and logger to avoid issues with special chars in cracks --- python/__main__.py | 6 +++--- python/htpclient/hashcat_cracker.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index 5ae5ab9..ce8b0d8 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -83,8 +83,8 @@ def init(): global CONFIG, binaryDownload logformat = '[%(asctime)s] [%(levelname)-5s] %(message)s' dateformat = '%Y-%m-%d %H:%M:%S' - logfile = 'client.log' loglevel = logging.INFO + logfile = open('client.log', "a", encoding="utf-8") logging.getLogger("requests").setLevel(logging.WARNING) @@ -92,8 +92,8 @@ def init(): if CONFIG.get_value('debug'): loglevel = logging.DEBUG logging.getLogger("requests").setLevel(logging.DEBUG) - logging.basicConfig(filename=logfile, level=loglevel, format=logformat, datefmt=dateformat) - logging.getLogger().addHandler(logging.StreamHandler()) + logging.basicConfig(level=loglevel, format=logformat, datefmt=dateformat) + logging.getLogger().addHandler(logging.StreamHandler(logfile)) logging.info("Starting client '" + Initialize.get_version() + "'...") diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index ed4059a..2114efc 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -414,7 +414,7 @@ def output_watcher(self, file_path, process): time.sleep(1) if process.poll() is not None: return - file_handle = open(file_path) + file_handle = open(file_path, encoding="utf-8") end_count = 0 while 1: where = file_handle.tell() From 6e09befd6844c3e1214a590245d1b758eee9c6ad Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Tue, 2 Oct 2018 11:12:38 +0200 Subject: [PATCH 12/33] setting two different formats for stdout and logging to file. This way not too much space is used on the terminal. --- python/__main__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index ce8b0d8..c423f63 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -82,6 +82,7 @@ def run_health_check(): def init(): global CONFIG, binaryDownload logformat = '[%(asctime)s] [%(levelname)-5s] %(message)s' + printformat = '%(message)s' dateformat = '%Y-%m-%d %H:%M:%S' loglevel = logging.INFO logfile = open('client.log', "a", encoding="utf-8") @@ -92,8 +93,10 @@ def init(): if CONFIG.get_value('debug'): loglevel = logging.DEBUG logging.getLogger("requests").setLevel(logging.DEBUG) - logging.basicConfig(level=loglevel, format=logformat, datefmt=dateformat) - logging.getLogger().addHandler(logging.StreamHandler(logfile)) + logging.basicConfig(level=loglevel, format=printformat, datefmt=dateformat) + file_handler = logging.StreamHandler(logfile) + file_handler.setFormatter(logging.Formatter(logformat)) + logging.getLogger().addHandler(file_handler) logging.info("Starting client '" + Initialize.get_version() + "'...") From 568939a724a0f51c3714f100f9bf840248d13c71 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Tue, 2 Oct 2018 11:19:37 +0200 Subject: [PATCH 13/33] updated variable names in init function --- python/__main__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index c423f63..6a3da0b 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -81,21 +81,21 @@ def run_health_check(): def init(): global CONFIG, binaryDownload - logformat = '[%(asctime)s] [%(levelname)-5s] %(message)s' - printformat = '%(message)s' - dateformat = '%Y-%m-%d %H:%M:%S' - loglevel = logging.INFO + log_format = '[%(asctime)s] [%(levelname)-5s] %(message)s' + print_format = '%(message)s' + date_format = '%Y-%m-%d %H:%M:%S' + log_level = logging.INFO logfile = open('client.log', "a", encoding="utf-8") logging.getLogger("requests").setLevel(logging.WARNING) CONFIG = Config() if CONFIG.get_value('debug'): - loglevel = logging.DEBUG + log_level = logging.DEBUG logging.getLogger("requests").setLevel(logging.DEBUG) - logging.basicConfig(level=loglevel, format=printformat, datefmt=dateformat) + logging.basicConfig(level=log_level, format=print_format, datefmt=date_format) file_handler = logging.StreamHandler(logfile) - file_handler.setFormatter(logging.Formatter(logformat)) + file_handler.setFormatter(logging.Formatter(log_format)) logging.getLogger().addHandler(file_handler) logging.info("Starting client '" + Initialize.get_version() + "'...") From adb3776369be76f486b71eda5ab41e2a87e1634d Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Wed, 3 Oct 2018 13:03:50 +0200 Subject: [PATCH 14/33] added parsing of server version if available --- python/htpclient/initialize.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/htpclient/initialize.py b/python/htpclient/initialize.py index 81be616..9ed0ba0 100644 --- a/python/htpclient/initialize.py +++ b/python/htpclient/initialize.py @@ -54,6 +54,8 @@ def __login(self): self.__login() else: logging.info("Login successful!") + if 'server-version' in ans: + logging.info("Hashtopolis Server version: " + ans['server-version']) if 'multicastEnabled' in ans and ans['multicastEnabled'] and self.get_os() == 0: # currently only allow linux logging.info("Multicast enabled!") self.config.set_value('multicast', True) From 17c4f09129588eb32016bf77d819b08eca2d38f3 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:02:03 +0200 Subject: [PATCH 15/33] improved session class --- python/htpclient/session.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python/htpclient/session.py b/python/htpclient/session.py index 4f44d7e..1892d14 100644 --- a/python/htpclient/session.py +++ b/python/htpclient/session.py @@ -1,9 +1,8 @@ -import requests - -class Session(): +class Session: __instance = None + def __new__(cls, s=None): - if Session.__instance == None: + if Session.__instance is None: Session.__instance = object.__new__(cls) Session.__instance.s = s return Session.__instance From e826af54b878f3ace44bdc49dd0203a591de5bbc Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:02:51 +0200 Subject: [PATCH 16/33] requests is required --- python/htpclient/session.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/htpclient/session.py b/python/htpclient/session.py index 1892d14..5552125 100644 --- a/python/htpclient/session.py +++ b/python/htpclient/session.py @@ -1,3 +1,6 @@ +import requests + + class Session: __instance = None From 9b9e6d54b6a07a3d9488422d7e2edb56c096d1f7 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:24:49 +0200 Subject: [PATCH 17/33] added mode to print version --- python/__main__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/__main__.py b/python/__main__.py index a3cdbfd..e72c150 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -1,3 +1,4 @@ +import sys import time from time import sleep @@ -221,6 +222,9 @@ def loop(): if __name__ == "__main__": try: + if len(sys.argv) > 1 and sys.argv[1] == '--version': + print(Initialize.get_version()) + exit() init() loop() except KeyboardInterrupt: From 000b10cba165acfdd319d5dfb9f837bf9b628253 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:25:42 +0200 Subject: [PATCH 18/33] added travis build script for python agent --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..313cd5f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: python +python: + - "3.6" + - "3.7" +install: + - pip install -r python/requirements.txt +script: + - python/build.sh + - python python/hashtopolis.zip --version From 99cd8ce07bd0a88d1c9ee7986fc9050acbddd930 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:28:53 +0200 Subject: [PATCH 19/33] updated script to build zip --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 313cd5f..601db76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,5 @@ python: install: - pip install -r python/requirements.txt script: - - python/build.sh + - cd python && ./build.sh - python python/hashtopolis.zip --version From 0f19bae31813ad0dfc754a27668247078873d602 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:31:57 +0200 Subject: [PATCH 20/33] testing path --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 601db76..4d8f648 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,6 @@ python: install: - pip install -r python/requirements.txt script: - - cd python && ./build.sh - - python python/hashtopolis.zip --version + - cd python + - ./build.sh + - python hashtopolis.zip --version From af3d098b3b6359d824f025a03d9d027b9537c0c7 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:36:25 +0200 Subject: [PATCH 21/33] testing for existence of zip before removing it --- python/build.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/build.sh b/python/build.sh index d8e8c94..0c7fcb2 100755 --- a/python/build.sh +++ b/python/build.sh @@ -1,4 +1,6 @@ #!/usr/bin/env bash -rm hashtopolis.zip +if [ -f hashtopolis.zip ]; then + rm hashtopolis.zip +fi zip -r hashtopolis.zip __main__.py htpclient -x "*__pycache__*" From ac158daa77366ef05f3e3fa634f5b8d179fe3875 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:38:32 +0200 Subject: [PATCH 22/33] not testing 3.7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4d8f648..51edec5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: + - "3.5" - "3.6" - - "3.7" install: - pip install -r python/requirements.txt script: From d3dcc35eb1813e1efc33b95bf5a24a3a2056b117 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 8 Oct 2018 11:49:05 +0200 Subject: [PATCH 23/33] renaming old .out files instead of removing them --- python/htpclient/hashcat_cracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index ed4059a..480a4ac 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -94,7 +94,7 @@ def run_chunk(self, task, chunk): full_cmd = full_cmd.replace("/", '\\') # clear old found file if os.path.exists("hashlists/" + str(task['hashlistId']) + ".out"): - os.remove("hashlists/" + str(task['hashlistId']) + ".out") + os.rename("hashlists/" + str(task['hashlistId']) + ".out", "hashlists/" + str(task['hashlistId']) + "_" + str(time.time()) + ".out") # create zap folder if not os.path.exists("hashlist_" + str(task['hashlistId'])): os.mkdir("hashlist_" + str(task['hashlistId'])) From ed429d77f7ad9304c1abc904097bebb08c736491 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 22 Oct 2018 10:47:24 +0200 Subject: [PATCH 24/33] updated keyspace measuring feedback to avoid endless loops and updated piping to be dependent if algorithm is slow hash or not --- python/__main__.py | 6 +++-- python/htpclient/chunk.py | 5 ++-- python/htpclient/generic_cracker.py | 2 +- python/htpclient/hashcat_cracker.py | 40 +++++++++++++++-------------- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index 73fc787..c58361d 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -172,8 +172,10 @@ def loop(): continue elif chunk_resp == -1: # measure keyspace - cracker.measure_keyspace(task.get_task(), chunk) - continue + if cracker.measure_keyspace(task.get_task(), chunk): + continue + else: # failure case + task.reset_task() elif chunk_resp == -3: run_health_check() task.reset_task() diff --git a/python/htpclient/chunk.py b/python/htpclient/chunk.py index 96aa69e..fb7faae 100644 --- a/python/htpclient/chunk.py +++ b/python/htpclient/chunk.py @@ -50,10 +50,11 @@ def send_keyspace(self, keyspace, task_id): if ans is None: logging.error("Failed to send keyspace!") sleep(5) - return 0 + return False elif ans['response'] != 'SUCCESS': logging.error("Sending of keyspace failed: " + str(ans)) sleep(5) - return 0 + return False else: logging.info("Keyspace got accepted!") + return True diff --git a/python/htpclient/generic_cracker.py b/python/htpclient/generic_cracker.py index ad29685..0859525 100644 --- a/python/htpclient/generic_cracker.py +++ b/python/htpclient/generic_cracker.py @@ -124,7 +124,7 @@ def measure_keyspace(self, task, chunk): continue keyspace = line self.keyspace = int(keyspace) - chunk.send_keyspace(int(keyspace), task['taskId']) + return chunk.send_keyspace(int(keyspace), task['taskId']) def run_benchmark(self, task): ksp = self.keyspace diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index e317e49..0edec73 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -128,7 +128,7 @@ def run_chunk(self, task, chunk): def run_loop(self, proc, chunk, task): self.cracks = [] piping_threshold = 95 - enable_piping = False + enable_piping = True if self.config.get_value('piping-threshold'): piping_threshold = self.config.get_value('piping-threshold') if self.config.get_value('allow-piping') != '': @@ -163,17 +163,18 @@ def run_loop(self, proc, chunk, task): self.statusCount += 1 # test if we have a low utility - if not self.usePipe and enable_piping and task['files'] and not task['usePrince'] 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 + if enable_piping and 'slowHash' in task and task['slowHash'] and not self.usePipe: + if task['files'] and not task['usePrince'] 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 @@ -279,8 +280,7 @@ def run_loop(self, proc, chunk, task): def measure_keyspace(self, task, chunk): if task['usePrince']: - self.prince_keyspace(task, chunk) - return + return self.prince_keyspace(task, chunk) full_cmd = self.callPath + " --keyspace --quiet " + update_files(task['attackcmd']).replace(task['hashlistAlias'] + " ", "") + ' ' + task['cmdpars'] if Initialize.get_os() == 1: full_cmd = full_cmd.replace("/", '\\') @@ -289,14 +289,15 @@ def measure_keyspace(self, task, chunk): except subprocess.CalledProcessError: logging.error("Error during keyspace measure") send_error("Keyspace measure failed!", self.config.get_value('token'), task['taskId']) - return + 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 - chunk.send_keyspace(int(keyspace), task['taskId']) + return chunk.send_keyspace(int(keyspace), task['taskId']) def prince_keyspace(self, task, chunk): binary = "pp64." @@ -313,7 +314,8 @@ def prince_keyspace(self, task, chunk): except subprocess.CalledProcessError: logging.error("Error during PRINCE keyspace measure") send_error("PRINCE keyspace measure failed!", self.config.get_value('token'), task['taskId']) - return + sleep(5) + return False output = output.decode(encoding='utf-8').replace("\r\n", "\n").split("\n") keyspace = "0" for line in output: @@ -321,9 +323,9 @@ def prince_keyspace(self, task, chunk): continue keyspace = line if int(keyspace) > 9000000000000000000: # max size of a long long int - chunk.send_keyspace(-1, task['taskId']) + return chunk.send_keyspace(-1, task['taskId']) else: - chunk.send_keyspace(int(keyspace), task['taskId']) + return chunk.send_keyspace(int(keyspace), task['taskId']) def run_benchmark(self, task): if task['benchType'] == 'speed': From 565384914b102362e20dedcc8f2f57aace82cdaf Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 10:41:22 +0100 Subject: [PATCH 25/33] avoid loop when keyspace measure fails and reset task --- python/__main__.py | 7 +++---- python/htpclient/hashcat_cracker.py | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index c58361d..767d7e9 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -172,10 +172,9 @@ def loop(): continue elif chunk_resp == -1: # measure keyspace - if cracker.measure_keyspace(task.get_task(), chunk): - continue - else: # failure case + if not cracker.measure_keyspace(task.get_task(), chunk): # failure case task.reset_task() + continue elif chunk_resp == -3: run_health_check() task.reset_task() @@ -211,7 +210,7 @@ def loop(): continue # check if we have an invalid chunk - if chunk.chunk_data()['length'] == 0: + if chunk.chunk_data() is not None and chunk.chunk_data()['length'] == 0: logging.error("Invalid chunk size (0) retrieved! Retrying...") task.reset_task() continue diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 0edec73..0e329ee 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -285,9 +285,10 @@ def measure_keyspace(self, task, chunk): 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: - logging.error("Error during keyspace measure") + 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']) sleep(5) return False From dac1a58368201d7ffa5e203f123bff5b70801a5c Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 13:07:13 +0100 Subject: [PATCH 26/33] enforcing task reset after error on sending solve to hopefully overcome race condition when loosing connection --- python/htpclient/hashcat_cracker.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 0e329ee..6a600e1 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -233,6 +233,7 @@ def run_loop(self, proc, chunk, task): 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()) @@ -248,6 +249,7 @@ def run_loop(self, proc, chunk, task): kill_hashcat(proc.pid, Initialize.get_os()) except ProcessLookupError: pass + sleep(5) return else: cracks_count = len(self.cracks) From 414d43659c643887edf3e31f79b6b5ab868efeeb Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 15:20:35 +0100 Subject: [PATCH 27/33] added better exit for agent during running hashcat without sending client error --- python/__main__.py | 9 ++++++--- python/htpclient/hashcat_cracker.py | 7 ++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/python/__main__.py b/python/__main__.py index 767d7e9..30def6b 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -18,6 +18,7 @@ CONFIG = None binaryDownload = None +current_cracker = None def run_health_check(): @@ -120,7 +121,7 @@ def init(): def loop(): - global binaryDownload, CONFIG + global binaryDownload, CONFIG, current_cracker logging.debug("Entering loop...") task = Task() @@ -163,8 +164,10 @@ def loop(): logging.info("Got cracker binary type " + binaryDownload.get_version()['name']) if binaryDownload.get_version()['name'].lower() == 'hashcat': cracker = HashcatCracker(task.get_task()['crackerId'], binaryDownload) + current_cracker = cracker else: cracker = GenericCracker(task.get_task()['crackerId'], binaryDownload) + current_cracker = cracker task_change = False chunk_resp = chunk.get_chunk(task.get_task()['taskId']) if chunk_resp == 0: @@ -228,9 +231,9 @@ def loop(): try: if len(sys.argv) > 1 and sys.argv[1] == '--version': print(Initialize.get_version()) - exit() + sys.exit() init() loop() except KeyboardInterrupt: logging.info("Exiting...") - exit() + sys.exit() diff --git a/python/htpclient/hashcat_cracker.py b/python/htpclient/hashcat_cracker.py index 6a600e1..294af6c 100644 --- a/python/htpclient/hashcat_cracker.py +++ b/python/htpclient/hashcat_cracker.py @@ -33,6 +33,7 @@ def __init__(self, cracker_id, binary_download): self.progressVal = 0 self.statusCount = 0 self.last_update = 0 + self.hc_proc = None self.wasStopped = False def build_command(self, task, chunk): @@ -273,12 +274,12 @@ def run_loop(self, proc, chunk, task): else: pass # logging.warning("HCOUT: " + line.strip()) - else: + elif identifier == 'ERR': msg = escape_ansi(line.replace(b"\r\n", b"\n").decode('utf-8')).strip() - if msg: + 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']) - sleep(5) + sleep(0.1) def measure_keyspace(self, task, chunk): if task['usePrince']: From 6834eb698ea74a3dfc56fef75d60e1f5fb26fc73 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 16:40:55 +0100 Subject: [PATCH 28/33] moved python to root dir, removed csharp --- .gitignore | 12 +- README.md | 98 +- python/__main__.py => __main__.py | 0 python/build.sh => build.sh | 0 python/changelog.md => changelog.md | 0 csharp/.gitignore | 7 - csharp/.gitkeep | 0 csharp/hashtopolis.sln | 31 - csharp/hashtopolis/.gitignore | 0 csharp/hashtopolis/7zClass.cs | 155 ---- csharp/hashtopolis/App.config | 6 - csharp/hashtopolis/Program.cs | 223 ----- csharp/hashtopolis/Properties/AssemblyInfo.cs | 36 - csharp/hashtopolis/binary/hashtopolis.exe | Bin 68608 -> 0 bytes csharp/hashtopolis/downloadClass.cs | 149 --- csharp/hashtopolis/hashcatClass.cs | 630 ------------- csharp/hashtopolis/hashcatUpdateClass.cs | 192 ---- csharp/hashtopolis/hashtopolis.csproj | 99 -- csharp/hashtopolis/hashtopolis.csproj.user | 3 - csharp/hashtopolis/jsonClass.cs | 254 ------ csharp/hashtopolis/registerClass.cs | 485 ---------- csharp/hashtopolis/small.ico | Bin 7140 -> 0 bytes csharp/hashtopolis/taskClass.cs | 854 ------------------ csharp/hashtopolis/updateClass.cs | 160 ---- {python/htpclient => htpclient}/__init__.py | 0 .../htpclient => htpclient}/binarydownload.py | 0 {python/htpclient => htpclient}/chunk.py | 0 {python/htpclient => htpclient}/config.py | 0 {python/htpclient => htpclient}/dicts.py | 0 {python/htpclient => htpclient}/download.py | 0 {python/htpclient => htpclient}/files.py | 0 .../generic_cracker.py | 0 .../htpclient => htpclient}/generic_status.py | 0 .../hashcat_cracker.py | 0 .../htpclient => htpclient}/hashcat_status.py | 0 {python/htpclient => htpclient}/hashlist.py | 0 {python/htpclient => htpclient}/helpers.py | 0 {python/htpclient => htpclient}/initialize.py | 0 .../htpclient => htpclient}/jsonRequest.py | 0 {python/htpclient => htpclient}/session.py | 0 {python/htpclient => htpclient}/task.py | 0 python/.gitignore | 9 - python/README.md | 95 -- python/requirements.txt => requirements.txt | 0 44 files changed, 100 insertions(+), 3398 deletions(-) rename python/__main__.py => __main__.py (100%) rename python/build.sh => build.sh (100%) rename python/changelog.md => changelog.md (100%) delete mode 100644 csharp/.gitignore delete mode 100644 csharp/.gitkeep delete mode 100644 csharp/hashtopolis.sln delete mode 100644 csharp/hashtopolis/.gitignore delete mode 100644 csharp/hashtopolis/7zClass.cs delete mode 100644 csharp/hashtopolis/App.config delete mode 100644 csharp/hashtopolis/Program.cs delete mode 100644 csharp/hashtopolis/Properties/AssemblyInfo.cs delete mode 100644 csharp/hashtopolis/binary/hashtopolis.exe delete mode 100644 csharp/hashtopolis/downloadClass.cs delete mode 100644 csharp/hashtopolis/hashcatClass.cs delete mode 100644 csharp/hashtopolis/hashcatUpdateClass.cs delete mode 100644 csharp/hashtopolis/hashtopolis.csproj delete mode 100644 csharp/hashtopolis/hashtopolis.csproj.user delete mode 100644 csharp/hashtopolis/jsonClass.cs delete mode 100644 csharp/hashtopolis/registerClass.cs delete mode 100644 csharp/hashtopolis/small.ico delete mode 100644 csharp/hashtopolis/taskClass.cs delete mode 100644 csharp/hashtopolis/updateClass.cs rename {python/htpclient => htpclient}/__init__.py (100%) rename {python/htpclient => htpclient}/binarydownload.py (100%) rename {python/htpclient => htpclient}/chunk.py (100%) rename {python/htpclient => htpclient}/config.py (100%) rename {python/htpclient => htpclient}/dicts.py (100%) rename {python/htpclient => htpclient}/download.py (100%) rename {python/htpclient => htpclient}/files.py (100%) rename {python/htpclient => htpclient}/generic_cracker.py (100%) rename {python/htpclient => htpclient}/generic_status.py (100%) rename {python/htpclient => htpclient}/hashcat_cracker.py (100%) rename {python/htpclient => htpclient}/hashcat_status.py (100%) rename {python/htpclient => htpclient}/hashlist.py (100%) rename {python/htpclient => htpclient}/helpers.py (100%) rename {python/htpclient => htpclient}/initialize.py (100%) rename {python/htpclient => htpclient}/jsonRequest.py (100%) rename {python/htpclient => htpclient}/session.py (100%) rename {python/htpclient => htpclient}/task.py (100%) delete mode 100644 python/.gitignore delete mode 100644 python/README.md rename python/requirements.txt => requirements.txt (100%) diff --git a/.gitignore b/.gitignore index 1981af8..97c5696 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ - -.idea/ *.iml -java/ \ No newline at end of file +*.exe +*.log +*.json +crackers +prince +files +hashlists +__pycache__ +*.zip diff --git a/README.md b/README.md index a54d362..d162bf9 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,95 @@ -# Hashtopolis Agents +# Hashtopolis Python Agent -Official agents for using the distributed hashcracker [Hashtopolis](https://github.com/s3inlc/hashtopolis). +[![CodeFactor](https://www.codefactor.io/repository/github/s3inlc/hashtopolis-agent/badge)](https://www.codefactor.io/repository/github/s3inlc/hashtopolis-agent) +[![LoC](https://tokei.rs/b1/github/s3inlc/Hashtopolis-Agent?category=code)](https://github.com/s3inlc/Hashtopolis-Agent) -Currently available agents: -- [C#](csharp) -- [Python](python) +This Hashtopolis agent is only compatible with Hashtopolis versions 0.5.0 and higher. -## Protocol Documentation +## Prerequisites -A documentation to the protocol which is used to communicate between the agent and the server can be found here: [Protocol.pdf](https://github.com/s3inlc/hashtopolis/blob/master/doc/protocol.pdf) +You need python3 installed on your agent system. +Following python packages are required: + +* requests + +## Manual + +You can either download the agent from the Hashtopolis new agent page or you can use the url shown there to download the agent with +wget/curl. + +### Run + +To run the agent you simply need to call `python3 hashtopolis.zip`. There are no command line options accepted, all +settings/configurations are done via the config file, described in the following section. + +Please note that the client does not correctly recognize the OS when you are running in Cygwin or similar on Windows. You need to run it in Windows command line. + +### Config + +When you run the client for the first time it will ask automatically for all the requirement settings and then saves it automatically to a config file called `config.json`. This could for example look like this: + +``` +{ + "url": "https://coray.org/htp-test/src/api/server.php", + "token": "7RNDqtnPxm", + "uuid": "49dcd31c-3637-4f2a-8df1-b545202df5b3" +} +``` + +### Overview + +| field | type | default | description | +|-----------------------|---------|---------|----------------------------------------------------------------------------| +| voucher | string | | Used for agent registration (will be prompted on first start) | +| url | string | | The hashtopolis API endpoint (will be prompted on first start) | +| token | string | | The access token for the API (sent by server on registration) | +| uuid | string | | Unique identifier of the agent (generated on registration) | +| debug | boolean | false | Enables debug output | +| allow-piping | boolean | false | Allows hashcat to read password candidates from stdin | +| piping-threshold | integer | 95 | Restarts chunk in piping mode when GPU UTIL is below this value | +| rsync | boolean | false | Enables download of wordlists and rules via rsync | +| rsync-path | string | | Remote path to hashtopolis files directory | +| multicast-device | string | eth0 | Device which is used to retrieve UDP multicast file distribution | +| file-deletion-disable | boolean | false | Disable requesting the server for files to delete | +| file-deletion-interval| integer | 600 | Interval time in seconds in which the agent should check for deleted files | +| proxies | object | | Specify proxies e.g. `"proxies": {"https": "localhost:8433"}` | +| auth-user | string | | HTTP Basic Auth user | +| auth-password | string | | HTTP Basic AUth password | + +### Debug example + +``` +{ + "url": "https://coray.org/htp-test/src/api/server.php", + "token": "7RNDqtnPxm", + "uuid": "49dcd31c-3637-4f2a-8df1-b545202df5b3", + "debug": true +} +``` + +### rsync + +You need a user on the server which can automatically login (e.g. SSH keys) and has read access to the files directory of hashtopolis. On the client side you need rsync installed and set the following lines in your agent config. + +``` + "rsync": true, + "rsync-path": "user@yourserver:/path/to/hashtopolis/files" +``` + +### Multicast + +In order to use the multicast distribution for files, please make sure that the agents and server are prepared according to this:https://github.com/s3inlc/hashtopolis-runner + +## Hashcat Compatibility + +The list contains all Hashcat versions with which the client was tested and is able to work with (other versions might work): + +* 4.2.1 +* 4.2.0 +* 4.1.0 +* 4.0.1 +* 4.0.0 + +## Generic Crackers + +This client is able to run generic Hashtopolis cracker binaries which fulfill the minimal functionality requirements, described [here](https://github.com/s3inlc/hashtopolis/tree/master/doc/README.md). An example implementation can be found [here](https://github.com/s3inlc/hashtopolis-generic-cracker) diff --git a/python/__main__.py b/__main__.py similarity index 100% rename from python/__main__.py rename to __main__.py diff --git a/python/build.sh b/build.sh similarity index 100% rename from python/build.sh rename to build.sh diff --git a/python/changelog.md b/changelog.md similarity index 100% rename from python/changelog.md rename to changelog.md diff --git a/csharp/.gitignore b/csharp/.gitignore deleted file mode 100644 index 9d725e2..0000000 --- a/csharp/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -hashtopolis/bin/ -hashtopolis/obj/ -*.suo -.vs/ -.suo - - diff --git a/csharp/.gitkeep b/csharp/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/csharp/hashtopolis.sln b/csharp/hashtopolis.sln deleted file mode 100644 index eb1e016..0000000 --- a/csharp/hashtopolis.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.12 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "hashtopolis", "hashtopolis\hashtopolis.csproj", "{199AD37B-3000-4CC0-992C-87738F84C768}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {199AD37B-3000-4CC0-992C-87738F84C768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {199AD37B-3000-4CC0-992C-87738F84C768}.Debug|Any CPU.Build.0 = Debug|Any CPU - {199AD37B-3000-4CC0-992C-87738F84C768}.Debug|x64.ActiveCfg = Debug|x64 - {199AD37B-3000-4CC0-992C-87738F84C768}.Debug|x64.Build.0 = Debug|x64 - {199AD37B-3000-4CC0-992C-87738F84C768}.Release|Any CPU.ActiveCfg = Release|Any CPU - {199AD37B-3000-4CC0-992C-87738F84C768}.Release|Any CPU.Build.0 = Release|Any CPU - {199AD37B-3000-4CC0-992C-87738F84C768}.Release|x64.ActiveCfg = Release|x64 - {199AD37B-3000-4CC0-992C-87738F84C768}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6AF2D704-CD70-4421-8080-269C7AD78ABA} - EndGlobalSection -EndGlobal diff --git a/csharp/hashtopolis/.gitignore b/csharp/hashtopolis/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/csharp/hashtopolis/7zClass.cs b/csharp/hashtopolis/7zClass.cs deleted file mode 100644 index d0fc6e1..0000000 --- a/csharp/hashtopolis/7zClass.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.IO; -using System.Diagnostics; - - -namespace hashtopolis -{ - - class _7zClass - { - - public class dlProps - { - public string action = "downloadBinary"; - public string type = "7zr"; - public string token { get; set; } - } - - public int osID { get; set; } - public string tokenID { get; set; } - public string appPath { get; set; } - public string connectURL { get; set; } - - string binPath = ""; - - public Boolean init7z() - { - - binPath = Path.Combine(appPath, "7zr"); - if (osID == 1) - { - binPath += ".exe"; - } - - FileInfo f = new FileInfo(binPath); - - if (!File.Exists(binPath) || f.Length == 0) - { - Console.WriteLine("Downloading 7zip binary"); - jsonClass jsC = new jsonClass { debugFlag = true, connectURL = connectURL }; - - dlProps dlzip = new dlProps - { - token = tokenID - }; - - - string jsonString = jsC.toJson(dlzip); - string ret = jsC.jsonSend(jsonString); - if (jsC.isJsonSuccess(ret)) - - { - string dlLocation = jsC.getRetVar(ret,"executable"); - downloadClass dlClass = new downloadClass(); - - if (!dlClass.DownloadFile(dlLocation, binPath)) - { - Console.WriteLine("Unable to download requested file"); - } - else - { - Console.WriteLine("Finished downloading file"); - } - - } - if (osID != 1) //If OS is not windows, we need to set the permissions - { - try - { - Console.WriteLine("Applying execution permissions to 7zr binary"); - Process.Start("chmod", "+x \"" + binPath + "\""); - } - catch (Exception e) - { - Console.Write(e.Data); - Console.WriteLine("Unable to change access permissions of 7zr, execution permissions required"); - } - } - - } - - if (File.Exists(binPath)) - { - return true; - } - - return false; - - } - - //Code from hashtopus - public Boolean xtract(string archivePath, string outDir, string files = "") - { - ProcessStartInfo pinfo = new ProcessStartInfo(); - pinfo.FileName = binPath; - pinfo.WorkingDirectory = appPath; - pinfo.UseShellExecute = false; - pinfo.RedirectStandardError = true; - pinfo.RedirectStandardOutput = true; - pinfo.Arguments = " x -y -o\"" + outDir + "\" \"" + archivePath + "\""; - string stdOutSingle = ""; - Boolean unpackFailed = false; - Process unpak = new Process(); - unpak.StartInfo = pinfo; - - if (files != "") unpak.StartInfo.Arguments += " " + files; - - Console.WriteLine(pinfo.FileName + pinfo.Arguments); - Console.WriteLine("Extracting archive " + archivePath + "..."); - - FileInfo f = new FileInfo(archivePath); - - if (f.Length == 0) - { - Console.WriteLine("File is 0 bytes"); - return false; - } - - try - { - if (!unpak.Start()) return false; - while (!unpak.HasExited) - { - while (!unpak.StandardOutput.EndOfStream) - { - stdOutSingle = unpak.StandardOutput.ReadLine().TrimEnd(); - if (stdOutSingle == "Error: Can not open file as archive") - { - unpackFailed = true; - } - } - } - unpak.StandardOutput.Close(); - } - catch - { - Console.WriteLine("Could not start 7zr."); - return false; - } - finally - { - unpak.WaitForExit(); - } - - if (unpackFailed == true) - { - Console.WriteLine("Failed to extract " + archivePath); - Console.WriteLine("WARNING:Some needed files may be missing and the tasks may not start correctly"); - return false; - } - return true; - - } - } -} diff --git a/csharp/hashtopolis/App.config b/csharp/hashtopolis/App.config deleted file mode 100644 index e707b32..0000000 --- a/csharp/hashtopolis/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/csharp/hashtopolis/Program.cs b/csharp/hashtopolis/Program.cs deleted file mode 100644 index b99f205..0000000 --- a/csharp/hashtopolis/Program.cs +++ /dev/null @@ -1,223 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Diagnostics; -namespace hashtopolis -{ - - - - public struct Packets - { - public Dictionary statusPackets; - public List crackedPackets; - } - - public class testProp - { - public string action = "testConnection"; - } - - - - class Program - { - - public static string AppPath = AppDomain.CurrentDomain.BaseDirectory; - private static string urlPath = Path.Combine(AppPath, "URL"); - private static string serverURL = ""; - - static void initDirs() - { - - string[] createDirs = new String[] { "files", "hashlists", "tasks", "hashcat" }; - - foreach (string dir in createDirs) - { - string enumDir = Path.Combine(AppPath, dir); - try - { - if (!Directory.Exists(enumDir)) - { - Console.WriteLine("Creating {0} directory", dir); - Directory.CreateDirectory(enumDir); - } - } - catch(Exception e) - { - Console.WriteLine(e.Data); - Console.WriteLine("Unable to create dir {0}", dir); - Console.WriteLine("Client now terminating"); - Environment.Exit(0); - } - - } - - } - - - public static bool loadURL() - { - if (serverURL == "") - { - if (File.Exists(urlPath)) - { - serverURL = File.ReadAllText(urlPath); - if (serverURL == "") - { - File.Delete(urlPath); - return false; - } - } - else - { - return false; - } - } - return true; - - } - - - public static Boolean initConnect() - { - jsonClass testConnect = new jsonClass { debugFlag = DebugMode }; - testProp tProp = new testProp(); - string urlMsg = "Please enter server connect URL (https will be used unless specified):"; - while (!loadURL()) - { - Console.WriteLine(urlMsg); - string url = Console.ReadLine(); - if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - url = "https://" + url; - } - Console.WriteLine("Testing connection to " + url); - testConnect.connectURL = url; - string jsonString = testConnect.toJson(tProp); - string ret = testConnect.jsonSendOnce(jsonString); - if (ret != null) - { - if (testConnect.isJsonSuccess(ret)) - { - File.WriteAllText(urlPath, url); - } - } - else - { - urlMsg = "Test connect failed, please enter server connect URL:"; - } - - } - - Console.WriteLine("Connecting to server {0}",serverURL); - return true; - } - - public static Boolean DebugMode; - - static void Main(string[] args) - { - - - if (Console.LargestWindowWidth > 94 && Console.LargestWindowHeight > 24) - { - Console.SetWindowSize(95, 25); - } - - - - System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone(); - customCulture.NumberFormat.NumberDecimalSeparator = "."; - System.Threading.Thread.CurrentThread.CurrentCulture = customCulture; - - string tokenSwitch = ""; - - foreach (string arg in args) - { - switch (arg.Substring(0, 2)) - { - - case "-t": - tokenSwitch = arg.Substring(3); - break; - case "-u": - serverURL = arg.Substring(3); - break; - case "-d": - DebugMode = true; - break; - } - } - - string AppVersion = "0.52.6"; - Console.WriteLine("Client Version " + AppVersion); - - initConnect(); - initDirs(); - - registerClass client = new registerClass { connectURL = serverURL, debugFlag = DebugMode,tokenID = tokenSwitch}; - Boolean legacy = false; //Defaults to legacy STATUS codes - client.setPath( AppPath); - if (client.loginAgent()) - { - Console.WriteLine("Logged in to server"); - } - - updateClass updater = new updateClass - { - htpVersion = AppVersion, - parentPath = AppPath, - arguments = args, - connectURL = serverURL, - debugFlag = DebugMode, - tokenID = client.tokenID - - }; - updater.runUpdate(); - //Run code to self-update - - _7zClass zipper = new _7zClass - { - tokenID = client.tokenID, - osID = client.osID, - appPath = AppPath, - connectURL = serverURL - }; - - if (!zipper.init7z()) - { - Console.WriteLine("Failed to initialize 7zip, proceeding without. \n The client may not be able to extract compressed files"); - } - - taskClass tasks = new taskClass - { - sevenZip = zipper, - debugFlag = DebugMode, - client = client, - legacy = legacy - - }; - - tasks.setOffset(); //Set offset for STATUS changes in hashcat 3.6.0 - tasks.setDirs(AppPath); - - int backDown = 5; - while(true) //Keep waiting for 5 seconds and checking for tasks - { - Thread.Sleep(backDown * 1000); - - if (tasks.getTask()) - { - backDown = 5; - } - if (backDown <30) - { - backDown++; - } - } - - } - } -} diff --git a/csharp/hashtopolis/Properties/AssemblyInfo.cs b/csharp/hashtopolis/Properties/AssemblyInfo.cs deleted file mode 100644 index 867088f..0000000 --- a/csharp/hashtopolis/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("hashtopolis")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("hashtopolis")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("199ad37b-3000-4cc0-992c-87738f84c768")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/csharp/hashtopolis/binary/hashtopolis.exe b/csharp/hashtopolis/binary/hashtopolis.exe deleted file mode 100644 index 1bf8228c0be02d8e76cc2238bcd5a2c434676fbe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68608 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 U&^iS1m+}9=q5bcW{uKlN2fk(i2><{9 diff --git a/csharp/hashtopolis/downloadClass.cs b/csharp/hashtopolis/downloadClass.cs deleted file mode 100644 index 8030e4b..0000000 --- a/csharp/hashtopolis/downloadClass.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Threading; -using System.IO; -using System.ComponentModel; - -namespace hashtopolis -{ - class downloadClass - { - - - Stopwatch sw = new Stopwatch(); - private bool completedFlag = false; - - public bool DownloadFileCurl(string urlAddress, string location) - { - string AppPath = AppDomain.CurrentDomain.BaseDirectory; - ProcessStartInfo pinfo = new ProcessStartInfo(); - pinfo.FileName = "curl"; - pinfo.UseShellExecute = false; - pinfo.RedirectStandardOutput = true; - - - pinfo.WorkingDirectory = AppPath; - - pinfo.Arguments = " " + urlAddress + " -o" + "\"" + location + "\""; - - Process unpak = new Process(); - unpak.StartInfo = pinfo; - unpak.Start(); - unpak.WaitForExit(); - return true; - - } - - - - public bool DownloadFile(string urlAddress, string location) - { - - completedFlag = false; - WebClient webClient; - try - { - System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | - SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3; - } - catch - { - Console.WriteLine("Skipping TLS settings (consider upgrading to the latest .NET framework for better TLS support"); - } - - using (webClient = new WebClient()) - { - webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged); - webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(dlFinished); - if (!urlAddress.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - urlAddress = "https://" + urlAddress; - } - Uri URL = null; - try - { - Console.WriteLine("Downloading from " + urlAddress); - URL = new Uri(urlAddress); - } - catch - { - Console.WriteLine("Invalid url for downloading"); - return false; - } - - //webClient.DownloadFile(URL, location); - // Start the stopwatch which we will be using to calculate the download speed - sw.Start(); - - try - { - // Start downloading the file - webClient.DownloadFileAsync(URL, location); - - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - return false; - } - while (!completedFlag) Thread.Sleep(500); - - if (File.Exists(location)) - { - FileInfo f = new FileInfo(location); - long size = f.Length; - Console.WriteLine(); - return true; - } - else - { - return false; - } - - } - } - - //This will fire upon filedownload completion - void dlFinished(object sender, AsyncCompletedEventArgs e) - { - completedFlag = true; - } - - // The event that will fire whenever the progress of the WebClient is changed - private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - - double speed = e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds; - int divCount = 0; - while (speed > 1000) - { - speed = speed / 1000; - divCount += 1; - } - - string speedMetric = "?/s"; - switch (divCount) - { - case 0: - speedMetric = "KB/s"; - break; - case 1: - speedMetric = "MB/s"; - break; - case 2: - speedMetric = "GB/s"; - break; - case 3: - speedMetric = "TB/s"; - break; - - } - - Console.Write("\r{0} {1}% @ {2} {3}", "Downloading",e.ProgressPercentage, speed.ToString("0.00"), speedMetric); - - } - - - } -} diff --git a/csharp/hashtopolis/hashcatClass.cs b/csharp/hashtopolis/hashcatClass.cs deleted file mode 100644 index d6040cc..0000000 --- a/csharp/hashtopolis/hashcatClass.cs +++ /dev/null @@ -1,630 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics; -using System.Text.RegularExpressions; -using System.Globalization; - -namespace hashtopolis -{ - class hashcatClass : IDisposable - { - public Boolean debugFlag { get; set; } - - public List hashlist = new List { }; //New collection to store cracks - public Process hcProc; - - private string workingDir = ""; - private string filesDir = ""; - private string hcDir = "hashcat"; - private string hcBin = "hashcat64.exe"; - public string hcDirectory { get; set; } - public string hcBinary { get; set; } - - private string hcArgs = ""; - - private object packetLock; - private object crackedLock; - private object statusLock; - - List passedPackets; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (!hcProc.HasExited ) - { - hcProc.Kill(); - hcProc.Dispose(); - } - } - } - - public void setPassthrough(ref List refPacketlist, ref object objpacketLock, Boolean debugging) - { - passedPackets = refPacketlist; - packetLock = objpacketLock; - - crackedLock = new object(); - statusLock = new object(); - debugFlag = debugging; - - } - - public void setArgs(string args) - { - - hcArgs = args; - } - - public void setDirs(string fpath) - { - hcDir = Path.Combine(fpath, hcDirectory); - workingDir = Path.Combine(fpath, "tasks").TrimEnd(); - filesDir = Path.Combine(fpath, "files"," ").TrimEnd(); - - hcBin = hcBinary; - - } - - public void runUpdate() - { - if (!Directory.Exists(hcDir)) - { - //forceUpdate = true; - } - } - - - - private void parseStatus1(string line,ref Dictionary collection) - { - - System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone(); - customCulture.NumberFormat.NumberDecimalSeparator = "."; - System.Threading.Thread.CurrentThread.CurrentCulture = customCulture; - - //Console.WriteLine(line); - - string[] items = line.Split('\t'); - double speedData = 0; - double countStep = 0; - double execRuntime = 0; - - int max = items.Count(); - int i = 0; - - if (debugFlag) - { - Console.WriteLine(line); - } - - - while(i < max) - { - countStep = 0; - switch (items[i]) - { - case "STATUS": - collection.Add("STATUS", Convert.ToInt64(items[i + 1])); - i =+ 1; - break; - case "SPEED": - while (items[i+1] != "EXEC_RUNTIME") //Due to multiple cards, perform micro-loop - { - collection.Add("SPEED" + countStep, Convert.ToDouble(items[i + 1])); - speedData += (Convert.ToDouble(items[i + 1]) * 1000) / Convert.ToDouble(items[i + 2]); //For hashcat 3.7 compatability - countStep++; - i += 2; - } - collection.Add("SPEED_TOTAL", speedData); - collection.Add("SPEED_COUNT", countStep); - break; - case "EXEC_RUNTIME": - while (items[i+1] != "CURKU") //Due to multiple cards, perform micro-loop - { - collection.Add("EXEC_RUNTIME" + countStep, Math.Round(Convert.ToDouble(Decimal.Parse(items[i + 1]), CultureInfo.InvariantCulture),2)); - execRuntime += Convert.ToDouble(Decimal.Parse(items[i + 1]), CultureInfo.InvariantCulture); - countStep++; - i += 1; - } - collection.Add("EXEC_RUNTIME_AVG", Math.Round(execRuntime/ countStep,2)); //Calculate the average kernel run-time - collection.Add("EXEC_TIME_COUNT", countStep); - - break; - case "CURKU": - collection.Add("CURKU", Convert.ToDouble(items[i + 1])); - i += 1; - break; - case "PROGRESS": - collection.Add("PROGRESS1", Convert.ToDouble(items[i + 1])); //First progress value - collection.Add("PROGRESS2", Convert.ToDouble(items[i + 2])); //Total progress value - collection.Add("PROGRESS_DIV", Math.Round(Convert.ToDouble(items[i + 1])/Convert.ToInt64(items[i + 2]),15)); //Total progress value - i += 2; - break; - case "RECHASH": - collection.Add("RECHASH1", Convert.ToDouble(items[i + 1])); //First RECHASH value - collection.Add("RECHASH2", Convert.ToDouble(items[i + 2])); //Second RECHASH value - i += 2; - break; - case "RECSALT": - collection.Add("RECSALT1", Convert.ToDouble(items[i + 1])); //First RECSALT value - collection.Add("RECSALT2", Convert.ToDouble(items[i + 2])); //Second RECSALT value - i += 2; - break; - case "REJECTED": - collection.Add("REJECTED", Convert.ToDouble(items[i + 1])); - collection.Add("PROGRESS_REJ", Math.Round((collection["PROGRESS1"]-collection["REJECTED"]) / collection["PROGRESS2"], 15)); //Total progress value - i += 1; - break; - - } - i += 1; - } - - string[] Vars = new String[] { "STATUS", "SPEED_TOTAL", "EXEC_RUNTIME_AVG", "CURKU", "PROGRESS1","RECHASH1","RECSALT1" }; - foreach (string variable in Vars) - { - if (!collection.ContainsKey(variable)) - { - Console.WriteLine("Failed to parse {0} variable, something went wrong", variable); - } - } - } - - - private void parseStatus2(string statusLine, ref Dictionary collection) - { - - CultureInfo customCulture = (CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone(); - customCulture.NumberFormat.NumberDecimalSeparator = "."; - System.Threading.Thread.CurrentThread.CurrentCulture = customCulture; - - Match match = Regex.Match(statusLine, ":[0-9]{1,}:[0-9.]{1,}(\n|\r|\r\n)", RegexOptions.IgnoreCase); //Match only the progress line using regex - long counter = 0; - double leftT = 0; - double rightT = 0; - - while (match.Success) - { - - string[] items = match.ToString().TrimEnd().Split(':'); - - - collection.Add("LEFT" + counter, Convert.ToDouble(Decimal.Parse(items[1],CultureInfo.InvariantCulture))); - collection.Add("RIGHT" + counter, Convert.ToDouble(Decimal.Parse(items[2], CultureInfo.InvariantCulture))); - leftT += Convert.ToDouble(Decimal.Parse(items[1], CultureInfo.InvariantCulture)); - rightT += Convert.ToDouble(Decimal.Parse(items[2], CultureInfo.InvariantCulture)); - counter++; - match = match.NextMatch(); - } - collection.Add("LEFT_TOTAL" ,leftT); - collection.Add("RIGHT_TOTAL", rightT); - - } - - public Boolean runBenchmark(int benchMethod, int benchSecs, ref Dictionary collection,Boolean legacy) - { - - StringBuilder stdOutBuild = new StringBuilder(); - - string suffixArgs = " --restore-disable --potfile-disable --machine-readable --session=hashtopolis"; - string suffixExtra = ""; - - if (benchMethod == 1) - { - suffixExtra = " --runtime=" + benchSecs; - } - else if (benchMethod == 2) - { - suffixExtra = " --progress-only"; - } - - if (legacy) //--weak was removed post HC 3.6, don't issue this command - { - suffixArgs = suffixArgs + "--weak=0" + suffixExtra; - } - else - { - suffixArgs = suffixArgs + suffixExtra; - } - - ProcessStartInfo pInfo = new ProcessStartInfo(); - pInfo.FileName = Path.Combine(hcDirectory, hcBinary); - - if (!File.Exists(pInfo.FileName)) - { - Console.WriteLine("Could not locate " + pInfo.FileName); - return false; - } - - pInfo.WorkingDirectory = hcDirectory; - pInfo.Arguments = hcArgs + suffixArgs; - pInfo.UseShellExecute = false; - pInfo.RedirectStandardError = true; - pInfo.RedirectStandardOutput = true; - - - if (debugFlag) - { - Console.WriteLine("Using {0} as working directory", filesDir); - Console.WriteLine(pInfo.FileName + pInfo.Arguments); - } - - - Process hcProcBenchmark = new Process(); - hcProcBenchmark.StartInfo = pInfo; - - hcProcBenchmark.ErrorDataReceived += (sender, argu) => outputError(argu.Data); - - if (benchMethod == 1) - { - Console.WriteLine("Server requested the client benchmark this task for {0} seconds", benchSecs); - - } - else - { - Console.WriteLine("Server has requested the client perform a speed benchmark"); - - } - try - { - hcProcBenchmark.Start(); - hcProcBenchmark.BeginErrorReadLine(); - - while (!hcProcBenchmark.HasExited) - { - while (!hcProcBenchmark.StandardOutput.EndOfStream) - { - - string stdOut = hcProcBenchmark.StandardOutput.ReadLine().TrimEnd(); - stdOutBuild.AppendLine(stdOut); - if (stdOut.Contains("STATUS\t") && benchMethod !=2) - { - - { - parseStatus1(stdOut, ref collection); - } - - break; - } - } - } - hcProcBenchmark.StandardOutput.Close(); - - } - finally - { - hcProcBenchmark.Close(); - } - - if (stdOutBuild.ToString().Contains("Parsing Hashes: 0/")) //Can read from stderr for no hashes loaded, but this also works. - { - return false; - } - else - { - Console.WriteLine(stdOutBuild.ToString()); - } - - if (benchMethod == 2) - { - parseStatus2(stdOutBuild.ToString(),ref collection); - } - - return true; - } - - private static void parseKeyspace(string line, ref long keySpace) - { - line = line.TrimEnd(); - - if (!long.TryParse(line, out keySpace)) - { - Console.WriteLine("There was an error parsing the keyspace, setting keyspace to 0. Please review attack cmd"); - keySpace = 0; //Return 0 which will throw error - } - - } - - public string getVersion2(ref string[] versionNum) - { - ProcessStartInfo pInfo = new ProcessStartInfo(); - pInfo.FileName = Path.Combine(hcDir, hcBin); - pInfo.WorkingDirectory = filesDir; - pInfo.Arguments = "--version"; - pInfo.UseShellExecute = false; - pInfo.RedirectStandardError = true; - pInfo.RedirectStandardOutput = true; - Process hcGetVersion = new Process(); - - hcGetVersion.StartInfo = pInfo; - string versionString = ""; - - try - { - hcGetVersion.Start(); - versionString = hcGetVersion.StandardOutput.ReadToEnd().TrimEnd(); - hcGetVersion.WaitForExit(); - - Regex regex = new Regex("v(?[^-]*)"); - - Match match = regex.Match(versionString); - - if (match.Success) - { - versionNum = match.Groups["version"].Value.Split('.'); - - } - else - { - versionNum = versionString.Split('.'); //Hashcat changed the output after 3.6 to exclude the version string - } - } - catch - { - Console.WriteLine("Something went wrong when trying to get HC version"); - } - finally - { - if (hcGetVersion.ExitCode != 0) - { - Console.WriteLine("Something went when trying to get HC version"); - } - - hcGetVersion.Close(); - } - - return versionString; - } - public string getVersion() - { - - string stdOutSingle = ""; - ProcessStartInfo pInfo = new ProcessStartInfo(); - pInfo.FileName = Path.Combine(hcDir, hcBin); - pInfo.WorkingDirectory = filesDir; - pInfo.Arguments = "--version"; - pInfo.UseShellExecute = false; - pInfo.RedirectStandardError = true; - pInfo.RedirectStandardOutput = true; - Process hcGetVersion = new Process(); - hcGetVersion.StartInfo = pInfo; - hcGetVersion.ErrorDataReceived += (sender, argu) => outputError(argu.Data); - - try - { - - hcGetVersion.Start(); - while (!hcGetVersion.HasExited) - { - while (!hcGetVersion.StandardOutput.EndOfStream) - { - - string stdOut = hcGetVersion.StandardOutput.ReadLine().TrimEnd(); - stdOutSingle = stdOut; //We just want the last line - } - } - hcGetVersion.StandardOutput.Close(); - - } - catch - { - Console.WriteLine("Something went wrong when trying to get HC version"); - } - finally - { - - hcGetVersion.Close(); - } - - return stdOutSingle; - - - } - - public Boolean runKeyspace(ref long keySpace) - { - - Console.WriteLine("Server has requested the client measure the keyspace for this task"); - - string stdOutSingle = ""; - string suffixArgs = " --session=hashtopolis --keyspace --quiet"; - ProcessStartInfo pInfo = new ProcessStartInfo(); - pInfo.FileName = Path.Combine(hcDirectory, hcBinary); - - if (!File.Exists(pInfo.FileName)) - { - Console.WriteLine("Could not locate " + pInfo.FileName); - return false; - } - - pInfo.WorkingDirectory = hcDirectory; - - - pInfo.Arguments = hcArgs + suffixArgs; - pInfo.UseShellExecute = false; - pInfo.RedirectStandardError = true; - pInfo.RedirectStandardOutput = true; - if (debugFlag) - { - Console.WriteLine("Using {0} as working directory", pInfo.WorkingDirectory); - Console.WriteLine(pInfo.FileName + " " + pInfo.Arguments); - } - - Process hcProcKeyspace = new Process(); - hcProcKeyspace.StartInfo = pInfo; - hcProcKeyspace.ErrorDataReceived += (sender, argu) => outputError(argu.Data); - - try - { - hcProcKeyspace.Start(); - hcProcKeyspace.BeginErrorReadLine(); - - while (!hcProcKeyspace.HasExited) - { - while (!hcProcKeyspace.StandardOutput.EndOfStream) - { - string stdOut = hcProcKeyspace.StandardOutput.ReadLine().TrimEnd(); - stdOutSingle = stdOut; //We just want the last line - } - } - hcProcKeyspace.StandardOutput.Close(); - - } - catch - { - Console.WriteLine("Something went wrong with keyspace measuring"); - } - finally - { - if (hcProcKeyspace.ExitCode != 0) - { - Console.WriteLine("Something went wrong with keyspace measuring"); - } - - hcProcKeyspace.Close(); - } - - parseKeyspace(stdOutSingle,ref keySpace); - - return true; - } - - public static void outputError(string stdError) - { - if (!string.IsNullOrEmpty(stdError)) - { - Console.WriteLine(stdError.Trim()); - } - - } - - public void stdOutTrigger(string stdOut) - { - - if (!string.IsNullOrEmpty(stdOut)) - { - - if ((!stdOut.Contains("STATUS\t") && (!stdOut.Contains("EXEC_RUNTIME\t")) && (!stdOut.Contains("CURKU\t")))) - { - if (stdOut.StartsWith("Hashfile")) - { - if (!stdOut.Contains("Line-length exception")) - { - lock (crackedLock) - { - hashlist.Add(stdOut); - } - } - else - { - lock (crackedLock) - { - hashlist.Add(stdOut); - } - } - } - else - { - lock (crackedLock) - { - hashlist.Add(stdOut); - } - } - } - - else - - { - lock (statusLock) - { - Dictionary dStats = new Dictionary(); - - parseStatus1(stdOut, ref dStats); - - - lock (packetLock) - { - lock (crackedLock) - { - passedPackets.Add(new Packets { statusPackets = new Dictionary(dStats), crackedPackets = new List(hashlist) }); - dStats.Clear(); - hashlist.Clear(); - - } - } - } - } - - } - } - - - - public Boolean startAttack(long chunk, long taskID, long skip, long size, long interval, string taskPath) - { - - string oPath = Path.Combine(taskPath, taskID + "_" + chunk + ".txt"); // Path to write th -o file - if (File.Exists(oPath)) - { - File.Delete(oPath); // We need to wipe the outfile if it exists since we want to start at pos 0 - } - - ProcessStartInfo pInfo = new ProcessStartInfo(); - - pInfo.FileName = Path.Combine(hcDir, hcBin); - - if (!File.Exists(pInfo.FileName)) - { - Console.WriteLine("Could not locate " + pInfo.FileName); - return false; - } - - pInfo.Arguments = hcArgs + " --potfile-disable --quiet --restore-disable --session=hashtopolis --status --machine-readable --status-timer=" + interval + " --outfile-check-timer=" + interval + " --remove --remove-timer=" + interval + " -s " + skip + " -l " + size; - pInfo.WorkingDirectory = hcDirectory; - pInfo.UseShellExecute = false; - pInfo.RedirectStandardError = true; - pInfo.RedirectStandardOutput = true; - - if (debugFlag) - { - Console.WriteLine(pInfo.FileName + " " + pInfo.Arguments); - } - - hcProc = new Process { }; - hcProc.StartInfo = pInfo; - // create event handlers for normal and error output - - hcProc.OutputDataReceived += (sender, argu) => stdOutTrigger(argu.Data); - hcProc.ErrorDataReceived += (sender, argu) => outputError(argu.Data); - hcProc.EnableRaisingEvents = true; - hcProc.Start(); - hcProc.BeginOutputReadLine(); - hcProc.BeginErrorReadLine(); - - hcProc.WaitForExit(); - hcProc.CancelErrorRead(); - hcProc.CancelOutputRead(); - if (debugFlag) - { - Console.WriteLine("Attack finished"); - } - - - hcProc.Dispose(); - - return true; - - } - } -} diff --git a/csharp/hashtopolis/hashcatUpdateClass.cs b/csharp/hashtopolis/hashcatUpdateClass.cs deleted file mode 100644 index e14c700..0000000 --- a/csharp/hashtopolis/hashcatUpdateClass.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Diagnostics; - -namespace hashtopolis -{ - - class hashcatUpdateClass - { - - public class hcUpdateProper - { - public string action = "downloadBinary"; - public string type = "cracker"; - public string token = ""; - public int binaryVersionId = 0; - public int force { set; get; } - - } - - public Boolean debugFlag { get; set; } - public string AppPath { get; set; } - public _7zClass sevenZip { get; set; } - public registerClass client { get; set; } - public int binaryVersionId { get; set; } - - - public bool updateCracker() - { - hcUpdateProper hcUpd = new hcUpdateProper(); - jsonClass jsonUpd = new jsonClass { debugFlag = debugFlag, connectURL = client.connectURL }; - hcUpd.token = client.tokenID; - hcUpd.binaryVersionId = binaryVersionId; - - string jsonString = jsonUpd.toJson(hcUpd); - string ret = jsonUpd.jsonSend(jsonString); - - if (jsonUpd.isJsonSuccess(ret)) - { - string crackerName = jsonUpd.getRetVar(ret, "name"); - string fullSubDir = Path.Combine(AppPath, crackerName.ToLower(), binaryVersionId.ToString()); - if (!Directory.Exists(fullSubDir)) //We need to download - { - Console.WriteLine("Client doesn't have required cracker..."); - downloadClass dlClass = new downloadClass(); - if (client.osID != 1) - { - dlClass.DownloadFileCurl(jsonUpd.getRetVar(ret, "url"), Path.Combine(AppPath, "crackerClient.7z")); - } - else - { - dlClass.DownloadFile(jsonUpd.getRetVar(ret, "url"), Path.Combine(AppPath, "crackerClient.7z")); - } - - if (Directory.Exists(Path.Combine(AppPath, "tmp"))) - { - Directory.Delete(Path.Combine(AppPath, "tmp"), true); - } - - sevenZip.xtract(Path.Combine(AppPath, "crackerClient.7z"), Path.Combine(AppPath, "tmp")); - - //check if files present - - string[] files = Directory.GetFiles(Path.Combine(AppPath, "tmp")); - if (files.Length != 0) - { - Directory.Move(Path.Combine(AppPath, "tmp"), fullSubDir); - } - else - { - string[] dirs = Directory.GetDirectories(Path.Combine(AppPath, "tmp")); - Directory.Move(dirs[0], fullSubDir); - } - - Directory.Delete(Path.Combine(AppPath, "tmp")); - string binLocation = Path.Combine(fullSubDir, jsonUpd.getRetVar(ret, "executable")); - - if (client.osID != 1) //Chmod for non windows - { - Console.WriteLine("Applying execution permissions to cracker binary"); - Process.Start("chmod", "+x \"" + binLocation + "\""); - } - - //May need to inplement legacy checks if cracker is hashcat - } - else - { - Console.WriteLine("Client already exists, skipping download"); - } - client.crackerBinary = jsonUpd.getRetVar(ret, "executable"); - - - if (client.is64Bit) - { - client.crackerBinary = client.crackerBinary.Replace(".", "64."); - } - else - { - client.crackerBinary = client.crackerBinary.Replace(".", "32."); - } - - - - client.crackerPath = Path.Combine(AppPath, crackerName.ToLower(), binaryVersionId.ToString()); - } - - - if (Directory.Exists(client.crackerPath)) - { - return true; - } - else - { - Console.WriteLine("Could not locate cracker, perhaps manually delete cracker " + binaryVersionId.ToString()); - return false; - } - } - - - public bool updateHashcat() - { - hcUpdateProper hcUpd = new hcUpdateProper(); - jsonClass jsonUpd = new jsonClass { debugFlag = debugFlag, connectURL = client.connectURL }; - hcUpd.token = client.tokenID; - string hcBinName = "hashcat"; - if (client.osID == 0) - { - hcBinName = hcBinName + "64.bin"; - } - else if (client.osID == 1) - { - hcBinName = hcBinName + "64.exe"; - } - - string hcBinLoc = Path.Combine(AppPath, "hashcat", hcBinName); - - if (File.Exists(hcBinLoc)) - { - hcUpd.force = 0; //HC exists, we don't need to force - } - else - { - hcUpd.force = 1; //HC doesn't exist, we need to force - } - - string jsonString = jsonUpd.toJson(hcUpd); - string ret = jsonUpd.jsonSend(jsonString); - - if (jsonUpd.getRetVar(ret, "version") == "NEW") - { - downloadClass dlClass = new downloadClass(); - - if (client.osID != 1) - { - dlClass.DownloadFileCurl(jsonUpd.getRetVar(ret, "url"), Path.Combine(AppPath, "hcClient.7z")); - } - else - { - dlClass.DownloadFile(jsonUpd.getRetVar(ret, "url"), Path.Combine(AppPath, "hcClient.7z")); - } - - sevenZip.xtract(Path.Combine(AppPath, "hcClient.7z"), Path.Combine(AppPath, "hcClient")); - if (Directory.Exists(Path.Combine(AppPath, "hashcat"))) - { - Directory.Delete(Path.Combine(AppPath, "hashcat"), true); - } - Directory.Move(Path.Combine(AppPath, "hcClient", jsonUpd.getRetVar(ret, "rootdir")), Path.Combine(AppPath, "hashcat")); - Directory.Delete(Path.Combine(AppPath, "hcClient")); - - - if (client.osID != 1) //Chmod for non windows - { - Console.WriteLine("Applying execution permissions to 7zr binary"); - Process.Start("chmod", "+x \"" + hcBinLoc + "\""); - } - } - - if (File.Exists(hcBinLoc)) - { - return true; - } - - return false; - - } - - } -} diff --git a/csharp/hashtopolis/hashtopolis.csproj b/csharp/hashtopolis/hashtopolis.csproj deleted file mode 100644 index 489c60e..0000000 --- a/csharp/hashtopolis/hashtopolis.csproj +++ /dev/null @@ -1,99 +0,0 @@ - - - - - Debug - AnyCPU - {199AD37B-3000-4CC0-992C-87738F84C768} - Exe - Properties - hashtopolis - hashtopolis - v4.5 - 512 - true - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - small.ico - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/csharp/hashtopolis/hashtopolis.csproj.user b/csharp/hashtopolis/hashtopolis.csproj.user deleted file mode 100644 index 9fcb30c..0000000 --- a/csharp/hashtopolis/hashtopolis.csproj.user +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/csharp/hashtopolis/jsonClass.cs b/csharp/hashtopolis/jsonClass.cs deleted file mode 100644 index 8d18b23..0000000 --- a/csharp/hashtopolis/jsonClass.cs +++ /dev/null @@ -1,254 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Collections; -using System.Web.Script.Serialization; -using System.Linq; -using System.Threading; - -public class jsonClass -{ - - public Boolean debugFlag { get; set; } - public string connectURL { get; set; } - Random rnd = new Random(Guid.NewGuid().GetHashCode()); //init and seed the random generator for use in re-try backdown - JavaScriptSerializer jss = new JavaScriptSerializer(); - //Checks if json string has success response - //Will print the error messages on fail - public Boolean isJsonSuccess(string jsonString) - { - jss.MaxJsonLength = 2147483647; - - if (debugFlag) - Console.WriteLine(jsonString); - - try - { - Dictionary dict = jss.Deserialize>(jsonString); - - if (dict.ContainsKey("response")) - { - if (dict["response"] == "SUCCESS") - { - return true; - } - else - { - Console.WriteLine(dict["response"]); - if (dict.ContainsKey("message")) - { - Console.WriteLine(dict["message"]); - } - } - } - return false; - } - catch (Exception e) - { - Console.WriteLine(e.Data); - Console.WriteLine("Empty string for success check"); - return false; - } - - } - - - //Returns variable from json string, values are casted to string - public string getRetVar(string jsonString, string itemVar) - { - jss.MaxJsonLength = 2147483647; - - try - { - var dict = jss.Deserialize>(jsonString); - if (dict.ContainsKey(itemVar)) - { - return Convert.ToString(dict[itemVar]); - } - } - catch(Exception e) - { - Console.WriteLine(e); - Console.WriteLine("Error while trying to get {0} from jaon string", itemVar); - } - - - return null; - } - - //Returns json string array to arraylist - //This is probably redundant as we can use the below function gerRetList to return a better typed array - public ArrayList getRetArray(string jsonString, string itemVar) - { - jss.MaxJsonLength = 2147483647; - - var dict = jss.Deserialize>(jsonString); - if (dict.ContainsKey(itemVar)) - { - return dict[itemVar]; - } - - return null; - } - - //Return json string array to list with type string - public List getRetList(string jsonString, string itemVar) - { - jss.MaxJsonLength = 2147483647; - - var dict = jss.Deserialize>(jsonString); - if (dict.ContainsKey(itemVar)) - { - List newList = new List(dict[itemVar].ToArray(typeof(string))); //Convert Array to List - return newList; - } - - return dict[itemVar]; - } - - //Converts array=>key to jason string format - public string toJson(object obj) - { - jss.MaxJsonLength = 2147483647; - - var json = jss.Serialize(obj); - if (debugFlag) - Console.WriteLine(json); - return json; - } - - - public string jsonSendOnce(string json) - { - var request = (HttpWebRequest)WebRequest.Create(connectURL); - request.ContentType = "application/json"; - request.Method = "POST"; - request.KeepAlive = false; - - int randomTime = 0; - - HttpWebResponse response = null; - int tries = 0; - { - Thread.Sleep(tries * 1000 + randomTime * 1000); - try - { - using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream())) - { - streamWriter.Write(json); - } - - } - catch (WebException ex) - { - Console.WriteLine(ex.Message); - return null ; - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - return null; - } - - try - { - response = (HttpWebResponse)request.GetResponse(); - string result; - using (var streamReader = new StreamReader(response.GetResponseStream())) - { - result = streamReader.ReadToEnd(); - } - - return result; - } - catch(WebException ex) - { - Console.WriteLine(ex.Message); - } - - - return null; - - } - } - - //On fail, the client will use a backdown algorithm and retry 30 times - public string jsonSend(string json, int timeOutSecs = 30) - { - - int tries = 0; - int randomTime = 0; - string result = null; - - do - { - Thread.Sleep(tries * 1000 + randomTime * 1000); - - try - { - - var request = (HttpWebRequest)WebRequest.Create(connectURL); - request.ContentType = "application/json"; - request.Method = "POST"; - request.Timeout = timeOutSecs * 1000; - request.KeepAlive = true; - - HttpWebResponse response = null; - - using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream())) - { - streamWriter.Write(json); - } - - - response = (HttpWebResponse)request.GetResponse(); - if (response.StatusCode != HttpStatusCode.OK) - { - Console.WriteLine("Invalid HTTP response"); - Console.WriteLine("terminating"); - Environment.Exit(0); - } - - - using (var streamReader = new StreamReader(response.GetResponseStream())) - { - result = streamReader.ReadToEnd(); - } - if (string.IsNullOrEmpty(result)) - { - Console.WriteLine("server is not responding to requests"); - Console.WriteLine("terminating"); - Environment.Exit(0); - } - break; - } - - catch (WebException ex) - { - if (ex.Status == WebExceptionStatus.Timeout) - { - Console.WriteLine("Server timed out"); - Console.WriteLine(ex.Message); - tries++; - randomTime = rnd.Next(1, tries); - Console.WriteLine("Attempting to re-connect in {0} seconds", tries + randomTime); - } - } - catch (Exception) - { - Console.WriteLine("Could not connect to specified server, exiting"); - tries++; - randomTime = rnd.Next(1, tries); - Console.WriteLine("Attempting to re-connect in {0} seconds", tries + randomTime); - } - - } while (tries <= 10); - - - return result; //Return json string - - } - - -} \ No newline at end of file diff --git a/csharp/hashtopolis/registerClass.cs b/csharp/hashtopolis/registerClass.cs deleted file mode 100644 index cfef1a0..0000000 --- a/csharp/hashtopolis/registerClass.cs +++ /dev/null @@ -1,485 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Management; -using System.Diagnostics; -using System.Runtime.InteropServices; - -public class registerClass -{ - private string tokenPath; - public string tokenID { get; set; } - public int osID { get; set; } - public Boolean is64Bit { get; set; } - public string connectURL { get; set; } - public Boolean debugFlag { set; get; } - public string crackerPath { set; get; } - public string crackerBinary { set; get; } - - //Suppress P/Invoke warning my using NativeMethods - internal static class NativeMethods - { - [DllImport("libc")] - public static extern int uname(IntPtr buf); - } - - //Code from Pinta Core Project - private bool IsRunningOnMac() - { - - IntPtr buf = IntPtr.Zero; - try - { - buf = Marshal.AllocHGlobal(8192); - // This is a hacktastic way of getting sysname from uname () - if (NativeMethods.uname(buf) == 0) - { - string os = Marshal.PtrToStringAnsi(buf); - if (os == "Darwin") - return true; - } - } - catch - { - } - finally - { - if (buf != IntPtr.Zero) - Marshal.FreeHGlobal(buf); - } - return false; - } - - //Code to run commands - private static string ReadProcessOutput(string procName, string args) - { - try - { - Process p = new Process(); - p.StartInfo.UseShellExecute = false; - p.StartInfo.RedirectStandardOutput = true; - if (args != null && args != "") p.StartInfo.Arguments = " " + args; - p.StartInfo.FileName = procName; - p.Start(); - string output = p.StandardOutput.ReadToEnd(); - p.WaitForExit(); - if (output == null) output = ""; - output = output.Trim(); - return output; - } - catch - { - return ""; - } - } - - //Detect whether we are running under mono - private void setOS() - { - is64Bit = false; //Default to 32bit unless 64bit detected - if (Type.GetType("Mono.Runtime") != null) - { - - string machine = ReadProcessOutput("uname", "-m"); - if (machine.Contains("x86_64")) - { - is64Bit = true; - } - - if (!IsRunningOnMac()) - { - - if (is64Bit) - { - Console.WriteLine("System is Linux 64-bit"); - } - else - { - Console.WriteLine("System is Linux 32-bit"); - } - osID = 0; - } - else - { - if (is64Bit) - { - Console.WriteLine("System is MAC 64-bit"); - } - else - { - Console.WriteLine("System is MAC 32-bit"); - }; - osID = 2; - } - - - - } - else - { - - if (Environment.Is64BitProcess) - { - Console.WriteLine("System is Windows 64-bit"); - is64Bit = true; - } - else - { - Console.WriteLine("System is Windows 32-bit"); - } - osID = 1; - } - - } - - public void setPath(string path) - { - tokenPath = Path.Combine(path,"token"); - } - - private class Register - { - public string action { get; set; } - public string voucher { get; set; } - public string name { get; set; } - } - - private class UpdateClient - { - public string action { get; set; } - public string token { get; set; } - public string uid { get; set; } - public int os { get; set; } - public IList devices { get; set; } - } - - - private bool registerAgent(string iVoucher) - { - jsonClass jsC = new jsonClass { debugFlag = debugFlag, connectURL = connectURL }; - string machineName = "default"; - setOS(); - - if (osID == 1) //Windows - { - machineName = System.Environment.MachineName; - } - else if (osID == 0) //Linux - { - ProcessStartInfo pinfo = new ProcessStartInfo(); - pinfo = new ProcessStartInfo(); - pinfo.FileName = "uname"; - pinfo.Arguments = "-n"; - pinfo.UseShellExecute = false; - pinfo.RedirectStandardOutput = true; - Process uname = new Process(); - uname.StartInfo = pinfo; - uname.Start(); - while (!uname.HasExited) - { - while (!uname.StandardOutput.EndOfStream) - { - string stdOut = uname.StandardOutput.ReadLine(); - machineName = stdOut; - } - } - } - else if (osID == 2) //Mac - { - //Get Machine Name (Mac) - ProcessStartInfo pinfo = new ProcessStartInfo(); - pinfo.FileName = "scutil"; - pinfo.Arguments = " --get ComputerName"; - pinfo.UseShellExecute = false; - pinfo.RedirectStandardError = true; - pinfo.RedirectStandardOutput = true; - - Process getMachineName = new Process(); - getMachineName.StartInfo = pinfo; - getMachineName.Start(); - while (!getMachineName.HasExited) - { - while (!getMachineName.StandardOutput.EndOfStream) - { - string stdOut = getMachineName.StandardOutput.ReadLine(); - machineName = stdOut; - } - } - - } - - Register regist = new Register - { - action = "register", - voucher = iVoucher, - name = machineName, - }; - - string jsonString = jsC.toJson(regist); - string ret = jsC.jsonSend(jsonString); - - String guid = Guid.NewGuid().ToString(); //Generate GUID - - if (jsC.isJsonSuccess(ret)) - { - tokenID = jsC.getRetVar(ret, "token"); - File.WriteAllText(tokenPath, tokenID); - - updateAgentInformation(); - - return true; - } - return false; - - } - - - - private bool updateAgentInformation() - { - Console.WriteLine("Sending server client information"); - jsonClass jsC = new jsonClass { debugFlag = debugFlag, connectURL = connectURL }; - - setOS(); - - - List deviceList; - string CPUModel = ""; - - deviceList = new List { }; - - if (osID == 1) - { - ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Description FROM Win32_VideoController"); //Prep object to query windows GPUs - - //Get Devices (Windows) - foreach (ManagementObject mo in searcher.Get()) - { - deviceList.Add(mo.Properties["Description"].Value.ToString().Trim()); - } - - //Get CPU (Windows) - searcher = new ManagementObjectSearcher("SELECT Name from Win32_Processor"); //Prep object to query windows CPUs - foreach (ManagementObject mo in searcher.Get()) - { - deviceList.Add(mo.Properties["Name"].Value.ToString().Trim()); - } - - } - else if(osID == 0) - { - - //Get GPU Devices (Linux) use lspci to query GPU - ProcessStartInfo pinfo = new ProcessStartInfo(); - pinfo.FileName = "lspci"; - pinfo.UseShellExecute = false; - pinfo.RedirectStandardOutput = true; - Process lspci = new Process(); - lspci.StartInfo = pinfo; - lspci.Start(); - List searchList = new List(new string[] { "VGA compatible controller: ", "3D controller: "}); - - - while (!lspci.HasExited) - { - while (!lspci.StandardOutput.EndOfStream) - { - string stdOut = lspci.StandardOutput.ReadLine(); - foreach (string searchItem in searchList) - { - int pozi = stdOut.IndexOf(searchItem); - if (pozi != -1) - { - deviceList.Add(stdOut.Substring(pozi + searchItem.Length)); - } - } - - } - } - - //Get CPU (Linux) use lscpu to query CPU - pinfo.FileName = "lscpu"; - pinfo.UseShellExecute = false; - pinfo.RedirectStandardOutput = true; - lspci.StartInfo = pinfo; - lspci.Start(); - string searchString = "Model Name: "; - while (!lspci.HasExited) - { - while (!lspci.StandardOutput.EndOfStream) - { - string stdOut = lspci.StandardOutput.ReadLine(); - int pos = stdOut.IndexOf(searchString); - if (pos != -1) - { - deviceList.Add(stdOut.Substring(pos + searchString.Length)); - } - } - } - } - else if(osID == 2) - { - //Get Machine Name (Mac) - ProcessStartInfo pinfo = new ProcessStartInfo(); - pinfo.FileName = "scutil"; - pinfo.Arguments = " --get ComputerName"; - pinfo.UseShellExecute = false; - pinfo.RedirectStandardError = true; - pinfo.RedirectStandardOutput = true; - - - //Get Devices (Mac) - pinfo.FileName = "system_profiler"; - pinfo.Arguments = " -detaillevel mini"; - Process getDevices = new Process(); - getDevices.StartInfo = pinfo; - - Console.WriteLine("Please wait while devices are being enumerated..."); - getDevices.Start(); - Boolean triggerRead = false; - - string searchID = "Chipset Model: "; - - while (!getDevices.StandardOutput.EndOfStream) - { - - string stdOut = getDevices.StandardOutput.ReadLine().TrimEnd(); - - if (triggerRead == true) - { - if (stdOut.Contains("Total Number of Cores:")) //Just incase we go past - { - break; - } - if (stdOut.Contains("Hardware:")) - { - searchID = "Processor Name: "; - } - int pos = stdOut.IndexOf(searchID); - - if (pos != -1) - { - if (searchID == "Chipset Model: ") - { - - deviceList.Add(stdOut.Substring(pos + searchID.Length)); - - } - else if (searchID == "Processor Name: ") - { - CPUModel = stdOut.Substring(pos + searchID.Length); - searchID = "Processor Speed: "; - } - else if (searchID == "Processor Speed: ") - { - CPUModel = CPUModel + " @ " + stdOut.Substring(pos + searchID.Length); - deviceList.Add(CPUModel); - break; - } - } - } - else if (triggerRead == false) - { - if (stdOut.Contains("Graphics/Displays:")) - { - triggerRead = true; - } - } - - - } - } - - String guid = Guid.NewGuid().ToString(); //Generate GUID - - UpdateClient update = new UpdateClient - { - action = "updateInformation", - token = tokenID, - uid = guid, - os = osID, - devices = deviceList - }; - - string jsonString = jsC.toJson(update); - string ret = jsC.jsonSend(jsonString); - - if (jsC.isJsonSuccess(ret)) - { - return true; - } - return false; - - } - public bool loginAgent() - { - if (!loadToken()) - { - Console.WriteLine("Unable to find existing token, please enter voucher"); - while (registerAgent(Console.ReadLine()) == false) - { - Console.WriteLine("Invalid voucher, please try again"); - } - - - } - else - { - Console.WriteLine("Existing token found"); - jsonClass jsC = new jsonClass { connectURL = connectURL, debugFlag = debugFlag }; - - var arrayKey = new Dictionary - { - { "action", "login" }, - { "clientSignature", "generic-csharp"}, - { "token",tokenID}, - }; - - string jsonString = jsC.toJson(arrayKey); - string ret = jsC.jsonSend(jsonString); - - if (jsC.isJsonSuccess(ret)) - { - - updateAgentInformation(); - return true; - } - else - { - Console.WriteLine("Existing token is invalid, please enter voucher"); - while (registerAgent(Console.ReadLine()) == false) - { - Console.WriteLine("Invalid voucher, please try again"); - } - } - return false; - } - return true; - - } - - public bool loadToken() - { - - if (tokenID == "") - { - if (File.Exists(tokenPath)) - { - tokenID = File.ReadAllText(tokenPath); - if (tokenID == "") - { - File.Delete(tokenPath); - return false; - } - } - else - { - return false; - } - setOS(); - } - - return true; - } - -} diff --git a/csharp/hashtopolis/small.ico b/csharp/hashtopolis/small.ico deleted file mode 100644 index 1eb93a9429ac087b5bf6a4e7885a97d8310bb79d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7140 zcmaiZ?U`;J^G|009huDH;HP;vYw9X(-`?s6qcIzA{u^=YQ(|3j4)B zxbn9+1^{SMmE~n%J}bw$z5%d><&gZ$(Qk?2iQ&0mE@f<>j9UT&2s(%ns?vmjx0Efl z&s4yRt&Z6S$t!O>dY>dsnhcwarR75}knCfe{!j*-{VlF(EmO zc$UIpQEXY*h){}y@`6}2jYLgJUotJ3I2a(9_`!7uf~+s%O~gjh4va2Y--H z2~NO#lHqFfO(Fei{kHC_2SO-QJ@&{V3AyhlSvaOOd(EX6Fa#eMkEcj-*sIU;OTg)_ zoNvtYl^-WKjYBd_WCXwvqkE_GKBhNj#gW}9>UGmA?^#F6mb0}}dZ0l=nc?5#7qAW% z^E2_TEwp zl`~2f{>2&GpFcpz8~F_FJ>Yt_jO|9!TaeKdxx!KSu@_3`=tcF)Aj3jurpb4MguL+| zixTz5gkmr4&(U+ZHF0RuByx^Vx3Dr~YRH;pM{OgoBP`ED(P)b^%H>}mYQ$uyt}nGM z*a1hS5ixfw=Os#x8#upuu&z+wv;nU>pf(LCf1yg>ti2wm3*I)NCF}K%h73-Df^0=+ z_3jAgb)4QUISk>@R7c4!bYh21jwj->xPq z$QU#M9b!Y@Jnz8z8&V{3z{|SnXYbfE_;q$*4WO+GG&4e@Ud3d<38=DFmFDcB_;L5d zDz6pdZVnk*Xw%f5elO|9^HK|FA@L3)2hG{43%i9e5)F3l6{7H`YM;BJ2rb7BeHBdw z*nA#ADZ~_w2D@khh~mHB`v_CP_&q7=g%OK(WR=U_!W552c3~NEgfzNMlr0Bb1svRe zAg)auFWp*;g@RnQP{^cDw}>zuAj-j(yD5n0$@s^2PIBqYV<0c_+MrjGixL+G`?g27 zLC7>m3TPwaFWGI=P0YX&fWiPs&@f#~Zb6S#gjO~y8}sh9bPSYKnwY$2YoA!LU%nAR zp$-J=0KuWvfTut@2Gc`%-4H?QM`IwhV+!cAVobjMK^5_bROT$SuhEw5yL=Tp{93p` zE?e|+_!dVGhg2S>u?P#fbWFf(i8AJQ#cwbGx5iz)x->UiF`9$68u9?*X=s5_zFT*2 zqbFPcPgQ|^QpSC6)EC4!*qzT(rT6o2+Ca~x8~}j5r_G4plh|uCu6smK>qGLdDXZ_Q z(P6md?FhF|PR;eE{GqNCXVttxPwNdKt_-?wF`a0Pr;$yJ(`c!|h?)1J!)Q#y4 zi@2)F{;Qv=m19EV!kQohLS^ddD}w>=AV?II^XEbPzK@m?koJ_eq07`E;UsWGB^GHV zOspXfL*iR*4?687@+RRNfFp5Y1N>XD{*Jt^J~3y{I1AR{F7fCe7|e94wXL_gcowg& zQ~Fe8(DeoRzS!b#@)&So%6W$(`!!Q*+6QwLz11PXnx+`9Al$eLgI5fCAblR0&H~18 zdP+y{1uZ(}>FurQZNA8r$17;iOzR1LA!+x$kcYspQhj~)@N6NzOz*O*jI&DLPotoZ z7Z&;srbg4W958#zvbM2W*O_ACiCxt!{FgzHcl?VoSur9o2h*sWgdr4vAm{=?*{0rURNqS)RBjPJg+2 zO|b0zE<0pt19+w?xAWtj*hj~=>ll@qJREv{SW&a>j&F~@H=y=8wc6t_^SBK&t?qBw zv{Hd1yHPRlwPjj@17j(1mY=6-MV{v z{H*$jMHe(pSyMVzu3$>4%Q?6f+vgx$)oJX5Lb)2r}YzcSLX7=kQ(o|Di_XI4w?yTJ2+(-PjclkpmW#&k0b z*+X7O-I2H#2s~YZDO})A+$TSECaN!X)-O3-!#-0DU$)6auhV3-X36y-pNR~{d)NJK zaCd0d+=3FhBeu+jE(!>L%KE2KNZM49MO`E9GfO1C?Wxsb8NTqZGPwx z#~>^Q4DGq;kQf^F5;CYefQi>uUq z(rzDOCvEO0F#LE`;Z%;)x&#fVUP&iM&gCyznNwSK`7Yr$bvcD}FQ2s2Qa1bbjaxH~ zn4r`<~guYG@=rjCk%kWvoVRXu3eX&f-i&c0UzsI9sI( z_}oZe&WyCkdd)-CKk>ouUcV?L3H|7}gXZEM?Ckyy$m$BQi?%A>47y}V)5o8QXozlNUke))NDl$d5ZMVj<1c`mzCwcO%m4K91%n(|}#=yVK zKaWMf|6#KjuNVPtP_y3Z01>SP9!$y1HYNE$OuUUkN(PJZ6;W~vBB55Hp|(0X3&O|p9r zbkjs~2ULANK$FF#TuGi})mL==i@H6sTc+9}3?~J-fdtRN7KC!YMYAxDzTo0hw==hD z_566NyZGqcJVx1+;C13A{?fGyu*etF#3_`x!2F~a=Ab+q3e0(LXtob(C37w)xIZOZ z;B(?`q#f3U7XkLqgx6i=i&q-`UpTptaC38ax${V`aD8nHO$ zl>GJds2`uqSyZ<&xbop6l}YGo>JXnl2GoWFN1#FPFP3gNL8yaO^AF6ZlmT87hxAw| zet+uocPJWRa#=MXCIc;JMtEKGDil2`NGHS6Cl?YPe@F906s<=y2T;-gRR!|5;p4i( z;NDUrtZv427NNv;PB!OW5wjCy6>$_asv!jx_fHYD7+h<19fJI;*jGQM(C51(nyHR( zn)p;GRDpMpb##hGnF;T?&WT1);^%`h{b6%}qTBn^Z-1%*_I&gqfj|zm%~IVq{BF^Uo;FRZ+&FX44xfm5LQt8jWi?hqk!0|= zueEz%m0db&NW7|H)y|rCF)!`j5rc9t^=ELpPPK97s0Pg^(06VFe_^#lSPex{vD~qu z+26qEgA-yvjrfPxzQ#bize_6YzumqUg)i)(803kbGi^?;&YZ!q9Rm7mznB*6$eJs1 z)&K%pGutah%^;%jR0)*Kcu(cR-ov_l7C;7f-jcB%E6JhPeMe9@MYC&@NX8!U}+z=z)b+E7a`I>M$bMUh>JDd+8sUwjBp zcIklHV%?4*GNP>Vx?6BwW55a{vG~!9z;~aiZA*F+P`+);NyUu7c;z3sL$I3?{wq-8 zUUW##WNfQwLT_~LwNaj~yO{3({-`lzaClWd=}h7&yzMe4u@-eM5hL4J zGdJnruGj|vs&`fcy=n+G$Afz1%zwq;Z8HXKHeQvmFNy8F*FZb;>jH0y9`K?k2`;=n z1!4w-gRwK>6(WS5MJ$>z0R0P9_Alh$^w_7d?`_vdwEasp>>cNkDIL>;_ru>vWhm$9;8isb;WFy!7^;V9aadCu9!J=^ zO8sDey5lgjXRsErOy73^+vwU{o-3Pa=(z<{`#{vicV@XsAn6T8BUP5!ZS#dnRupvZ ziMG|_(NjB@~rnD9*$+WQ}3uv(rq3087Hg3sQ*-akJs9Y zm{6E^=(#o$sF{woJO%5c#EUt`oO5SAY%ivQiTY4Px6Yy$N@GKec%Wa{hjEI2K<3aT zNhw^u(v)|o6i>~Kj-pn(S}FQTy?Pf8J&hOeEVBFK*>@%7N)_x_&-jaFai2X`-`ODw zc*59EN+&i?Kg{`pL{mjO05_UFhhFDjv*Fni5?@5Q{U#a27$JYe|3tuuhDuU>l0Cyv z45^E-($0k6Rr^j^A8MTU;Wto5zP?&deUVV{1(&5>G@;>8t*I?49@a2E!TJeE&aRz# z0Xs#V++PECct`J(3S-icQr+lDzgOBp6@P{vb*@(bz3E;uNe0z~_%Ct+&AMO7(;XAm zb*k1fWDwtc>bQ4?#rKp!<+3N?>UCxX-&5N^UIc*PHmf%;ag~2`nNUpd+BG6_=dT?% zy;J?X8W78PbKDgSI))=kq78XuqDdvz#eIKQ!^q4;BZx{z-h6d|Z*V~Hm@y~?KOJe&R+AhaDGmWSIS$ARYY*@zGUC}2 zA!Q@&1e2YjIlu`48rsU-_=Y&l(f=MZ2v}rdnLkco`1_^8%MP4?DhtI1+-A=ILxsY z^(h5@WY>2akYDawtNq7?VF0+D0_hoVsg<>UU2H$_wfsA`3|o+*NIX@o!&@Vl66hww z>;SmbIiP!6yVON->kYa1n72m2za;<_s);GsfynWDhD0)x4$z;tY+4PUi!!AyLv;=C z8tU(lKF7&IY@=B}b7)X|eZ4^A!J*`tr+3^{Fn4XJg^*Q~8?!@nt8R7_MPCsV$Fun= zRD`@7cm`=Y`nfFetGm4`&a{G*()s|^v~%88Xb%=v5%IfrKF^GR=-{F<228rN^Io9H zMoqU=qt#5p5fP@=gsl*>MgMj(k9<{0WMjEr)kpgNN!aUFU!XkyFowyZpT4_^J(M3= zf3&NwFRHe&nZd9pykt0CN{zU!L=PO_#(Vh@PW%30he0U^z4&ePrH@3;=Gn|s?Tc*3 z&BQR=PxU>6X6;=MSsk##IMp1>moc|ZG20bL3<7H*+5R7UdLfs`_@k}32*GKiM_RgKO@DsyD0gizWZNez>}%UH4);S3=o@dH ziG)$sErR@Eqxsf}2Fo|g&4nrr<1)Gb&ZA@P;I4jlGhL-^VsdkQf-SQpOcVnS|S;*Ler5&vsaywv^mJJB|dDm5-$pIDxe zQf>Q}0@@>rbo)$J8DlMhE-P2uy2wo?I(y~_0$R}{Rp#4(UTaeusPvdjK>3BqwB?EW z%Lj~)q5|e$FSvqv*q3MeK*UoduU#kS0q3r!mw`@(<>GU{Q?Cef&Vcl^QuXc!eP3K#0v9Ts-Jr2wdk}wKb_FbpJN8^+1OVW zMzJEnTYr?m1tF=52W2HFrs(owg38eDZ&CYt7bQDGGvG$gt+4rqo zT4LFmCn>Hv5Ln5TepSHAeZ8MnA>)1LNrF%Yo2Mb|b%f3c>A|hPgmiNl{?puU=&zSK zhclN|l}B!_pEq#&TBB=!nu|y4uH0l*c2W*IbNUOMl#Tq57RZ_w$aaeoF^|G_-c!>* ztcyB*UyNAD`IGvTZT<4R_gjEn{+(4lVmq9&3N0V%_Xo zrAV5Iqiy|TaUtAyzksak%?W>F9jCtTWxw*dc&dS&BV=~26P6w+p663%V zuN6c2T<9AM1^UZpcqy$d#!Jf1R`nehg5M91`>1yc`&yqH5q96~lGHtA4D#=7C>jI- zanNX^aoJ>iDqIr7fyH)B6%ehh-rUvSVS495OsEa%Mm*hzEdPVgN zY$k*-CND~WU)f$5{RNbdnc^6gJPf>YOH4uO$OP`UA9-qK;jpEFbttF7{5h_|Qj^bT z9eH^S&8o?K54r}4!Yo-Fg|Rx(WuLQHv#?pip;l4MNrqcdq@ufD*#&fEFjC2MWys+I zv$B*0|1rmdF^M!g#~)i0-usz^EY~W3+{FmJ2vLbGO7i#Vx>maKn30P;7-3;N7klb; zHxXj+$8gx=)x|T~QXa69y7r<|ujB-f>5h5cQlCLM+w#?~=wE-7qXmcK?u!3RaM;!C zEFsetAL(6u?jv$JZ(Mq%pXKm550kpAB$>LR4EP0EK+pFdbB-$$HrxEE@e}LoRBuXJ zApvB1=IU^^nd;jGloph@l)WT_)2XZ=%`eNLkoi+26)A-*4qKMPmw*2XdCcSi29n=O zQeW;`Wdla6qEXMP)t1bLaM4lM{DMe#4Yye99ajX2N?8$7u#}WDqn=2G3kS@PBGaK# zCV7~qe;t}pgTW{NWx5GMIdd6`YF{h|9~N% z6JC715BC=-`N0d1ykMii7JKDf6f1sJ{|S9Z3mO(5V1HuGm?Kk^s6mm5$7a4nt}Aw0 zKOgjGKNd||Ji$HNLcMB>3~PCij=&v3oj=He!<1!Nlr-q`ovO?#{5X4f`)yv4+M}u; zt5DKfUzmBz`=-)VkVaiP{c^vhis>2ZnwA*Mo5eL{LE9g7X+^=OM0Uni*(5jmJNsu= z#?*GsVPTuA#4fEZp;SYHH4OABjw{?yXLJXzfl@h`ewVW40zaWqW||Ay4OOZOS1_NP zHJNrJX!!J#b_3jG?%Pch5y2jrJmu2>WnQj~)|y%suVqfH!d;Qbjx%?kb+H#)gbXNY zCML=Ah954Uun?Bo{X5)JKAj-f`dtz_oOkLc-bi_^vu4^-FYB%Gd^p;p3!8+KQ;qf? zEo>@m7<26CvEC14PtEZ}jCLOI*|+FlUGOq@E#|<|>Xv2B_!ep0!uLg{6RIO+g%kEg ztj_v%$L-Quvp$dK`aS~Q*a*Jl>jNaEo}=eC#4`uczZZzoHXYhk1OGa1&lD&RM=4Q)0j}eALd~wc0#HR?$(o|#jo4nd3#Tx%! zu~?&JtQ2|C6ydO0ykdIB3K~XzV}~Nt_K`iC*eE{x?6rOvv6>Z$wX$7^-By%-R{0+I z)6$>@ftHQ@8ijR>m+Ws%w0^1~hDZqNg;f-ojP!V3R~18H#|?pYA*@WL7fHADpPt$P z(X>`1B%=V&p21C?IF#zO`n6j-ydj=AWz?Q}C4Nv{oEy@$kjFb8Qd0+qRv8}{stckd=&d8bmsee8lKv_XUzDCvp F@qbceR^b2u diff --git a/csharp/hashtopolis/taskClass.cs b/csharp/hashtopolis/taskClass.cs deleted file mode 100644 index a5fa585..0000000 --- a/csharp/hashtopolis/taskClass.cs +++ /dev/null @@ -1,854 +0,0 @@ -using System; -using System.Collections; -using System.IO; -using System.Collections.Generic; -using System.Threading; - -namespace hashtopolis -{ - class taskClass - { - - hashcatClass hcClass = new hashcatClass(); - - private string attackcmd; - private string cmdpars; - private Boolean stipPath; - private string actualHLpath; - private int benchTime, hashlistID, taskID, statusTimer, benchMethod, crackerId; - private ArrayList files; - private string hashlistAlias = "#HL#"; - - private string prefixServerdl = ""; - - private long chunkNo, skip, length; - private string filepath, hashpath, appPath, zapPath, tasksPath; - - public Boolean debugFlag { get; set; } - public _7zClass sevenZip { get; set; } - public registerClass client { get; set; } - public Boolean legacy { get; set; } - private int offset = 0; - - public void setOffset() - { - if (!legacy) - { - offset = 1; - Console.WriteLine("Using new STATUS codes"); - } - else - { - Console.WriteLine("Using legacy STATUS codes"); - } - } - - - private List primaryCracked; //Stores the cracked hashes as they come - private object packetLock = new object(); //Lock to prevent the packetList from being edited as it's passed between the periodicUpload thread and the stdOut reader in hashcatClass - - public void setDirs(string fpath) - { - appPath = fpath; - filepath = Path.Combine(fpath, "files"); - hashpath = Path.Combine(fpath, "hashlists"); - zapPath = Path.Combine(fpath, "hashlists", "zaps"); - tasksPath = Path.Combine(fpath, "tasks"); - prefixServerdl = client.connectURL.Substring(0, client.connectURL.IndexOf("/api/")) + "/"; - - } - - private class Task - { - public string action { get; set; } - public string token { get; set; } - } - - private class FileProps - { - public string action { get; set; } - public string token { get; set; } - public int taskId { get; set; } - public string file { get; set; } - } - - - private class chunkProps - { - public string action = "getChunk"; - public string token { get; set; } - public int taskId { get; set; } - } - - private class hashlistProps - { - public string action = "getHashlist"; - public string token { get; set; } - public int hashlistId { get; set; } - } - - private class keyspaceProps - { - public string action = "sendKeyspace"; - public string token { get; set; } - public int taskId { get; set; } - public long keyspace { get; set; } - } - - private class benchProps - { - public string action = "sendBenchmark"; - public string token { get; set; } - public int taskId { get; set; } - public string type { get; set; } - public string result { get; set; } - } - - private class errorProps - { - public string action = "clientError"; - public string token { get; set; } - public int taskId { get; set; } - public string message { get; set; } - } - - private class solveProps - { - public string action = "sendProgress"; - public string token { get; set; } - public long chunkId { get; set; } - public double keyspaceProgress { get; set; } - public double relativeProgress { get; set; } - //public double total { get; set; } - public double speed { get; set; } - public double state { get; set; } - public List cracks { get; set; } - } - - public Boolean getHashes(int inTask) - { - - actualHLpath = Path.Combine(hashpath, Path.GetFileName(inTask.ToString())); - - Console.WriteLine("Downloading hashlist for this task, please wait..."); - - hashlistProps hProps = new hashlistProps - { - token = client.tokenID, - hashlistId = inTask - }; - jsonClass jsC = new jsonClass { debugFlag = debugFlag, connectURL = client.connectURL }; - string jsonString = jsC.toJson(hProps); - string ret = jsC.jsonSend(jsonString,300); //300 second timeout - - if (jsC.isJsonSuccess(ret)) - { - - getURLtoFile(jsC.getRetVar(ret, "url"), actualHLpath); - } - - - /* - //Check if is json string, a nasty workaround copies from the javaclient to detect whether the return string is json vs hl. Should probably use a proper detector - if (ret[0] != '{' && ret[ret.Length - 1] != '}') - { - File.WriteAllText(actualHLpath, ret); - Directory.CreateDirectory(Path.Combine(hashpath, "zaps" + inTask.ToString())); - } - else - { - if (jsC.isJsonSuccess(ret)) - { - string b64data = jsC.getRetVar(ret,"data"); - byte[] binArray = System.Convert.FromBase64String(b64data); - File.WriteAllBytes(actualHLpath, binArray); - stipPath = true; //Strip path for all HL recieved binary hashlsits - - } - else - { - return false; - } - - } - */ - - return true; - } - - public string speedCalc(double speed) - { - int count = 0; - while (speed > 1000) - { - speed = speed / 1000; - count++; - } - - speed = Math.Round(speed, 2); - - if (count == 0) - { - return speed.ToString("F") + "H/s"; - } - else if (count == 1) - { - return speed.ToString("F") + "KH/s"; - } - else if (count == 2) - { - return speed.ToString("F") + "MH/s"; - } - else if (count == 3) - { - return speed.ToString("F") + "GH/s"; - } - else if (count == 4) - { - return speed.ToString("F") + "TH/s"; - } - return speed.ToString("F"); - } - - - //This runs as an independant thread and uploads the STATUS generated from the hcAttack - //This thread is run on a dynamic timer based on the size of the queue and will range from a base 2500ms down to 200ms - //There is very little discruption to the attack as a very quick lock/unlock is performed on the packet list to pop the job off the queue - public void threadPeriodicUpdate(ref List uploadPackets, ref object objPacketlock) - { - System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone(); - customCulture.NumberFormat.NumberDecimalSeparator = "."; - System.Threading.Thread.CurrentThread.CurrentCulture = customCulture; - - jsonClass jsC = new jsonClass {debugFlag = debugFlag, connectURL = client.connectURL };//Initis the json class - solveProps sProps = new solveProps(); //Init the properties to build our json string - List receivedZaps = new List { }; //List to store incoming zaps for writing - string ret =""; //Return string from json post - string jsonString =""; - string zapfilePath = zapPath + hashlistID.ToString(); - long zapCount = 0; - List batchList = new List { }; - double chunkPercent = 0; - double chunkStart = 0; - Boolean run = true; - List singlePacket = new List { }; - int sleepTime = 2500; - long ulQueue = 0; - hcClass.debugFlag = debugFlag; - Boolean firstRun = true; - - - - string oPath = Path.Combine(tasksPath, taskID + "_" + chunkNo + ".txt"); // Path to write th -o file - - while (run) - { - Thread.Sleep(sleepTime); //Delay this thread for 2.5 seconds, if this falls behind it will batch the jobs - lock (objPacketlock) - { - if (uploadPackets.Count > 0) - { - - singlePacket.Add(uploadPackets[0]); - ulQueue = uploadPackets.Count; - uploadPackets.RemoveAt(0); - if (uploadPackets.Count > 3) - - sleepTime = 200; //Decrese the time we process the queue - } - else - { - sleepTime = 2500; //Decrese the time we process the queue - } - } - - if (firstRun == true) //This is a work around to send a server a dummy stat to prevent timeouts on the initial start - { - sProps.token = client.tokenID; - sProps.chunkId = chunkNo; - sProps.keyspaceProgress = skip; - - sProps.relativeProgress = 0; - - sProps.speed = 0; - sProps.state = 3; //Can't find the status code list lets try 3 - - sProps.cracks = new List(); - - jsonString = jsC.toJson(sProps); - ret = jsC.jsonSend(jsonString); - - if (!jsC.isJsonSuccess(ret)) //If we received error, eg task was removed just break - { - break; - } - firstRun = false; - } - - if (singlePacket.Count == 0) - { - continue; - } - - try - { - { - //Special override as there is a possible race condition in HC, where STATUS4 doesn't give 100% - if (singlePacket[0].statusPackets["STATUS"] == 4 + offset) - { - singlePacket[0].statusPackets["PROGRESS1"] = singlePacket[0].statusPackets["PROGRESS2"]; - } - - sProps.token = client.tokenID; - sProps.chunkId = chunkNo; - sProps.keyspaceProgress = singlePacket[0].statusPackets["CURKU"]; - - - chunkStart = Math.Floor(singlePacket[0].statusPackets["PROGRESS2"]) / (skip + length) * skip; - chunkPercent = Math.Round((Convert.ToDouble(singlePacket[0].statusPackets["PROGRESS1"]) - chunkStart) / Convert.ToDouble(singlePacket[0].statusPackets["PROGRESS2"] - chunkStart), 4) * 10000; - - sProps.relativeProgress = chunkPercent; - - //sProps.total = singlePacket[0].statusPackets["PROGRESS2"]; - sProps.speed = singlePacket[0].statusPackets["SPEED_TOTAL"]; - sProps.state = singlePacket[0].statusPackets["STATUS"] - offset; //Client-side workaround for old STATUS on server - - if (singlePacket[0].crackedPackets.Count > 200) - { - int max = 200; - - //Process the requests in batches of 1000 - while (singlePacket[0].crackedPackets.Count != 0) - { - List subChunk = new List(singlePacket[0].crackedPackets.GetRange(0, max)); - singlePacket[0].crackedPackets.RemoveRange(0, max); - if (singlePacket[0].crackedPackets.Count < max) - { - max = singlePacket[0].crackedPackets.Count; - } - - if (stipPath == true) - { - for (int i = 0; i <= subChunk.Count-1; i++) - { - subChunk[i] = subChunk[i].Replace(actualHLpath + ":", ""); - } - } - - sProps.cracks = subChunk; - jsonString = jsC.toJson(sProps); - ret = jsC.jsonSend(jsonString); - - if (!jsC.isJsonSuccess(ret)) //If we received error, eg task was removed just break - { - break; - } - } - - } - else - { - if (stipPath == true) - { - for (int i =0; i<= singlePacket[0].crackedPackets.Count-1; i++) - { - singlePacket[0].crackedPackets[i] = singlePacket[0].crackedPackets[i].Replace(actualHLpath + ":", ""); - } - } - sProps.cracks = singlePacket[0].crackedPackets; - - jsonString = jsC.toJson(sProps); - ret = jsC.jsonSend(jsonString); - } - } - - - if (jsC.isJsonSuccess(ret)) - { - - if (jsC.getRetVar(ret, "agent") == "stop") //Special command sent by server, possibly undocumented - { - hcClass.hcProc.CancelOutputRead(); - hcClass.hcProc.CancelErrorRead(); - hcClass.hcProc.Kill(); - run = false; - Console.WriteLine("Server has instructed the client terminate the task via stop"); - } - - - chunkPercent = chunkPercent / 100; //We already calculated with * 10000 earlier - - receivedZaps = jsC.getRetList(ret, "zaps"); //Check whether the server sent out hashes to zap - if (receivedZaps.Count > 0) - { - zapCount++; - File.WriteAllLines(Path.Combine(zapfilePath,zapCount.ToString()), receivedZaps); //Write hashes for zapping - - } - Console.WriteLine("Progress:{0,7} | Speed:{1,-4} | Cracks:{2,-4} | Accepted:{3,-4} | Zapped:{4,-4} | Queue:{5,-2}", chunkPercent.ToString("F") + "%", speedCalc(singlePacket[0].statusPackets["SPEED_TOTAL"]), singlePacket[0].crackedPackets.Count, jsC.getRetVar(ret, "cracked"), receivedZaps.Count,ulQueue); - receivedZaps.Clear(); - - - } - - - else //We received an error from the server, terminate the run - { - - string writeCracked = Path.Combine(hashpath, Path.GetFileName(hashlistID.ToString())) + ".cracked"; - Console.WriteLine("Writing any cracks in queue to file " + writeCracked); - File.AppendAllLines(writeCracked, singlePacket[0].crackedPackets); - lock (objPacketlock) - { - if (uploadPackets.Count > 0) - { - for (int i = 0; i < uploadPackets.Count; i++) - { - if (uploadPackets[i].crackedPackets.Count > 0) - { - File.AppendAllLines(writeCracked, uploadPackets[i].crackedPackets); - } - } - } - } - - run = false; //Potentially we can change this so keep submitting the rest of the cracked queue instead of terminating - - if (!hcClass.hcProc.HasExited) - { - hcClass.hcProc.CancelOutputRead(); - hcClass.hcProc.CancelErrorRead(); - hcClass.hcProc.Kill(); - //The server would need to accept the chunk but return an error - } - break; - } - - - { - if (singlePacket[0].statusPackets["STATUS"] >= 4 + offset) //We are the last upload task - //if (singlePacket[0].statusPackets["STATUS"] >= 5) //Uncomment this line, and comment above line for upcoming HC > 3.6 - { - Console.WriteLine("Finished processing chunk"); - singlePacket.Clear(); - run = false; - } - else - { - singlePacket.RemoveAt(0); - } - - } - - } - - - catch (Exception e) - { - Console.WriteLine(e.Message); - Console.WriteLine("Error processing packet for upload"); - } - - - } - - } - - private jsonClass jsC = new jsonClass { }; - - public int getChunk(int inTask) - { - Console.WriteLine("Getting chunk..."); - chunkProps cProps = new chunkProps - { - action = "getChunk", - token = client.tokenID, - taskId = inTask - }; - - jsC.debugFlag = debugFlag; - jsC.connectURL = client.connectURL; - primaryCracked = new List { }; - hcClass.debugFlag = debugFlag; - - string jsonString = jsC.toJson(cProps); - string ret = jsC.jsonSend(jsonString); - - - if (jsC.isJsonSuccess(ret)) - { - string status = jsC.getRetVar(ret, "status"); - - - string argBuilder = attackcmd; - string attackcmdMod = " " + cmdpars + " "; - string actualHLpath = Path.Combine(hashpath, hashlistID.ToString()); - switch (status) - { - case "OK": - attackcmdMod = " " + cmdpars + " "; //Reset the argument string - attackcmdMod += attackcmd.Replace(hashlistAlias, "\"" + actualHLpath + "\" "); //Add the path to Hashlist - - attackcmdMod = convertToRelative(attackcmdMod); - - attackcmdMod += " --outfile-check-dir=\"" + zapPath + hashlistID.ToString() + "\" "; //Add the zap path to the commands - - hcClass.setArgs(attackcmdMod); - - chunkNo = Convert.ToInt64(jsC.getRetVar(ret, "chunkId")); - skip = Convert.ToInt64(jsC.getRetVar(ret, "skip")); - length = Convert.ToInt64(jsC.getRetVar(ret, "length")); - - List uploadPackets = new List(); - - hcClass.setDirs(appPath); - hcClass.setPassthrough(ref uploadPackets, ref packetLock, debugFlag); - - Thread thread = new Thread(() => threadPeriodicUpdate(ref uploadPackets, ref packetLock)); - thread.Start(); //Start our thread to monitor the upload queue - - hcClass.startAttack(chunkNo, taskID, skip, length, statusTimer, tasksPath); //Start the hashcat binary - thread.Join(); - - return 1; - - case "keyspace_required": - hcClass.setDirs(appPath); - attackcmdMod = " " + cmdpars + " "; //Reset the argument string - attackcmdMod += attackcmd.Replace(hashlistAlias, ""); //Remove out the #HL# - - attackcmdMod = convertToRelative(attackcmdMod); - - hcClass.setArgs(attackcmdMod); - long calcKeyspace = 0; - - if (!hcClass.runKeyspace(ref calcKeyspace)) - { - Console.WriteLine("Keyspace measuring was unsuccessful, check all files are present"); - return 0; - } - - - if (calcKeyspace == 0) - { - errorProps eProps = new errorProps - { - token = client.tokenID, - taskId = taskID, - message = "Invalid keyspace, keyspace probably too small for this hashtype" - }; - jsonString = jsC.toJson(eProps); - ret = jsC.jsonSend(jsonString); - return 0; - } - else - { - keyspaceProps kProps = new keyspaceProps - { - token = client.tokenID, - taskId = taskID, - keyspace = calcKeyspace - }; - jsonString = jsC.toJson(kProps); - ret = jsC.jsonSend(jsonString); - - } - - return 2; - - case "fully_dispatched": - return 0; - - case "benchmark": - hcClass.setDirs(appPath); - attackcmdMod = " " + cmdpars + " "; //Reset the argument string - attackcmdMod += attackcmd.Replace(hashlistAlias, "\"" + actualHLpath + "\""); //Add the path to Hashlist - - attackcmdMod = convertToRelative(attackcmdMod); - - hcClass.setArgs(attackcmdMod); - - Dictionary collection = new Dictionary(); //Holds all the returned benchmark values1 - - if(!hcClass.runBenchmark(benchMethod, benchTime, ref collection, legacy)) - { - Console.WriteLine("Benchmark error, perhaps hashlist is empty"); - errorProps eProps = new errorProps - { - token = client.tokenID, - taskId = taskID, - message = "Client received an invalid hashlist for benchmark" - }; - jsonString = jsC.toJson(eProps); - ret = jsC.jsonSend(jsonString); - - return 0; - - } - - benchProps bProps = new benchProps - { - token = client.tokenID, - taskId = taskID, - }; - - try - { - if (benchMethod == 1) //Old benchmark method using actual run - { - bProps.type = "run"; - bProps.result = collection["PROGRESS_REJ"].ToString("0." + new string('#', 100)); - - } - else //New benchmark method using --speed param - { - bProps.type = "speed"; - bProps.result = collection["LEFT_TOTAL"].ToString() + ":" + collection["RIGHT_TOTAL"].ToString(); - } - } - catch - { - Console.WriteLine("Benchmark was unsuccessful, check all files are present"); - return 0; - } - - - - jsonString = jsC.toJson(bProps); - ret = jsC.jsonSend(jsonString); - if (!jsC.isJsonSuccess(ret)) - { - Console.WriteLine("Server rejected benchmark"); - Console.WriteLine("Check the hashlist was downloaded correctly"); - return 0; - } - return 3; - - } - - } - return 0; - } - - private string convertToRelative(string input) - { - string[] filename = input.Split(' '); //Split by spaces - string final = ""; - - - foreach (var file in filename) - { - if (File.Exists("files\\" + file)) - { - final += "..\\..\\files\\" + file + " "; - } - else - { - final += file + " "; - } - } - - if (client.osID != 1) - { - final = final.Replace("\\", "/"); - } - - return final; - - } - private Boolean getFile(string fileName) - { - FileProps get = new FileProps - { - action = "getFile", - token = client.tokenID, - taskId = taskID, - file = fileName - }; - - jsonClass jsC = new jsonClass { debugFlag = debugFlag, connectURL = client.connectURL }; - string jsonString = jsC.toJson(get); - string ret = jsC.jsonSend(jsonString); - - if (jsC.isJsonSuccess(ret)) - { - string fileDl = jsC.getRetVar(ret, "url"); - { - downloadClass dlHdl = new downloadClass(); - string dlFrom = Path.Combine(prefixServerdl, jsC.getRetVar(ret, "url")); - string dlTo = Path.Combine(filepath,fileName); - dlHdl.DownloadFile(dlFrom, dlTo); - Console.WriteLine("Finished downloading file"); - //Check if file exists. check if return success - return true; - } - - } - return false; - } - - private Boolean getURLtoFile(string url, string dst) - { - { - downloadClass dlHdl = new downloadClass(); - string dlFrom = Path.Combine(prefixServerdl, url); - string dlTo = Path.Combine(filepath, dst); - dlHdl.DownloadFile(dlFrom, dlTo); - Console.WriteLine("Finished downloading file"); - //Check if file exists. check if return success - if (File.Exists(dlTo)) - { - return true; - } - } - - return false; - } - - - private Int64 fileSize(string filePath) - { - Int64 fSize = new FileInfo(Path.Combine(hashpath , Path.GetFileName(hashlistID.ToString()))).Length; - return fSize; - } - - - public Boolean getTask() - { - - Console.WriteLine("Getting task"); - Task get = new Task - { - action = "getTask", - token = client.tokenID - }; - - jsonClass jsC = new jsonClass { debugFlag = debugFlag, connectURL = client.connectURL }; - string jsonString = jsC.toJson(get); - string ret = jsC.jsonSend(jsonString); - - if (jsC.isJsonSuccess(ret)) - { - if (jsC.getRetVar(ret, "taskId") != null) - { - taskID = Int32.Parse(jsC.getRetVar(ret, "taskId")); - attackcmd = (jsC.getRetVar(ret, "attackcmd")); - cmdpars = (jsC.getRetVar(ret, "cmdpars")); - hashlistID = Int32.Parse(jsC.getRetVar(ret, "hashlistId")); - benchTime = Int32.Parse(jsC.getRetVar(ret, "bench")); - crackerId = Int32.Parse(jsC.getRetVar(ret, "crackerId")); - - Console.WriteLine("Server has assigned client with Task:{0}, Cracker:{2} and Hashlist:{1}",taskID,hashlistID,crackerId); - if (jsC.getRetVar(ret, "benchType") == "run") - { - benchMethod = 1; - } - else - { - benchMethod = 2; - } - statusTimer = Int32.Parse(jsC.getRetVar(ret, "statustimer")); - hashlistAlias = jsC.getRetVar(ret, "hashlistAlias"); - files = jsC.getRetArray(ret, "files"); - int gotChunk = 1; - - foreach (string fileItem in files) - { - string actualFile = Path.Combine(filepath, fileItem); - if (!File.Exists(actualFile)) - { - getFile(fileItem); - - if (fileItem.ToLower().EndsWith(".7z")) - { - if (sevenZip.xtract(actualFile, filepath)) - { - File.WriteAllText(actualFile, "UNPACKED"); - } - else - { - return false; - } - } - } - } - - //Convert implied relative paths to absolute paths only applies to Mac OSX / Linux - //We, break up the attack command by space and check whether the file for the full path exists, we it does we replace - //Could potentially cause issues if the file names are attack numbers eg 1 2 3 4 5 6 7 - //File names cannot contain spaces - //Altnerative method is to perform find replace on the attackcmd based on the files array - if (client.osID != 1) - { - string[] explode = new string[] { }; - explode = attackcmd.Split(' '); - - for (int i = 0; i Date: Mon, 29 Oct 2018 16:42:25 +0100 Subject: [PATCH 29/33] updated compatibility list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d162bf9..9b44a4e 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ In order to use the multicast distribution for files, please make sure that the The list contains all Hashcat versions with which the client was tested and is able to work with (other versions might work): +* 5.0.0 * 4.2.1 * 4.2.0 * 4.1.0 From fbaf07fd3903d7e9c2228e4d8bb258b2f75c96ea Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 16:49:18 +0100 Subject: [PATCH 30/33] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9b44a4e..2e8353a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Hashtopolis Python Agent -[![CodeFactor](https://www.codefactor.io/repository/github/s3inlc/hashtopolis-agent/badge)](https://www.codefactor.io/repository/github/s3inlc/hashtopolis-agent) -[![LoC](https://tokei.rs/b1/github/s3inlc/Hashtopolis-Agent?category=code)](https://github.com/s3inlc/Hashtopolis-Agent) +[![CodeFactor](https://www.codefactor.io/repository/github/s3inlc/hashtopolis-agent-python/badge)](https://www.codefactor.io/repository/github/s3inlc/hashtopolis-agent-python) +[![LoC](https://tokei.rs/b1/github/s3inlc/Hashtopolis-Agent-Python?category=code)](https://github.com/s3inlc/Hashtopolis-Agent-Python) +[![Build Status](https://travis-ci.org/s3inlc/hashtopolis-agent-python.svg?branch=master)](https://travis-ci.org/s3inlc/hashtopolis-agent-python) This Hashtopolis agent is only compatible with Hashtopolis versions 0.5.0 and higher. From 62e5042f3ce4669ef4df1fda7c5e3f1918df092b Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 16:54:04 +0100 Subject: [PATCH 31/33] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e8353a..805b10d 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ When you run the client for the first time it will ask automatically for all the ``` { - "url": "https://coray.org/htp-test/src/api/server.php", - "token": "7RNDqtnPxm", + "url": "https://example.org/hashtopolis/api/server.php", + "token": "ABCDEFGHIJ", "uuid": "49dcd31c-3637-4f2a-8df1-b545202df5b3" } ``` From 1e127a13ec2e9e072a0dab85f48e4db352f37269 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 16:59:08 +0100 Subject: [PATCH 32/33] adjusted travis to moved repository and changed structure --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51edec5..ce013be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,7 @@ python: - "3.5" - "3.6" install: - - pip install -r python/requirements.txt + - pip install -r requirements.txt script: - - cd python - ./build.sh - python hashtopolis.zip --version From 5562f64b5f6751ae2103595590fdbf01c0c8e566 Mon Sep 17 00:00:00 2001 From: Sein Coray Date: Mon, 29 Oct 2018 17:04:31 +0100 Subject: [PATCH 33/33] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 805b10d..3795c91 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![LoC](https://tokei.rs/b1/github/s3inlc/Hashtopolis-Agent-Python?category=code)](https://github.com/s3inlc/Hashtopolis-Agent-Python) [![Build Status](https://travis-ci.org/s3inlc/hashtopolis-agent-python.svg?branch=master)](https://travis-ci.org/s3inlc/hashtopolis-agent-python) +This agent is used with [Hashtopolis](https://github.com/s3inlc/hashtopolis), read the wiki or create issues there, visit the [Forum](https://hashtopolis.org). This Hashtopolis agent is only compatible with Hashtopolis versions 0.5.0 and higher. ## Prerequisites