mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-03-12 21:23:05 -07:00
added debug options
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
"hcatBin": "hashcat",
|
||||
"hcatTuning": "--force --remove",
|
||||
"hcatPotfilePath": "~/.hashcat/hashcat.potfile",
|
||||
"hcatDebugLogPath": "./hashcat_debug",
|
||||
"hcatWordlists": "/Passwords/wordlists",
|
||||
"hcatOptimizedWordlists": "/Passwords/optimized_wordlists",
|
||||
"rules_directory": "/path/to/hashcat/rules",
|
||||
|
||||
@@ -962,14 +962,16 @@ class HashviewAPI:
|
||||
"combined_file": combined_file,
|
||||
}
|
||||
|
||||
def download_found_hashes(self, customer_id, hashfile_id, output_file=None):
|
||||
def download_found_hashes(self, customer_id, hashfile_id, output_file=None, hash_type=None):
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
url = f"{self.base_url}/v1/hashfiles/{hashfile_id}/found"
|
||||
resp = self.session.get(url, headers=self._auth_headers(), stream=True)
|
||||
resp.raise_for_status()
|
||||
if output_file is None:
|
||||
output_file = f"found_{customer_id}_{hashfile_id}.txt"
|
||||
|
||||
total = int(resp.headers.get("content-length", 0))
|
||||
downloaded = 0
|
||||
chunk_size = 8192
|
||||
@@ -992,81 +994,110 @@ class HashviewAPI:
|
||||
if total == 0:
|
||||
print(f"Downloaded {downloaded} bytes.")
|
||||
|
||||
# Combine with corresponding left file output if it exists
|
||||
# Only combine if the output file matches the expected naming pattern
|
||||
# Split found file into hashes and clears
|
||||
output_dir = os.path.dirname(os.path.abspath(output_file)) or os.getcwd()
|
||||
found_hashes_file = os.path.join(output_dir, f"found_hashes_{customer_id}_{hashfile_id}.txt")
|
||||
found_clears_file = os.path.join(output_dir, f"found_clears_{customer_id}_{hashfile_id}.txt")
|
||||
|
||||
hashes_count = 0
|
||||
clears_count = 0
|
||||
combined_count = 0
|
||||
combined_file = None
|
||||
|
||||
# Extract customer_id and hashfile_id from the output filename to ensure proper matching
|
||||
import re
|
||||
|
||||
output_basename = os.path.basename(output_file)
|
||||
# Match pattern: found_{customer_id}_{hashfile_id}.txt
|
||||
match = re.match(r"found_(\d+)_(\d+)\.txt$", output_basename)
|
||||
|
||||
if match:
|
||||
found_customer_id = match.group(1)
|
||||
found_hashfile_id = match.group(2)
|
||||
|
||||
# Only proceed if the IDs from filename match the actual download IDs
|
||||
if (
|
||||
str(customer_id) == found_customer_id
|
||||
and str(hashfile_id) == found_hashfile_id
|
||||
):
|
||||
left_base = f"left_{customer_id}_{hashfile_id}.txt"
|
||||
|
||||
# Check for regular format .out file
|
||||
left_out = left_base + ".out"
|
||||
if not os.path.exists(left_out):
|
||||
# Check for pwdump format .nt.txt.out file
|
||||
left_out = f"left_{customer_id}_{hashfile_id}.nt.txt.out"
|
||||
|
||||
if os.path.exists(left_out):
|
||||
# Read existing hashes from .out file into a set
|
||||
found_hashes = set()
|
||||
with open(left_out, "r", encoding="utf-8", errors="ignore") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line:
|
||||
found_hashes.add(line)
|
||||
|
||||
original_count = len(found_hashes)
|
||||
|
||||
# Read and add hashes from the downloaded found file
|
||||
with open(output_file, "r", encoding="utf-8", errors="ignore") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line:
|
||||
found_hashes.add(line)
|
||||
|
||||
combined_count = len(found_hashes) - original_count
|
||||
|
||||
# Write combined results to the .out file
|
||||
combined_file = left_out
|
||||
with open(combined_file, "w", encoding="utf-8") as f:
|
||||
for line in sorted(found_hashes):
|
||||
f.write(line + "\n")
|
||||
|
||||
print(f"Combined {combined_count} new hashes from {output_file}")
|
||||
print(
|
||||
f"Total unique hashes in {combined_file}: {len(found_hashes)}"
|
||||
)
|
||||
|
||||
try:
|
||||
with open(found_hashes_file, "w", encoding="utf-8") as hf, \
|
||||
open(found_clears_file, "w", encoding="utf-8") as cf:
|
||||
with open(output_file, "r", encoding="utf-8", errors="ignore") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line:
|
||||
parts = line.rsplit(":", 1) # Split on last colon
|
||||
if len(parts) == 2:
|
||||
hash_part, clear_part = parts
|
||||
hf.write(hash_part + "\n")
|
||||
cf.write(clear_part + "\n")
|
||||
hashes_count += 1
|
||||
clears_count += 1
|
||||
|
||||
print(f"✓ Split found file into {hashes_count} hashes and {clears_count} clears")
|
||||
|
||||
# Run hashcat to combine them into an output file
|
||||
combined_file = output_file + ".out"
|
||||
try:
|
||||
tuning_args = get_hcat_tuning_args()
|
||||
|
||||
# Create temporary outfile for hashcat
|
||||
temp_outfile = output_file + ".tmp"
|
||||
|
||||
if self.debug:
|
||||
print(f"[DEBUG] download_found_hashes: hash_type={hash_type}, type={type(hash_type)}")
|
||||
|
||||
# Build command with hash type if provided
|
||||
cmd = ["hashcat", *tuning_args]
|
||||
if hash_type:
|
||||
cmd.extend(["-m", str(hash_type)])
|
||||
cmd.extend([
|
||||
found_hashes_file,
|
||||
found_clears_file,
|
||||
"--outfile",
|
||||
temp_outfile,
|
||||
"--outfile-format=1,2",
|
||||
])
|
||||
|
||||
if self.debug:
|
||||
print(f"[DEBUG] Running command: {' '.join(cmd)}")
|
||||
|
||||
print(f"Running: {' '.join(cmd)}")
|
||||
|
||||
result = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, timeout=300)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"Warning: hashcat exited with code {result.returncode}")
|
||||
if result.stderr:
|
||||
print(f" stderr: {result.stderr}")
|
||||
|
||||
# Write the output file
|
||||
if os.path.exists(temp_outfile):
|
||||
with open(temp_outfile, "r", encoding="utf-8", errors="ignore") as tmp_f:
|
||||
with open(combined_file, "w", encoding="utf-8") as out_f:
|
||||
out_f.write(tmp_f.read())
|
||||
|
||||
# Delete the found file after successful merge
|
||||
# Count lines in output
|
||||
with open(combined_file, "r", encoding="utf-8", errors="ignore") as f:
|
||||
combined_count = len(f.readlines())
|
||||
print(f"✓ Created {combined_file} (total lines: {combined_count})")
|
||||
|
||||
# Clean up temp file
|
||||
try:
|
||||
os.remove(output_file)
|
||||
print(f"Deleted {output_file} after merge")
|
||||
os.remove(temp_outfile)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
print("Note: No cracked hashes generated")
|
||||
|
||||
except FileNotFoundError:
|
||||
print("✗ Error: hashcat not found in PATH")
|
||||
except subprocess.TimeoutExpired:
|
||||
print("✗ Error: hashcat execution timed out")
|
||||
except Exception as e:
|
||||
print(f"✗ Error running hashcat: {e}")
|
||||
|
||||
# Clean up temporary files (keep when debug is enabled)
|
||||
if not self.debug:
|
||||
files_to_delete = [found_hashes_file, found_clears_file]
|
||||
for temp_file in files_to_delete:
|
||||
try:
|
||||
if os.path.exists(temp_file):
|
||||
os.remove(temp_file)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not delete {output_file}: {e}")
|
||||
if self.debug:
|
||||
print(f"Warning: Could not delete {temp_file}: {e}")
|
||||
else:
|
||||
print(
|
||||
f"Skipping combine: customer_id/hashfile_id mismatch (expected {customer_id}/{hashfile_id}, filename has {found_customer_id}/{found_hashfile_id})"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"Skipping combine: output filename '{output_basename}' doesn't match expected pattern 'found_<customer_id>_<hashfile_id>.txt'"
|
||||
)
|
||||
|
||||
print("Debug enabled: keeping split files")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Error splitting found file: {e}")
|
||||
|
||||
return {
|
||||
"output_file": output_file,
|
||||
"size": downloaded,
|
||||
|
||||
@@ -327,7 +327,75 @@ def fingerprint_crack(ctx: Any) -> None:
|
||||
|
||||
|
||||
def combinator_crack(ctx: Any) -> None:
|
||||
ctx.hcatCombination(ctx.hcatHashType, ctx.hcatHashFile)
|
||||
print("\n" + "=" * 60)
|
||||
print("COMBINATOR ATTACK")
|
||||
print("=" * 60)
|
||||
print("This attack combines two wordlists to generate candidates.")
|
||||
print("Example: wordlist1='password' + wordlist2='123' = 'password123'")
|
||||
print("=" * 60)
|
||||
|
||||
use_default = (
|
||||
input("\nUse default combinator wordlists from config? (Y/n): ").strip().lower()
|
||||
)
|
||||
|
||||
if use_default != "n":
|
||||
print("\nUsing default wordlist(s) from config:")
|
||||
if isinstance(ctx.hcatCombinationWordlist, list):
|
||||
for wl in ctx.hcatCombinationWordlist:
|
||||
print(f" - {wl}")
|
||||
wordlists = ctx.hcatCombinationWordlist
|
||||
else:
|
||||
print(f" - {ctx.hcatCombinationWordlist}")
|
||||
wordlists = [ctx.hcatCombinationWordlist]
|
||||
else:
|
||||
print("\nSelect wordlists for combinator attack.")
|
||||
print("You need to provide exactly 2 wordlists.")
|
||||
print("You can enter:")
|
||||
print(" - Two file paths separated by commas")
|
||||
print(" - Press TAB to autocomplete file paths")
|
||||
|
||||
selection = ctx.select_file_with_autocomplete(
|
||||
"Enter 2 wordlist files (comma-separated)", allow_multiple=True
|
||||
)
|
||||
|
||||
if not selection:
|
||||
print("No wordlists selected. Aborting combinator attack.")
|
||||
return
|
||||
|
||||
if isinstance(selection, str):
|
||||
wordlists = [selection]
|
||||
else:
|
||||
wordlists = selection
|
||||
|
||||
if len(wordlists) < 2:
|
||||
print("\n[!] Combinator attack requires at least 2 wordlists.")
|
||||
print("Aborting combinator attack.")
|
||||
return
|
||||
|
||||
valid_wordlists = []
|
||||
for wl in wordlists[:2]: # Only use first 2
|
||||
resolved = ctx._resolve_wordlist_path(wl, ctx.hcatWordlists)
|
||||
if os.path.isfile(resolved):
|
||||
valid_wordlists.append(resolved)
|
||||
print(f"✓ Found: {resolved}")
|
||||
else:
|
||||
print(f"✗ Not found: {resolved}")
|
||||
|
||||
if len(valid_wordlists) < 2:
|
||||
print("\nCould not find 2 valid wordlists. Aborting combinator attack.")
|
||||
return
|
||||
|
||||
wordlists = valid_wordlists
|
||||
|
||||
wordlists = [ctx._resolve_wordlist_path(wl, ctx.hcatWordlists) for wl in wordlists[:2]]
|
||||
|
||||
print(f"\nStarting combinator attack with 2 wordlists:")
|
||||
print(f" Wordlist 1: {wordlists[0]}")
|
||||
print(f" Wordlist 2: {wordlists[1]}")
|
||||
print(f"Hash type: {ctx.hcatHashType}")
|
||||
print(f"Hash file: {ctx.hcatHashFile}")
|
||||
|
||||
ctx.hcatCombination(ctx.hcatHashType, ctx.hcatHashFile, wordlists)
|
||||
|
||||
|
||||
def hybrid_crack(ctx: Any) -> None:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"hcatBin": "hashcat",
|
||||
"hcatTuning": "--force --remove",
|
||||
"hcatPotfilePath": "~/.hashcat/hashcat.potfile",
|
||||
"hcatDebugLogPath": "./hashcat_debug",
|
||||
"hcatWordlists": "/Passwords/wordlists",
|
||||
"hcatOptimizedWordlists": "/Passwords/optimized_wordlists",
|
||||
"rules_directory": "/path/to/hashcat/rules",
|
||||
|
||||
@@ -454,6 +454,18 @@ except KeyError as e:
|
||||
)
|
||||
hcatGoodMeasureBaseList = default_config[e.args[0]]
|
||||
|
||||
try:
|
||||
hcatDebugLogPath = config_parser.get("hcatDebugLogPath", "./hashcat_debug")
|
||||
# Expand user home directory if present
|
||||
hcatDebugLogPath = os.path.expanduser(hcatDebugLogPath)
|
||||
except KeyError as e:
|
||||
print(
|
||||
"{0} is not defined in config.json using defaults from config.json.example".format(
|
||||
e
|
||||
)
|
||||
)
|
||||
hcatDebugLogPath = os.path.expanduser(default_config.get("hcatDebugLogPath", "./hashcat_debug"))
|
||||
|
||||
hcatExpanderBin = "expander.bin"
|
||||
hcatCombinatorBin = "combinator.bin"
|
||||
hcatPrinceBin = "pp64.bin"
|
||||
@@ -689,6 +701,28 @@ def _debug_cmd(cmd):
|
||||
print(f"[DEBUG] hashcat cmd: {_format_cmd(cmd)}")
|
||||
|
||||
|
||||
def _add_debug_mode_for_rules(cmd):
|
||||
"""Add debug mode arguments to hashcat command if rules are being used.
|
||||
|
||||
This function detects if rules are present in the command (by looking for -r flags)
|
||||
and adds --debug-mode=1 and --debug-file=<path> if rules are found.
|
||||
Debug log path is configurable via hcatDebugLogPath in config.json
|
||||
"""
|
||||
if "-r" in cmd:
|
||||
# Create debug output directory if it doesn't exist
|
||||
os.makedirs(hcatDebugLogPath, exist_ok=True)
|
||||
|
||||
# Create a debug output filename based on the session ID or hash file
|
||||
debug_filename = os.path.join(hcatDebugLogPath, "hashcat_debug.log")
|
||||
if "--session" in cmd:
|
||||
session_idx = cmd.index("--session") + 1
|
||||
if session_idx < len(cmd):
|
||||
debug_filename = os.path.join(hcatDebugLogPath, f"hashcat_debug_{cmd[session_idx]}.log")
|
||||
|
||||
cmd.extend(["--debug-mode", "4", "--debug-file", debug_filename])
|
||||
return cmd
|
||||
|
||||
|
||||
# Sanitize filename for use as hashcat session name
|
||||
def generate_session_id():
|
||||
"""Sanitize the hashfile name for use as a hashcat session name
|
||||
@@ -932,6 +966,7 @@ def hcatDictionary(hcatHashType, hcatHashFile):
|
||||
cmd.extend(["-r", rule_best66])
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd)
|
||||
cmd = _add_debug_mode_for_rules(cmd)
|
||||
hcatProcess = subprocess.Popen(cmd)
|
||||
try:
|
||||
hcatProcess.wait()
|
||||
@@ -956,6 +991,7 @@ def hcatDictionary(hcatHashType, hcatHashFile):
|
||||
]
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd)
|
||||
cmd = _add_debug_mode_for_rules(cmd)
|
||||
hcatProcess = subprocess.Popen(cmd)
|
||||
try:
|
||||
hcatProcess.wait()
|
||||
@@ -979,6 +1015,7 @@ def hcatDictionary(hcatHashType, hcatHashFile):
|
||||
]
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd)
|
||||
cmd = _add_debug_mode_for_rules(cmd)
|
||||
hcatProcess = subprocess.Popen(cmd)
|
||||
try:
|
||||
hcatProcess.wait()
|
||||
@@ -1020,6 +1057,7 @@ def hcatQuickDictionary(
|
||||
cmd.extend(shlex.split(hcatChains))
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd, use_potfile_path=use_potfile_path, potfile_path=potfile_path)
|
||||
cmd = _add_debug_mode_for_rules(cmd)
|
||||
_debug_cmd(cmd)
|
||||
hcatProcess = subprocess.Popen(cmd)
|
||||
try:
|
||||
@@ -1178,9 +1216,35 @@ def hcatFingerprint(
|
||||
|
||||
|
||||
# Combinator Attack
|
||||
def hcatCombination(hcatHashType, hcatHashFile):
|
||||
def hcatCombination(hcatHashType, hcatHashFile, wordlists=None):
|
||||
global hcatCombinationCount
|
||||
global hcatProcess
|
||||
|
||||
# Use provided wordlists or fall back to config default
|
||||
if wordlists is None:
|
||||
wordlists = hcatCombinationWordlist
|
||||
|
||||
# Ensure wordlists is a list with at least 2 items
|
||||
if not isinstance(wordlists, list):
|
||||
wordlists = [wordlists]
|
||||
|
||||
if len(wordlists) < 2:
|
||||
print("[!] Combinator attack requires at least 2 wordlists.")
|
||||
return
|
||||
|
||||
# Resolve wordlist paths
|
||||
resolved_wordlists = []
|
||||
for wordlist in wordlists[:2]: # Only use first 2 wordlists
|
||||
resolved = _resolve_wordlist_path(wordlist, hcatWordlists)
|
||||
if os.path.isfile(resolved):
|
||||
resolved_wordlists.append(resolved)
|
||||
else:
|
||||
print(f"[!] Wordlist not found: {resolved}")
|
||||
|
||||
if len(resolved_wordlists) < 2:
|
||||
print("[!] Could not find 2 valid wordlists. Aborting combinator attack.")
|
||||
return
|
||||
|
||||
cmd = [
|
||||
hcatBin,
|
||||
"-m",
|
||||
@@ -1192,8 +1256,8 @@ def hcatCombination(hcatHashType, hcatHashFile):
|
||||
f"{hcatHashFile}.out",
|
||||
"-a",
|
||||
"1",
|
||||
hcatCombinationWordlist[0],
|
||||
hcatCombinationWordlist[1],
|
||||
resolved_wordlists[0],
|
||||
resolved_wordlists[1],
|
||||
]
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd)
|
||||
@@ -1620,6 +1684,7 @@ def hcatPrince(hcatHashType, hcatHashFile):
|
||||
]
|
||||
hashcat_cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(hashcat_cmd)
|
||||
hashcat_cmd = _add_debug_mode_for_rules(hashcat_cmd)
|
||||
with open(prince_base, "rb") as base:
|
||||
prince_proc = subprocess.Popen(prince_cmd, stdin=base, stdout=subprocess.PIPE)
|
||||
hcatProcess = subprocess.Popen(hashcat_cmd, stdin=prince_proc.stdout)
|
||||
@@ -1656,6 +1721,7 @@ def hcatGoodMeasure(hcatHashType, hcatHashFile):
|
||||
]
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd)
|
||||
cmd = _add_debug_mode_for_rules(cmd)
|
||||
hcatProcess = subprocess.Popen(cmd)
|
||||
try:
|
||||
hcatProcess.wait()
|
||||
@@ -1739,6 +1805,7 @@ def hcatLMtoNT():
|
||||
]
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd)
|
||||
cmd = _add_debug_mode_for_rules(cmd)
|
||||
hcatProcess = subprocess.Popen(cmd)
|
||||
try:
|
||||
hcatProcess.wait()
|
||||
@@ -1778,6 +1845,7 @@ def hcatRecycle(hcatHashType, hcatHashFile, hcatNewPasswords):
|
||||
]
|
||||
cmd.extend(shlex.split(hcatTuning))
|
||||
_append_potfile_arg(cmd)
|
||||
cmd = _add_debug_mode_for_rules(cmd)
|
||||
hcatProcess = subprocess.Popen(cmd)
|
||||
try:
|
||||
hcatProcess.wait()
|
||||
@@ -1897,6 +1965,7 @@ def hashview_api():
|
||||
menu_options.append(("upload_wordlist", "Upload Wordlist"))
|
||||
menu_options.append(("download_wordlist", "Download Wordlist"))
|
||||
menu_options.append(("download_left", "Download Left Hashes (with automatic merge if found)"))
|
||||
menu_options.append(("download_found", "Download Found Hashes (with automatic split)"))
|
||||
if hcatHashFile:
|
||||
menu_options.append(("upload_hashfile_job", "Upload Hashfile and Create Job"))
|
||||
menu_options.append(("back", "Back to Main Menu"))
|
||||
@@ -2415,6 +2484,152 @@ def hashview_api():
|
||||
except Exception as e:
|
||||
print(f"\n✗ Error downloading hashes: {str(e)}")
|
||||
|
||||
elif option_key == "download_found":
|
||||
# Download found hashes
|
||||
try:
|
||||
while True:
|
||||
# First, list customers to help user select
|
||||
customers_result = api_harness.list_customers()
|
||||
customers = (
|
||||
customers_result.get("customers", [])
|
||||
if isinstance(customers_result, dict)
|
||||
else customers_result
|
||||
)
|
||||
if customers:
|
||||
api_harness.display_customers_multicolumn(customers)
|
||||
else:
|
||||
print("\nNo customers found.")
|
||||
|
||||
# Select or create customer
|
||||
customer_input = input(
|
||||
"\nEnter customer ID or N to create new: "
|
||||
).strip()
|
||||
if customer_input.lower() == "n":
|
||||
customer_name = input("Enter customer name: ").strip()
|
||||
if customer_name:
|
||||
try:
|
||||
result = api_harness.create_customer(customer_name)
|
||||
print(
|
||||
f"\n✓ Success: {result.get('msg', 'Customer created')}"
|
||||
)
|
||||
customer_id = result.get("customer_id") or result.get("id")
|
||||
if not customer_id:
|
||||
print("\n✗ Error: Customer ID not returned.")
|
||||
continue
|
||||
print(f" Customer ID: {customer_id}")
|
||||
except Exception as e:
|
||||
print(f"\n✗ Error creating customer: {str(e)}")
|
||||
continue
|
||||
else:
|
||||
print("\n✗ Error: Customer name cannot be empty.")
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
customer_id = int(customer_input)
|
||||
except ValueError:
|
||||
print(
|
||||
"\n✗ Error: Invalid ID entered. Please enter a numeric ID or N."
|
||||
)
|
||||
continue
|
||||
|
||||
# List hashfiles for the customer
|
||||
try:
|
||||
customer_hashfiles = api_harness.get_customer_hashfiles(
|
||||
customer_id
|
||||
)
|
||||
|
||||
if not customer_hashfiles:
|
||||
print(f"\nNo hashfiles found for customer ID {customer_id}")
|
||||
continue
|
||||
|
||||
print("\n" + "=" * 120)
|
||||
print(f"Hashfiles for Customer ID {customer_id}:")
|
||||
print("=" * 120)
|
||||
print(f"{'ID':<10} {'Hash Type':<10} {'Name':<96}")
|
||||
print("-" * 120)
|
||||
hashfile_map = {}
|
||||
for hf in customer_hashfiles:
|
||||
hf_id = hf.get("id")
|
||||
hf_name = hf.get("name", "N/A")
|
||||
hf_type = hf.get("hash_type") or hf.get("hashtype") or "N/A"
|
||||
if hf_id is None:
|
||||
continue
|
||||
# Truncate long names to fit within 120 columns
|
||||
if len(str(hf_name)) > 96:
|
||||
hf_name = str(hf_name)[:93] + "..."
|
||||
if debug_mode:
|
||||
print(f"[DEBUG] Hashfile {hf_id}: hash_type={hf.get('hash_type')}, hashtype={hf.get('hashtype')}, combined={hf_type}")
|
||||
print(f"{hf_id:<10} {hf_type:<10} {hf_name:<96}")
|
||||
hashfile_map[int(hf_id)] = hf_type
|
||||
print("=" * 120)
|
||||
print(f"Total: {len(hashfile_map)} hashfile(s)")
|
||||
except Exception as e:
|
||||
print(f"\nWarning: Could not list hashfiles: {e}")
|
||||
continue
|
||||
|
||||
while True:
|
||||
try:
|
||||
hashfile_id_input = input("\nEnter hashfile ID: ").strip()
|
||||
hashfile_id = int(hashfile_id_input)
|
||||
except ValueError:
|
||||
print("\n✗ Error: Invalid ID entered. Please enter a numeric ID.")
|
||||
continue
|
||||
if hashfile_id not in hashfile_map:
|
||||
print("\n✗ Error: Hashfile ID not in the list. Please try again.")
|
||||
continue
|
||||
break
|
||||
break
|
||||
|
||||
# Set output filename automatically
|
||||
output_file = f"found_{customer_id}_{hashfile_id}.txt"
|
||||
|
||||
# Get hash type for hashcat from the hashfile map
|
||||
selected_hash_type = hashfile_map.get(hashfile_id)
|
||||
if debug_mode:
|
||||
print(f"[DEBUG] selected_hash_type from map: {selected_hash_type}")
|
||||
if not selected_hash_type or selected_hash_type == "N/A":
|
||||
try:
|
||||
details = api_harness.get_hashfile_details(hashfile_id)
|
||||
selected_hash_type = details.get("hashtype")
|
||||
if debug_mode:
|
||||
print(f"[DEBUG] selected_hash_type from get_hashfile_details: {selected_hash_type}")
|
||||
except Exception as e:
|
||||
if debug_mode:
|
||||
print(f"[DEBUG] Error fetching hashfile details: {e}")
|
||||
selected_hash_type = None
|
||||
|
||||
# Download the found hashes
|
||||
if debug_mode:
|
||||
print(f"[DEBUG] Calling download_found_hashes with hash_type={selected_hash_type}")
|
||||
download_result = api_harness.download_found_hashes(
|
||||
customer_id, hashfile_id, output_file
|
||||
)
|
||||
print(f"\n✓ Success: Downloaded {download_result['size']} bytes")
|
||||
print(f" File: {download_result['output_file']}")
|
||||
if selected_hash_type:
|
||||
print(f" Hash mode: {selected_hash_type}")
|
||||
|
||||
# Ask if user wants to switch to this hashfile
|
||||
switch = (
|
||||
input("\nSwitch to this hashfile for cracking? (Y/n): ")
|
||||
.strip()
|
||||
.lower()
|
||||
)
|
||||
if switch != "n":
|
||||
hcatHashFile = download_result["output_file"]
|
||||
if selected_hash_type:
|
||||
hcatHashType = str(selected_hash_type)
|
||||
else:
|
||||
hcatHashType = "1000" # Default to NTLM if unavailable
|
||||
print(f"✓ Switched to hashfile: {hcatHashFile}")
|
||||
print("\nReturning to main menu to start cracking...")
|
||||
return # Exit hashview menu and return to main menu
|
||||
|
||||
except ValueError:
|
||||
print("\n✗ Error: Invalid ID entered. Please enter a numeric ID.")
|
||||
except Exception as e:
|
||||
print(f"\n✗ Error downloading found hashes: {str(e)}")
|
||||
|
||||
elif option_key == "back":
|
||||
break
|
||||
|
||||
|
||||
Reference in New Issue
Block a user