automatic hash_id detection via api for hashview hashes and updated tests.

This commit is contained in:
Justin Bollinger
2026-02-05 15:39:08 -05:00
parent af5fe15ec4
commit ba61662d03
2 changed files with 84 additions and 19 deletions
+69 -16
View File
@@ -1815,18 +1815,47 @@ def hashview_api():
print("\n" + "=" * 60)
print("What would you like to do?")
print("=" * 60)
print("\t(1) Upload Cracked Hashes from current session")
print("\t(2) Upload Wordlist")
print("\t(3) Download Wordlist")
print("\t(4) Download Left Hashes (with automatic merge if found)")
# Build dynamic menu based on state
menu_options = []
if hcatHashFile:
print("\t(5) Upload Hashfile and Create Job")
print("\t(99) Back to Main Menu")
menu_options.append(("upload_cracked", "Upload Cracked Hashes from current session"))
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)"))
if hcatHashFile:
menu_options.append(("upload_hashfile_job", "Upload Hashfile and Create Job"))
menu_options.append(("back", "Back to Main Menu"))
# Display menu with dynamic numbering
for i, (option_key, option_text) in enumerate(menu_options, 1):
if option_key == "back":
print(f"\t(99) {option_text}")
else:
print(f"\t({i}) {option_text}")
# Create mapping of display numbers to option keys
option_map = {}
display_num = 1
for option_key, _ in menu_options[:-1]: # All except "back"
option_map[str(display_num)] = option_key
display_num += 1
option_map["99"] = "back"
choice = input("\nSelect an option: ")
if choice not in option_map:
print("Invalid option. Please try again.")
continue
option_key = option_map[choice]
if choice == "1":
if option_key == "upload_cracked":
# Upload cracked hashes
if not hcatHashFile:
print("\n✗ Error: No hashfile is currently set. This option is not available.")
continue
print("\n" + "-" * 60)
print("Upload Cracked Hashes")
print("-" * 60)
@@ -1906,7 +1935,7 @@ def hashview_api():
print("\nFull error details:")
traceback.print_exc()
elif choice == "2":
elif option_key == "upload_wordlist":
print("\n" + "-" * 60)
print("Upload Wordlist")
print("-" * 60)
@@ -1936,7 +1965,7 @@ def hashview_api():
except Exception as e:
print(f"\n✗ Error uploading wordlist: {str(e)}")
elif choice == "3":
elif option_key == "download_wordlist":
# Download wordlist
try:
wordlists = api_harness.list_wordlists()
@@ -1982,7 +2011,7 @@ def hashview_api():
except Exception as e:
print(f"\n✗ Error downloading wordlist: {str(e)}")
elif choice == "5":
elif option_key == "upload_hashfile_job":
# Upload hashfile and create job
if not hcatHashFile:
print("\n✗ Error: No hashfile is currently set.")
@@ -2154,7 +2183,7 @@ def hashview_api():
except Exception as e:
print(f"\n✗ Error uploading hashfile: {str(e)}")
elif choice == "4":
elif option_key == "download_left":
# Download left hashes
try:
while True:
@@ -2300,13 +2329,11 @@ def hashview_api():
except Exception as e:
print(f"\n✗ Error downloading hashes: {str(e)}")
elif choice == "99":
elif option_key == "back":
break
else:
print("Invalid option. Please try again.")
except KeyboardInterrupt:
print("\n\nHashview upload canceled.")
quit_hc()
except Exception as e:
print(f"\nError connecting to Hashview: {str(e)}")
@@ -2698,6 +2725,17 @@ def main():
"--hash-type", default=None, help="Hash type for hashcat (e.g., 1000 for NTLM)"
)
hv_download_found = hashview_subparsers.add_parser(
"download-found",
help="Download found hashes for a hashfile",
)
hv_download_found.add_argument(
"--customer-id", required=True, type=int, help="Customer ID"
)
hv_download_found.add_argument(
"--hashfile-id", required=True, type=int, help="Hashfile ID"
)
hv_upload_hashfile_job = hashview_subparsers.add_parser(
"upload-hashfile-job",
help="Upload a hashfile and create a job",
@@ -2735,7 +2773,13 @@ def main():
# Removed add_common_args(parser) since config items are now only set via config file
argv = sys.argv[1:]
hashview_subcommands = ["upload-cracked", "upload-wordlist", "download-left", "upload-hashfile-job"]
hashview_subcommands = [
"upload-cracked",
"upload-wordlist",
"download-left",
"download-found",
"upload-hashfile-job",
]
has_hashview_flag = "--hashview" in argv
has_hashview_subcommand = any(cmd in argv for cmd in hashview_subcommands)
@@ -2850,6 +2894,15 @@ def main():
print(f" File: {download_result['output_file']}")
sys.exit(0)
if args.hashview_command == "download-found":
download_result = api_harness.download_found_hashes(
args.customer_id,
args.hashfile_id,
)
print(f"\n✓ Success: Downloaded {download_result['size']} bytes")
print(f" File: {download_result['output_file']}")
sys.exit(0)
if args.hashview_command == "upload-hashfile-job":
hashfile_path = resolve_path(args.file)
if not hashfile_path or not os.path.isfile(hashfile_path):
@@ -47,6 +47,10 @@ def _ensure_customer_one():
if not url or not key:
pytest.skip("Missing hashview_url/hashview_api_key in config.json or env.")
api = HashviewAPI(url, key)
# Get customer ID from environment or default to 1
customer_id = int(os.environ.get("HASHVIEW_CUSTOMER_ID", "1"))
try:
customers_result = api.list_customers()
except Exception as exc:
@@ -56,9 +60,9 @@ def _ensure_customer_one():
if isinstance(customers_result, dict)
else customers_result
)
if not any(int(cust.get("id", 0)) == 1 for cust in customers or []):
api.create_customer("Example Customer")
return 1
if not any(int(cust.get("id", 0)) == customer_id for cust in customers or []):
api.create_customer(f"Example Customer {customer_id}")
return customer_id
@pytest.mark.parametrize(
@@ -226,6 +230,10 @@ def test_hashview_subcommands_live_upload_hashfile_job(tmp_path):
env=env,
)
output = run.stdout + run.stderr
if "Invalid customer ID" in output:
pytest.skip(
"HASHVIEW_CUSTOMER_ID does not exist for this API key. Update the env or create the customer."
)
assert run.returncode == 0, output
assert ("Hashfile uploaded" in output) or ("Hashfile added" in output)
assert ("Job created" in output) or ("Failed to add job" in output)
@@ -312,6 +320,10 @@ def test_hashview_subcommands_live_upload_hashfile_job_pwdump(tmp_path):
env=env,
)
output = run.stdout + run.stderr
if "Invalid customer ID" in output:
pytest.skip(
"HASHVIEW_CUSTOMER_ID does not exist for this API key. Update the env or create the customer."
)
assert run.returncode == 0, output
assert ("Hashfile uploaded" in output) or ("Hashfile added" in output)
assert ("Job created" in output) or ("Failed to add job" in output)