fix: propagate --username to hashcat --show potfile checks

`_run_hashcat_show` is called during the initial potfile check (main
preprocessing) and by `combine_ntlm_output` via `check_potfile()`. It
invokes `hashcat --show` via `subprocess.run` and previously did not go
through `_append_potfile_arg`, so it never received `--username`.

Without `--username`, hashcat treats the first colon of a `user:hash`
line as part of the hash and fails to match any potfile entries. This
caused the initial "already cracked" check to report zero hits for
legitimately cracked `user:hash` input files.

Route the command build through `_maybe_append_username_flag` before
invoking subprocess, mirroring the `_append_potfile_arg` pattern for
normal attack commands. Adds `TestUsernameInjectionIntoShow` covering
both flag-set and flag-unset code paths.

Refs #107

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Justin Bollinger
2026-04-22 15:18:31 -04:00
parent 77bb17d6fa
commit b75d897f42
2 changed files with 47 additions and 9 deletions

View File

@@ -1154,8 +1154,7 @@ def _dedup_netntlm_by_username(
def _run_hashcat_show(hash_type, hash_file, output_path):
result = subprocess.run(
[
cmd = [
hcatBin,
"--show",
# Use hashcat's built-in potfile unless configured otherwise.
@@ -1163,7 +1162,13 @@ def _run_hashcat_show(hash_type, hash_file, output_path):
"-m",
str(hash_type),
hash_file,
],
]
# If username:hash format was detected, --show also needs --username
# to parse the input correctly; otherwise it treats "user:hash" as a
# literal hash and finds no matches in the potfile.
_maybe_append_username_flag(cmd)
result = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
check=False,

View File

@@ -332,3 +332,36 @@ class TestUsernameInjectionIntoBruteForce:
main_module.hcatBruteForce("0", hash_file, 1, 7)
cmd = mp.call_args[0][0]
assert cmd.count("--username") == 1
class TestUsernameInjectionIntoShow:
"""_run_hashcat_show should also honor hcatUsernamePrefix so the initial
potfile check and combine_ntlm_output correctly parse user:hash files."""
def test_show_contains_username_when_flag_set(self, main_module, tmp_path):
hash_file = str(tmp_path / "hashes.txt")
output_path = str(tmp_path / "hashes.out")
mock_result = MagicMock()
mock_result.stdout = b""
with patch.object(main_module, "hcatBin", "hashcat"), \
patch.object(main_module, "hcatPotfilePath", ""), \
patch.object(main_module, "hcatUsernamePrefix", True), \
patch("hate_crack.main.subprocess.run", return_value=mock_result) as mr:
main_module._run_hashcat_show("0", hash_file, output_path)
cmd = mr.call_args[0][0]
assert "--username" in cmd
def test_show_no_username_when_flag_unset(self, main_module, tmp_path):
hash_file = str(tmp_path / "hashes.txt")
output_path = str(tmp_path / "hashes.out")
mock_result = MagicMock()
mock_result.stdout = b""
with patch.object(main_module, "hcatBin", "hashcat"), \
patch.object(main_module, "hcatPotfilePath", ""), \
patch.object(main_module, "hcatUsernamePrefix", False), \
patch("hate_crack.main.subprocess.run", return_value=mock_result) as mr:
main_module._run_hashcat_show("0", hash_file, output_path)
cmd = mr.call_args[0][0]
assert "--username" not in cmd