From c32a35bca023a0de4e42b0e49ab3011eba407055 Mon Sep 17 00:00:00 2001 From: Justin Bollinger Date: Wed, 21 Jan 2026 13:25:45 -0500 Subject: [PATCH] updated hashview pytest runners and updated config example --- config.json.example | 4 +- hashcat-utils/bin/combinator.arm.bin | Bin 0 -> 34416 bytes hashcat-utils/bin/expander.arm.bin | Bin 0 -> 34272 bytes hate_crack.py | 718 +++++++++++++++++++++++++-- princeprocessor/pp64.arm.bin | Bin 0 -> 35072 bytes test_hashview.py | 110 ++++ 6 files changed, 789 insertions(+), 43 deletions(-) create mode 100755 hashcat-utils/bin/combinator.arm.bin create mode 100755 hashcat-utils/bin/expander.arm.bin create mode 100755 princeprocessor/pp64.arm.bin create mode 100644 test_hashview.py diff --git a/config.json.example b/config.json.example index 43770ef..7b9bffc 100644 --- a/config.json.example +++ b/config.json.example @@ -16,5 +16,7 @@ "pipalPath": "/path/to/pipal", "pipal_count" : 10, "bandrelmaxruntime": 300, - "bandrel_common_basedwords": "welcome,password,p@ssword,p@$$word,changeme,letmein,summer,winter,spring,springtime,fall,autumn,monday,tuesday,wednesday,thursday,friday,saturday,sunday,january,february,march,april,may,june,july,august,september,october,november,december,christmas,easter,covid19" + "bandrel_common_basedwords": "welcome,password,p@ssword,p@$$word,changeme,letmein,summer,winter,spring,springtime,fall,autumn,monday,tuesday,wednesday,thursday,friday,saturday,sunday,january,february,march,april,may,june,july,august,september,october,november,december,christmas,easter,covid19", + "hashview_url": "http://localhost:8443", + "hashview_api_key": "" } \ No newline at end of file diff --git a/hashcat-utils/bin/combinator.arm.bin b/hashcat-utils/bin/combinator.arm.bin new file mode 100755 index 0000000000000000000000000000000000000000..e0bfe365851a8110d59f4082e72ef357ba533f1f GIT binary patch literal 34416 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 W`t(_2JHE5%+xsW-D~dVFiT(uvZNMx5 literal 0 HcmV?d00001 diff --git a/hashcat-utils/bin/expander.arm.bin b/hashcat-utils/bin/expander.arm.bin new file mode 100755 index 0000000000000000000000000000000000000000..ffb55c8c2be0ba01c9db0fd613f6aa72dfb9812b GIT binary patch literal 34272 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 QYf0Zt8~LDGdE0>YPbAXh3jhEB literal 0 HcmV?d00001 diff --git a/hate_crack.py b/hate_crack.py index 2301229..7b247a6 100755 --- a/hate_crack.py +++ b/hate_crack.py @@ -1,8 +1,10 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Methodology provided by Martin Bos (pure_hate) - https://www.trustedsec.com/team/martin-bos/ # Original script created by Larry Spohn (spoonman) - https://www.trustedsec.com/team/larry-spohn/ # Python refactoring and general fixing, Justin Bollinger (bandrel) - https://www.trustedsec.com/team/justin-bollinger/ +# Hashview integration by Justin Bollinger (bandrel) and Claude Sonnet 4.5 +# special thanks to hans for all his hard work on hashview and creating APIs for us to use import subprocess import sys @@ -13,10 +15,17 @@ import json import binascii import shutil +try: + import requests + REQUESTS_AVAILABLE = True +except ImportError: + REQUESTS_AVAILABLE = False + # python2/3 compatability try: input = raw_input except NameError: + pass hate_path = os.path.dirname(os.path.realpath(__file__)) @@ -108,6 +117,18 @@ except KeyError as e: print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) hcatGoodMeasureBaseList = default_config[e.args[0]] +try: + hashview_url = config_parser['hashview_url'] +except KeyError as e: + print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) + hashview_url = default_config.get('hashview_url', 'https://localhost:8443') + +try: + hashview_api_key = config_parser['hashview_api_key'] +except KeyError as e: + print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) + hashview_api_key = default_config.get('hashview_api_key', '') + hcatExpanderBin = "expander.bin" hcatCombinatorBin = "combinator.bin" @@ -299,7 +320,7 @@ def hcatQuickDictionary(hcatHashType, hcatHashFile, hcatChains, wordlists): def hcatTopMask(hcatHashType, hcatHashFile, hcatTargetTime): global hcatMaskCount global hcatProcess - hcatProcess = subprocess.Popen( + subprocess.Popen( "cat {hash_file}.out | cut -d : -f 2 > {hash_file}.working".format( hash_file=hcatHashFile), shell=True).wait() hcatProcess = subprocess.Popen( @@ -350,7 +371,7 @@ def hcatFingerprint(hcatHashType, hcatHashFile): crackedAfter = 0 while crackedBefore != crackedAfter: crackedBefore = lineCount(hcatHashFile + ".out") - hcatProcess = subprocess.Popen("cat {hash_file}.out | cut -d : -f 2 > {hash_file}.working".format( + subprocess.Popen("cat {hash_file}.out | cut -d : -f 2 > {hash_file}.working".format( hash_file=hcatHashFile), shell=True).wait() hcatProcess = subprocess.Popen( "{hate_path}/hashcat-utils/bin/{expander_bin} < {hash_file}.working | sort -u > {hash_file}.expanded".format( @@ -428,7 +449,7 @@ def hcatHybrid(hcatHashType, hcatHashFile): hcatProcess.kill() hcatProcess = subprocess.Popen( - "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} ?1?1?1 " + "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} ?1?1?1 " "{tuning} --potfile-path={hate_path}/hashcat.pot".format( hcatBin=hcatBin, hash_type=hcatHashType, @@ -444,7 +465,7 @@ def hcatHybrid(hcatHashType, hcatHashFile): hcatProcess.kill() hcatProcess = subprocess.Popen( - "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} " + "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} " "?1?1?1?1 {tuning} --potfile-path={hate_path}/hashcat.pot".format( hcatBin=hcatBin, hash_type=hcatHashType, @@ -460,7 +481,7 @@ def hcatHybrid(hcatHashType, hcatHashFile): hcatProcess.kill() hcatProcess = subprocess.Popen( - "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 7 -1 ?s?d ?1?1 {wordlist} " + "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 7 -1 ?s?d ?1?1 {wordlist} " "{tuning} --potfile-path={hate_path}/hashcat.pot".format( hcatBin=hcatBin, hash_type=hcatHashType, @@ -476,7 +497,7 @@ def hcatHybrid(hcatHashType, hcatHashFile): hcatProcess.kill() hcatProcess = subprocess.Popen( - "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1 {wordlist} " + "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1 {wordlist} " "{tuning} --potfile-path={hate_path}/hashcat.pot".format( hcatBin=hcatBin, hash_type=hcatHashType, @@ -492,7 +513,7 @@ def hcatHybrid(hcatHashType, hcatHashFile): hcatProcess.kill() hcatProcess = subprocess.Popen( - "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1?1 {wordlist} " + "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1?1 {wordlist} " "{tuning} --potfile-path={hate_path}/hashcat.pot".format( hcatBin=hcatBin, hash_type=hcatHashType, @@ -530,10 +551,14 @@ def hcatYoloCombination(hcatHashType, hcatHashFile): left=hcatLeft, right=hcatRight, hate_path=hate_path), shell=True) - hcatProcess.wait() + try: + hcatProcess.wait() + except KeyboardInterrupt: + print('Killing PID {0}...'.format(str(hcatProcess.pid))) + hcatProcess.kill() + raise except KeyboardInterrupt: - print('Killing PID {0}...'.format(str(hcatProcess.pid))) - hcatProcess.kill() + pass # Bandrel methodlogy def hcatBandrel(hcatHashType, hcatHashFile): @@ -625,10 +650,14 @@ def hcatMiddleCombinator(hcatHashType, hcatHashFile): middle_mask=masks[x], hate_path=hate_path), shell=True) - hcatProcess.wait() + try: + hcatProcess.wait() + except KeyboardInterrupt: + print('Killing PID {0}...'.format(str(hcatProcess.pid))) + hcatProcess.kill() + raise except KeyboardInterrupt: - print('Killing PID {0}...'.format(str(hcatProcess.pid))) - hcatProcess.kill() + pass # Middle thorough Combinator Attack def hcatThoroughCombinator(hcatHashType, hcatHashFile): @@ -646,20 +675,20 @@ def hcatThoroughCombinator(hcatHashType, hcatHashFile): new_masks.append('$'+mask) masks = new_masks + hcatProcess = subprocess.Popen( + "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {left} " + "{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format( + hcatBin=hcatBin, + hash_type=hcatHashType, + hash_file=hcatHashFile, + session_name=os.path.basename(hcatHashFile), + left=hcatThoroughBaseList, + right=hcatThoroughBaseList, + word_lists=hcatWordlists, + tuning=hcatTuning, + hate_path=hate_path), + shell=True) try: - hcatProcess = subprocess.Popen( - "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {left} " - "{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format( - hcatBin=hcatBin, - hash_type=hcatHashType, - hash_file=hcatHashFile, - session_name=os.path.basename(hcatHashFile), - left=hcatThoroughBaseList, - right=hcatThoroughBaseList, - word_lists=hcatWordlists, - tuning=hcatTuning, - hate_path=hate_path), - shell=True) hcatProcess.wait() except KeyboardInterrupt: print('Killing PID {0}...'.format(str(hcatProcess.pid))) @@ -681,10 +710,14 @@ def hcatThoroughCombinator(hcatHashType, hcatHashFile): middle_mask=masks[x], hate_path=hate_path), shell=True) - hcatProcess.wait() + try: + hcatProcess.wait() + except KeyboardInterrupt: + print('Killing PID {0}...'.format(str(hcatProcess.pid))) + hcatProcess.kill() + raise except KeyboardInterrupt: - print('Killing PID {0}...'.format(str(hcatProcess.pid))) - hcatProcess.kill() + pass try: for x in range(len(masks)): hcatProcess = subprocess.Popen( @@ -701,10 +734,14 @@ def hcatThoroughCombinator(hcatHashType, hcatHashFile): end_mask=masks[x], hate_path=hate_path), shell=True) - hcatProcess.wait() + try: + hcatProcess.wait() + except KeyboardInterrupt: + print('Killing PID {0}...'.format(str(hcatProcess.pid))) + hcatProcess.kill() + raise except KeyboardInterrupt: - print('Killing PID {0}...'.format(str(hcatProcess.pid))) - hcatProcess.kill() + pass try: for x in range(len(masks)): hcatProcess = subprocess.Popen( @@ -821,7 +858,7 @@ def hcatLMtoNT(): except KeyboardInterrupt: hcatProcess.kill() - hcatProcess = subprocess.Popen("cat {hash_file}.lm.cracked | cut -d : -f 2 > {hash_file}.working".format( + subprocess.Popen("cat {hash_file}.lm.cracked | cut -d : -f 2 > {hash_file}.working".format( hash_file=hcatHashFile), shell=True).wait() converted = convert_hex("{hash_file}.working".format(hash_file=hcatHashFile)) with open("{hash_file}.working".format(hash_file=hcatHashFile),mode='w') as working: @@ -917,7 +954,6 @@ def check_potfile(): else: print("No hashes found in POT file.") - # creating the combined output for pwdformat + cleartext def combine_ntlm_output(): hashes = {} @@ -963,6 +999,514 @@ def cleanup(): #incase someone mashes the Control+C it will still cleanup cleanup() +# Hashview Integration +class HashviewAPI: + """Upload files to Hashview API""" + + FILE_FORMATS = { + 'pwdump': 0, + 'netntlm': 1, + 'kerberos': 2, + 'shadow': 3, + 'user:hash': 4, + 'hash_only': 5, + } + + def __init__(self, base_url, api_key): + self.base_url = base_url.rstrip('/') + self.api_key = api_key + self.agent_uuid = None + self.session = requests.Session() + self.session.cookies.set('uuid', api_key) + # Disable SSL certificate verification for self-signed certificates + self.session.verify = False + # Suppress SSL warnings + import urllib3 + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + def use_agent_mode(self): + """Switch to using agent UUID for operations that require it""" + if not self.agent_uuid: + raise Exception("No agent registered. Call register_agent() first.") + + # Switch session to use agent UUID + self.session = self.agent_session + + def upload_wordlist(self, file_path, wordlist_name=None): + if wordlist_name is None: + wordlist_name = os.path.basename(file_path) + + with open(file_path, 'rb') as f: + file_content = f.read() + + url = f"{self.base_url}/v1/wordlists/add/{wordlist_name}" + headers = {'Content-Type': 'text/plain'} + + print(f"Uploading wordlist: {os.path.basename(file_path)} -> {wordlist_name}") + response = self.session.post(url, data=file_content, headers=headers) + response.raise_for_status() + return response.json() + + def upload_hashfile(self, file_path, customer_id, hash_type, file_format=5, hashfile_name=None): + if hashfile_name is None: + hashfile_name = os.path.basename(file_path) + + with open(file_path, 'rb') as f: + file_content = f.read() + + url = ( + f"{self.base_url}/v1/hashfiles/upload/" + f"{customer_id}/{file_format}/{hash_type}/{hashfile_name}" + ) + + headers = {'Content-Type': 'text/plain'} + + print(f"Uploading hashfile: {os.path.basename(file_path)} -> {hashfile_name}") + response = self.session.post(url, data=file_content, headers=headers) + response.raise_for_status() + return response.json() + + def upload_cracked_hashes(self, file_path, hash_type=1000): + # Read and convert file - API expects hex-encoded plaintext (uppercase) + print(f"Importing cracked hashes: {os.path.basename(file_path)}") + print(f" Converting plaintext to hex encoding...") + + converted_lines = [] + line_count = 0 + with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: + for line in f: + line = line.strip() + if not line or ':' not in line: + continue + + parts = line.split(':', 1) + if len(parts) != 2: + continue + + hash_value = parts[0].strip() + plaintext = parts[1].strip() + + # Convert plaintext to hex (uppercase as API expects) + plaintext_hex = plaintext.encode('utf-8').hex().upper() + converted_lines.append(f"{hash_value}:{plaintext_hex}") + line_count += 1 + + converted_content = '\n'.join(converted_lines) + + print(f" Processed {line_count} hash:plaintext pairs") + + # Use the actual endpoint from api_routes.py + url = f"{self.base_url}/v1/uploadCrackFile/{hash_type}" + + # API expects JSON with 'file' field + payload = { + "file": converted_content + } + headers = {'Content-Type': 'application/json'} + + print(f"\n === REQUEST DETAILS ===") + print(f" URL: {url}") + print(f" Method: POST") + print(f" Headers: {headers}") + print(f" Cookies: {dict(self.session.cookies)}") + print(f" Hash type: {hash_type}") + print(f" Payload preview (first 500 chars):") + print(converted_content[:500]) + print(f" Uploading...") + + response = self.session.post(url, json=payload, headers=headers) + + # Debug: print response details + print(f"\n === RESPONSE DETAILS ===") + print(f" Status code: {response.status_code}") + print(f" Response headers: {dict(response.headers)}") + print(f" Response content: {response.text[:500]}") + + response.raise_for_status() + + # Check if response is JSON error + try: + json_response = response.json() + if 'type' in json_response and json_response['type'] == 'Error': + raise Exception(f"Hashview API Error: {json_response.get('msg', 'Unknown error')}") + return json_response + except (json.JSONDecodeError, ValueError) as e: + # Not valid JSON + raise Exception(f"Invalid API response: {response.text[:200]}") + + def list_customers(self): + url = f"{self.base_url}/v1/customers" + + print("Fetching customer list...") + response = self.session.get(url) + response.raise_for_status() + data = response.json() + + # Parse the 'users' JSON string into a list + if 'users' in data: + customers = json.loads(data['users']) + return {'customers': customers} + + return data + + def create_customer(self, name, description=""): + url = f"{self.base_url}/v1/customers/add" + headers = {'Content-Type': 'application/json'} + data = {"name": name, "description": description} + + print(f"Creating customer: {name}") + response = self.session.post(url, json=data, headers=headers) + response.raise_for_status() + return response.json() + + def create_job(self, name, hashfile_id, customer_id, limit_recovered=False, notify_email=True): + url = f"{self.base_url}/v1/jobs/add" + headers = {'Content-Type': 'application/json'} + data = { + "name": name, + "hashfile_id": hashfile_id, + "customer_id": customer_id, + "limit_recovered": limit_recovered, + "notify_email": notify_email, + "notify_pushover": False + } + + print(f"Creating job: {name}") + response = self.session.post(url, json=data, headers=headers) + response.raise_for_status() + return response.json() + + def start_job(self, job_id): + url = f"{self.base_url}/v1/jobs/start/{job_id}" + + print(f"Starting job ID: {job_id}") + response = self.session.post(url) + response.raise_for_status() + return response.json() + + def list_jobs(self, customer_id=None): + # The API doesn't have a filter by customer endpoint, get all jobs + url = f"{self.base_url}/v1/jobs" + + if customer_id: + print(f"Fetching jobs for customer ID {customer_id}...") + else: + print("Fetching all jobs...") + + response = self.session.get(url) + response.raise_for_status() + data = response.json() + + # Parse the response - may return 'jobs' as JSON string + if 'jobs' in data and isinstance(data['jobs'], str): + jobs = json.loads(data['jobs']) + # Filter by customer_id if provided + if customer_id: + jobs = [job for job in jobs if job.get('customer_id') == customer_id] + return {'jobs': jobs} + + return data + + def download_left_hashes(self, customer_id, hashfile_id, output_file=None): + # Use the proper API v1 endpoint for downloading hashfiles (left only) + url = f"{self.base_url}/v1/hashfiles/{hashfile_id}" + + print(f"Downloading left hashes...") + print(f" Customer ID: {customer_id}") + print(f" Hashfile ID: {hashfile_id}") + + response = self.session.get(url) + + # Check if we got HTML (login page) instead of hash data + if response.content.startswith(b'tr=Tdc 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