diff --git a/README.md b/README.md index 19ef267..068288a 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ make install ```git clone https://github.com/trustedsec/hate_crack.git``` * Customize binary and wordlist paths in "config.json" * Make sure that at least "rockyou.txt" is within your "wordlists" path +* The hashcat-utils repo is a submodule. Initialize with `git submodule update --init --recursive` ------------------------------------------------------------------- ## Project Structure Core logic is now split into modules under `hate_crack/`: diff --git a/hate_crack.py b/hate_crack.py index 0b6a290..a1cff94 100755 --- a/hate_crack.py +++ b/hate_crack.py @@ -202,7 +202,7 @@ def verify_wordlist_dir(directory, wordlist): return directory + '/' + wordlist else: print('Invalid path for {0}. Please check configuration and try again.'.format(wordlist)) - response = input(f"Wordlist '{wordlist}' not found. Would you like to download rockyou.txt automatically? (Y/n): ").strip().lower() + response = input(f"Wordlist '{wordlist}' not found. Would you like to download rockyou.txt.gz automatically? (Y/n): ").strip().lower() if response in ('', 'y', 'yes'): try: import urllib.request @@ -1351,10 +1351,15 @@ def hashview_api(): print(f"File: {cracked_file}") print(f"Size: {file_size} bytes") print(f"Lines: {line_count}") - + + # Block upload if file is empty + if file_size == 0 or line_count == 0: + print(f"✗ Error: File {cracked_file} is empty. Upload aborted.") + continue + # Use the same hash type from main menu hash_type = hcatHashType - + # Upload print(f"\nUploading to Hashview (hash type: {hash_type})...") try: diff --git a/hate_crack/api.py b/hate_crack/api.py index 724af6b..b2ae9da 100644 --- a/hate_crack/api.py +++ b/hate_crack/api.py @@ -595,14 +595,32 @@ class HashviewAPI: return resp.json() def download_left_hashes(self, customer_id, hashfile_id, output_file=None): + import sys url = f"{self.base_url}/v1/hashfiles/{hashfile_id}" - resp = self.session.get(url) + resp = self.session.get(url, stream=True) resp.raise_for_status() if output_file is None: output_file = f"left_{customer_id}_{hashfile_id}.txt" + total = int(resp.headers.get('content-length', 0)) + downloaded = 0 + chunk_size = 8192 with open(output_file, 'wb') as f: - f.write(resp.content) - return {'output_file': output_file, 'size': len(resp.content)} + for chunk in resp.iter_content(chunk_size=chunk_size): + if chunk: + f.write(chunk) + downloaded += len(chunk) + if total > 0: + done = int(50 * downloaded / total) + bar = '[' + '=' * done + ' ' * (50 - done) + ']' + percent = 100 * downloaded / total + sys.stdout.write(f"\rDownloading: {bar} {percent:5.1f}% ({downloaded}/{total} bytes)") + sys.stdout.flush() + if total > 0: + sys.stdout.write("\n") + # If content-length is not provided, just print size at end + if total == 0: + print(f"Downloaded {downloaded} bytes.") + return {'output_file': output_file, 'size': downloaded} def upload_cracked_hashes(self, file_path, hash_type='1000'): valid_lines = []