Commit Graph
568 Commits
Author SHA1 Message Date
Justin BollingerandClaude Opus 4.6 fa940f67c5 perf: replace hard 15s sleep with proper rate limiter for Hashmob downloads
Introduces a shared _RateLimiter class (1 req/2s) instead of per-function
locks with a 15-second sleep. Also tunes backoff from 256s to 30s with
30s penalty increments for faster retry on rate-limited responses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:09:39 -04:00
Justin BollingerandGitHub 33e12eebc4 Merge pull request #105 from trustedsec/fix/output-path-symlinks
Fix output file path and remove symlink creation
v2.5.1
2026-04-08 13:11:49 -04:00
Justin BollingerandClaude Opus 4.6 c1a2767be3 test: add e2e test for output file path correctness
Verifies that a pwdump file at /tmp/test_hashes.ntds produces output
at /tmp/test_hashes.ntds.out using real hashcat. Confirms no files
leak into the project directory. Gated behind HATE_CRACK_RUN_E2E=1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:07:33 -04:00
Justin BollingerandClaude Opus 4.6 8e83bdeea3 fix: only report combined output file when it exists
cleanup() previously always printed 'Cracked passwords combined in
X.out' even when combine_ntlm_output() returned early (no cracked
hashes) or the hash type wasn't NTLM pwdump. Now checks file
existence first and falls back to pointing at the raw .out file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:05:08 -04:00
Justin Bollinger cce1b9d466 Merge branch 'remove-symlink-logic' 2026-04-08 13:02:49 -04:00
Justin BollingerandClaude Opus 4.6 9b97cd2a48 fix: remove symlink/copy from _ensure_hashfile_in_cwd
Output files now land next to the original hashfile. resolve_path()
already resolves relative paths against HATE_CRACK_ORIG_CWD, so
relocating the hashfile into CWD was unnecessary and created
confusing symlinks in the working directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:02:26 -04:00
Justin BollingerandClaude Opus 4.6 fa07d37a84 fix: write output files to user's CWD, not install directory
The bash shim uses `uv run --directory <install_dir>` which changes the
process CWD to the install directory. _ensure_hashfile_in_cwd() and the
Hashview download path used os.getcwd() to determine the target directory
for output files (.out, .nt, etc.), causing them to land in the install
directory instead of where the user ran the command.

Add orig_cwd() helper that reads HATE_CRACK_ORIG_CWD (set by the shim)
and use it in _ensure_hashfile_in_cwd(), the Hashview download path, and
the potfile fallback path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 11:43:51 -04:00
Justin Bollinger d0bfb015a6 docs: update README for v2.5.0 changes 2026-03-20 11:15:29 -04:00
Justin Bollinger 55e12211bb feat: restore hcatOptimizedWordlists config and use as quick crack default
Re-add hcatOptimizedWordlists config key (previously removed) with a
default of ./optimized_wordlists. Falls back to hcatWordlists if the
configured directory does not exist.

Update quick_crack to list files from and default to hcatOptimizedWordlists
instead of hcatWordlists when prompting for a wordlist or directory.
v2.5.0
2026-03-20 11:06:03 -04:00
Justin Bollinger 1de51e9094 feat: add tab autocomplete to wordlist menu file path prompts
Replace input() with ctx.select_file_with_autocomplete() for all file
and directory path prompts in the 7 wordlist tools submenu functions.
Non-path prompts (lengths, masks, offsets, mode selection) remain as
plain input() calls.

Update tests to set ctx.select_file_with_autocomplete.side_effect for
file path values and leave builtins.input patches only for non-path
inputs.
2026-03-20 10:30:08 -04:00
Justin Bollinger 1b812cda32 fix: move dev tools to dependency-groups so uv sync installs them always
ruff, ty, pytest, pytest-cov were in [project.optional-dependencies]
requiring --extra dev to install. Moved to [dependency-groups] which
uv sync includes by default, fixing the pre-push hook finding no ruff.
v2.4.7
2026-03-20 10:16:53 -04:00
Justin Bollinger e627807794 fix: read version from package metadata instead of _version.py
Replaces the _version.py import with importlib.metadata.version() so
the version is always read from the installed package, which setuptools-scm
writes correctly during uv sync. Removes the version_file config and
the stale-file workarounds from make install/clean.
2026-03-20 10:16:04 -04:00
Justin Bollinger e7f15dc0b5 ci: auto-publish GitHub release on version tag push v2.4.5 2026-03-20 10:13:22 -04:00
Justin Bollinger a9cad18949 fix: force _version.py regeneration on install and clean
_version.py is gitignored but persists on disk with a stale version.
Delete it before uv sync so setuptools-scm regenerates it from the
current git tag. Also remove it in make clean for consistency.
v2.4.4
2026-03-20 10:08:56 -04:00
Justin Bollinger b4b284cf50 fix: remove hashcat preflight check from Makefile
Hashcat path is configured via config.json at runtime. The build-time
check caused false failures when running as root (sudo) or before
config.json exists, and added no value since hashcat-utils builds
independently of the hashcat installation.
v2.4.3
2026-03-20 10:02:54 -04:00
Justin Bollinger d44527cd6e fix: search candidate config dirs in Makefile preflight hashcat check
Mirrors the Python runtime's _candidate_roots() logic so hcatPath is
honored even when config.json lives in ~/.hate_crack or another
non-cwd location.
v2.4.2
2026-03-20 09:55:28 -04:00
Justin Bollinger d1192f118f fix: honor config.json hcatPath/hcatBin in Makefile preflight check
The submodules-pre hashcat check now reads hcatPath and hcatBin from
config.json (mirroring main.py resolution logic) before falling back to
PATH lookup and the vendored hate_crack/hashcat/hashcat binary.
2026-03-20 09:37:34 -04:00
Justin Bollinger 2565641b29 fix: resolve hashcat binary from hcatPath when not in PATH
- Apply os.path.expanduser() to hcatPath so tilde (~) paths work,
  consistent with every other config path (hcatWordlists, rulesDirectory,
  hcatPotfilePath, hcatDebugLogPath)
- Improve error message when binary not found to show what hcatPath was
  checked, making it easier to diagnose misconfiguration
- Update optimizedKernelAttacks in config.json.example to include all 21
  attacks from DEFAULT_OPTIMIZED_ATTACKS (13 were added in v2.4.0 but
  config.json.example was not updated, causing the runtime override to
  exclude them)
v2.4.1
2026-03-20 09:27:03 -04:00
Justin BollingerandGitHub 0265ba1031 Merge pull request #103 from trustedsec/feat/release-v2.4.0
feat: release v2.4.0 - wordlist filtering, parallel rule downloads, dynamic optimized kernels
v2.4.0
2026-03-20 09:05:14 -04:00
Justin Bollinger dab7bb41ee chore: add pytest-timeout dev dependency 2026-03-19 23:43:49 -04:00
Justin Bollinger f80dfcee4e fix: add skip guards for missing runtime artifacts in e2e/integration tests 2026-03-19 23:42:43 -04:00
Justin Bollinger a3ad5579b7 fix: preserve hate_crack.api in module reload to prevent test isolation hang 2026-03-19 23:40:24 -04:00
Justin Bollinger 3b036f9696 test: add optimized kernel unit and integration tests (#82) 2026-03-19 21:37:58 -04:00
Justin Bollinger 7880bffce1 feat: add dynamic optimized kernel (-O) to 11 additional attack types (#82) 2026-03-19 21:11:59 -04:00
Justin Bollinger 4aef38ec51 test: verify .7z wordlist filtering and parallel rule downloads (#80 #81) 2026-03-19 20:23:28 -04:00
Justin Bollinger e409511c88 fix: correct download_left_hashes potfile merge bugs
Merge fix/download-left-hashes-potfile-bugs
v2.3.6
2026-03-19 19:14:00 -04:00
Justin Bollinger e006833812 fix: correct download_left_hashes potfile merge bugs
- Delete block that wrongly appended found hashes back into the left
  (unsolved) file - found hashes belong only in the potfile
- Fix get_hcat_potfile_path() to return "" when config key is
  explicitly set to "", respecting user intent to disable potfile override
- Fix get_hcat_potfile_path() to resolve relative paths relative to the
  config file directory, matching main.py's hate_path resolution
- Add potfile_path parameter to download_left_hashes() and
  download_hashes_from_hashview() so CLI --potfile-path and
  --no-potfile-path overrides propagate to the API merge step
- Update main.py call sites to pass hcatPotfilePath through
- Add tests covering all four bug fixes
2026-03-19 19:13:41 -04:00
Justin Bollinger 8770a700df fix: locate uv binary before upgrade to handle non-standard PATH
When running as root or via sudo, /root/.local/bin may not be in PATH.
Use shutil.which with fallback to ~/.local/bin/uv, and fail clearly
if uv can't be found.
v2.3.5
2026-03-19 18:05:00 -04:00
Justin Bollinger 88064a5a4f fix: use git fetch --tags and uv sync --reinstall to fix version after upgrade
uv's PEP 517 build isolation copies source to a temp dir without .git,
so setuptools-scm can't determine the version and falls back to the
existing _version.py. Forcing --reinstall-package hate_crack makes uv
rebuild from source in the actual repo dir (editable mode) where git
is accessible, so the correct version is generated.
v2.3.4
2026-03-19 18:02:54 -04:00
Justin Bollinger 0f692efe55 fix: drop make clean from upgrade command to fix version detection
make clean deinits submodules and wipes the uv cache, causing
setuptools-scm to compute a wrong version during the subsequent
uv sync. The clean step is unnecessary for an upgrade - just
git pull && make install is sufficient.
v2.3.3
2026-03-19 17:57:09 -04:00
Justin Bollinger 8483a17242 feat: add --update flag to trigger in-place upgrade on demand
Refactors the upgrade logic into _run_upgrade() so it can be called
both from the startup version check prompt and directly via --update,
bypassing the version comparison entirely.
2026-03-19 17:49:23 -04:00
Justin Bollinger 9fba3f7bf6 feat: add upgrade prompt to version update check
When a newer release is found, prompt the user to upgrade in-place.
Resolves the git repo root via `git rev-parse --show-toplevel` before
running `git pull && make clean && make && make install`, so the upgrade
works correctly whether hate_crack is run from source or installed into
site-packages. Ctrl-C and EOF at the prompt continue normally.
v2.3.2
2026-03-19 17:45:36 -04:00
Justin BollingerandGitHub 7b3293aee5 Merge pull request #102 from trustedsec/bug/analyze-rules-tab-complete
fix: use tab-completion file selector for analyze hashcat rules
v2.3.1
2026-03-19 16:23:21 -04:00
Justin Bollinger 7cd98ea714 Merge remote-tracking branch 'origin/main' into bug/analyze-rules-tab-complete 2026-03-19 16:22:23 -04:00
Justin BollingerandGitHub 917a1b5977 Merge pull request #95 from trustedsec/feat/rule-tools
feat: add rule file management submenu (#93)
v2.3.0
2026-03-19 16:04:12 -04:00
Justin Bollinger 95d0eb229a feat: add rule file tools submenu (key 81) with cleanup and optimize
Resolves merge conflict with origin/main (keys 19-22 and 80 from main
kept, rule tools submenu added at key 81).
2026-03-19 16:03:40 -04:00
Justin BollingerandGitHub 961da2d350 Merge pull request #99 from trustedsec/feat/wordlist-tools
feat: add wordlist tools submenu (len, req-include, req-exclude, cutb, rli, rli2, splitlen, gate)
2026-03-19 16:00:40 -04:00
Justin Bollinger 4b5091ef89 feat: add wordlist tools submenu (key 80) with 7 hashcat-utils filters
Resolves merge conflict with origin/main (keys 19-22 from main kept,
wordlist tools submenu added at key 80).

Fixes test isolation bug in test_random_rules_attack.py where
load_cli_module() nuked hate_crack.attacks from sys.modules, breaking
__globals__ references in wordlist_tools_submenu for downstream tests.
Also corrects wrong menu key assertion (21 not 20) for generate_rules_crack.
2026-03-19 16:00:09 -04:00
Justin BollingerandGitHub de65388d62 Merge pull request #101 from trustedsec/feat/combipow-attack
feat: Passphrase combination attack (issue #88)
2026-03-19 15:50:58 -04:00
Justin Bollinger a31497649f feat: add combipow passphrase attack at menu key 22
Resolves merge conflict with origin/main (keys 19-21 used by ngram,
permute, random-rules). Combipow takes key 22.

- gzip support: decompress .gz wordlists to a temp file before passing
  path to combipow.bin (which requires a filename argument)
- UI line-counting uses gzip.open for .gz files
- Update tests to reference key 22 instead of 21
2026-03-19 15:50:25 -04:00
Justin BollingerandGitHub a59309c29d Merge pull request #96 from trustedsec/feat/random-rules-attack
feat: add random rules attack (#87)
2026-03-19 15:42:47 -04:00
Justin Bollinger 6032787fa0 chore: ignore large local wordlist files 2026-03-19 15:42:18 -04:00
Justin Bollinger 63e7286fcb merge: resolve conflicts with main - random rules moves to key 21 2026-03-19 15:42:11 -04:00
Justin BollingerandGitHub 243013dcdf Merge pull request #100 from trustedsec/feat/permute-attack
feat: add permutation attack (key 19)
2026-03-19 15:34:09 -04:00
Justin Bollinger 92a835c6d8 merge: resolve conflicts with main - permute moves to key 20, ngram stays at 19 2026-03-19 15:33:48 -04:00
Justin Bollinger ffce245f78 fix: remove unused tempfile import 2026-03-19 15:30:27 -04:00
Justin Bollinger 142ee4b245 fix: transparently decompress gzip wordlists for external tool attacks
Add _open_wordlist() helper that returns gzip.open() or open() based on
the .gz extension. Apply it to the three functions that open wordlist
files themselves before piping to an external binary:

- hcatPrince: prince base list fed to pp64.bin
- hcatPermute: wordlist fed to permute.bin
- hcatMarkovTrain: source file fed to hcstat2gen.bin

Attacks that pass wordlist paths directly to hashcat are unaffected -
hashcat already handles .gz natively.
2026-03-19 15:29:59 -04:00
Justin Bollinger 78b51f9b10 revert: update hashcat-utils submodule to reverted ngramX 2026-03-19 15:05:37 -04:00
Justin Bollinger 724e089d63 Revert "fix: ngramX generates n-grams per line, not across entire corpus"
This reverts commit e354f3e57e.
2026-03-19 15:05:29 -04:00
Justin Bollinger e354f3e57e fix: ngramX generates n-grams per line, not across entire corpus
Previously ngramX.bin accumulated all words from the whole file into a
flat array, producing candidates that crossed line boundaries. With a
corpus of "roses are red\nviolets are blue", it generated "red violets"
and "are red violets" - mixing lines that represent separate phrases.

Fixes ngramX.c to process each line independently so n-grams stay
within a single line, matching the expected behavior for song lyrics,
book passages, and similar per-line corpora.
2026-03-19 15:02:42 -04:00